关于使用grequest模块的问题

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框架。

以上,加油吧

发布了65 篇原创文章 · 获赞 41 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43870646/article/details/93172270