python爬虫(四)

在写爬虫程序的时候,我们希望能够并发的抓取,而不是一次只抓取一个url。对于高并发的抓取,目前有三种方案:多进程,多线程,协程(python3.x)。论性能来说,协程最佳(异步执行),tornado就是采用了协程。另外,tornado的文档上,有一个并发的爬虫的例子。但目前我采用的是python2.7,那个例子看不懂啊。至于多进程,会消耗较多的cpu。如果电脑不错,开启多进程速度很快,但是进程有一些限制。

于是我就采用了轻量级的协程gevent,gevent会自动为我们自动切换协程,这样在等待网络IO的时候,就可以尽最大可能的减少时间的损耗。其实爬虫的性能瓶颈主要在于IO,而传统的python多线程是阻塞,如果遇到IO阻塞了,就会非常的消耗时间,因为他不会自动的切换线程运行。

使用gevent非常的简单,几行代码就可以搞定。

import gevent
import requests

def request(url):
    r = requests.get(url)
    return r.staus_code

g1 = gevent.Greenlet(request, url)
g2 = gevent.Greenlet(request, url)
g1.start()
g2.start()
gevent.joinall((g1, g2))

短短几行代码就搞定了并发,熟悉多线程的肯定会觉得上述的代码非常的熟悉。首先,我们创建了两个Greenlet对象,然后调用他们的start()方法,运行他们,最后等待他们运行结束。上述代码虽然可以并发请求,但是requests这个库是同步的,如果它阻塞了,整个程序还是会阻塞住的。而且就目前来说,requests的开发者完全没有时间去改造requests,使它成为异步。具体可以去google。github上有详细的资料。

就以上的代码,结合我们redis中保存的url队列,我们就可以构造我们自己的并发请求了:

#一些模块的导入
def request(url):
    r = requests.get(url)
    #do something

def make_request():
        """ 从redis服务器中的url_queue队列中取出url,进行抓取 """
        #网页并发请求次数
        num = 2 
        url_list = []
        while 1:    
            if redis.lindex('url_queue'):
                #从redis服务器的url_queue中取出一个item,取出的是一个元组对,
                #第一个元素是队列的名字(即'url_queue'),第二个才是目标元素
                result = redis.brpop('url_queue')               
                url_list.append(result['url'])
                if len(url_list) == num or (not redis.lindex('url_queue')):
                    greenlets = [gevent.spawn(request, url) \
                                for url in url_list]

                    gevent.joinall(greenlets)                   
                    url_list = []   
                    time.sleep(4)

if __name__ == "__main__":
    make_request()

上面的代码并不能那个直接使用,实现的也比较粗糙。我们假设网页的并发请求次数为2, 每次从url队列中拿出两个url,如果url队列为空,就阻塞住。然后我们就建立了两个Greenlet,进行并发请求。等到请求结束,我们就休息4秒,然后接着请求,直到没有url请求为止。

在这里建议大家,对于同一个站点的并发请求次数不能过多,请求的抓取间隔也不能太短。这样会对站点占用过多的流量,会引起网站管理员的注意,导致封锁IP。当然,如果你有IP池的话,也最好不能请求的太多,太频繁,如超过了站点的负载,响应的速度就会变慢,最后导致抓取效率大大降低。

gevent中还有非常多的功能以及模块,比如pool, group, hub等,还有monkey patch。当然,如果你使用的是python3,强烈建议你去看看tornado文档上的那个爬虫的列子。自己修改一下就可以拿来用。

    原文作者:Easy_to_python
    原文地址: https://blog.csdn.net/hjhmpl123/article/details/53072647
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞