Grequest是什么
Gevent 实现协程的基本思想是:遇到 IO 操作时,会自动切换到其他 Greenlet,等到 IO 操作完成时,再切换回来继续执行。有了自动切换协程,就保证总会有 Greenlet 在运行,而不是等待 IO 中。
Grequest允许你使用带有Gevent的请求,轻松的发出异步HTTP请求。
这就有点意思了,我们知道python的GIL锁会导致同一时间只能执行一个线程的问题,所以python下想要充分利用多核CPU,就要使用多进程,才能够有效的提高执行效率。
Grequest库封装了gevent和requests,实现了真正的多并发请求。
使用方法
import grequests
urls = [
'http://www.heroku.com',
'http://python-tablib.org',
'http://httpbin.org',
'http://python-requests.org',
'http://fakedomain/',
'http://kennethreitz.com'
]
rs = (grequests.get(u) for u in urls)
rs_item = grequests.map(rs)
for item in rs_item:
print(item.text)
这种写法会造成程序崩溃
rs = (grequests.get(url) for url in url_chunk)
res_items = grequests.map(rs, timeout=10s)
这样写可以优化性能
rs = (grequests.get(u, timeout=3, proxies=proxies) for u in urls)
for r in grequests.imap(rs, size=200):
print(r.content)
imap与map的区别
map和imap之间的区别在于map等待苏哟有请求完成,然后返回有序数据,而amap立即返回数据并减少订单。
map会立即执行所有请求并返回结果(这可能需要一段时间,这就是为什么你可能会说“等待所有请求完成”).
但是,imap仅按需提供请求.所以你必须遍历结果才能得到它们(但每次迭代只发出一个请求)
grequests库存放在https://github.com/kennethreitz/grequests,代码很少,很容易看懂。
grequests.get(url)其实就是grequests.AsyncRequest(‘GET’, url),grequests中是使用了functools.partial对此进行了转换。
类AsyncRequest的__init__函数做了一些初始化函数,self.url就是初始化该对象时给出的url,self.session是一个requests.Session()对象。
类AsyncRequest有一个send()方法,该方法就是调用self.session的request方法,将请求结果放入self.response中。
grequests下也有一个send方法,其内容是:
def send(r, pool=None, stream=False):
if pool != None:
return pool.spawn(r.send, stream=stream)
return gevent.spawn(r.send, stream=stream)
pool是gevent.pool.Pool的一个实例,用来管理一组greenlet。无论是pool.spawn还是gevent.spawn都是负责执行异步请求。
上面的说通了,那么grequests下的map函数也好理解了。
def map(requests, stream=False, size=None, exception_handler=None):
requests = list(requests)
pool = Pool(size) if size else None
jobs = [send(r, pool, stream=stream) for r in requests]
gevent.joinall(jobs)
ret = []
for request in requests:
if request.response:
ret.append(request.response)
elif exception_handler:
exception_handler(request, request.exception)
return ret
总之,Grequest模块用起来还是比较方便的,爬虫速度会提升很多,比较适合小型的爬虫项目,遇到大型的爬虫项目,需要解析的网页太多,首先是url的传统比较麻烦,二是不方便重复使用,所以建议复杂的大型爬虫还是使用Scrapy框架。
以上,加油吧