手里上有一批鏈接,需要檢查他們是否已經被刪除。本來是想用多線程的,但是考慮了下一個是實現起來稍繁瑣。而且性能不理想,單機基本超過10線程基本上就沒有太多增益了。
所以考慮了下,還是決定用異步IO。
在使用grequest之前用的是aiohttp來處理的,但是這個庫蛋疼的時,每個延時請求前都要添加await,導致代碼里一堆await和async。
基於此,就找到了grequest。
寫代碼的方式還是以同步的思路來寫的,只不過grequest會在底層幫你把代碼轉換成異步IO。
代碼如下
import grequests
urls = [
'http://www.baidu.com',
'http://www.qq.com',
'http://www.163.com',
'http://www.zhihu.com',
'http://www.toutiao.com',
'http://www.douban.com'
]
>>> rs = (grequests.get(u) for u in urls)
>>> grequests.map(rs)
[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, None, <Response [200]>]
>>> def exception_handler(request, exception):
... print("Request failed")
>>> reqs = [
... grequests.get('http://httpbin.org/delay/1', timeout=0.001),
... grequests.get('http://fakedomain/'),
... grequests.get('http://httpbin.org/status/500')]
>>> grequests.map(reqs, exception_handler=exception_handler)
Request failed
Request failed
[None, None, <Response [500]>]
但是,這里有個問題。就是grequest的map模塊在遇到請求超時、異常時返回的Response是None的。
這個就有點坑了,因為我有幾千個URL,而且還涉及不同的網站。其中有些網站可能已經關站,或者由於網速問題,超時了。
所以,這里把map模塊做了一下調整。
直接把grequests模塊的源碼復制一份,然后增加以下模塊。
ggrequests.py
...
def extract_item(request):
"""
提取request的內容
"""
item = dict()
item['url'] = request.url
item['text'] = request.response.text or ''
item['status_code'] = request.response.status_code or 0
return item
def map(requests, stream=False, size=None, exception_handler=None, gtimeout=None):
"""將Request列表轉換為Response。
:param 請求:Request對象的集合。
:param stream:如果為True,則內容不會立即下載。
:param size:指定單次請求的數量。 如果為空,則沒有限制。
:param exception_handler:回調函數,當發生異常時調用。 參數:請求,例外
:param gtimeout:幾秒鍾內Gevent連接超時。 (注意:與請求超時無關)
"""
requests = list(requests)
pool = Pool(size) if size else None
jobs = [send(r, pool, stream=stream) for r in requests]
gevent.joinall(jobs, timeout=gtimeout)
ret = []
# 這里就是請求成功后處理Response的地方
for request in requests:
if request.response is not None:
ret.append(extract_item(request))
elif exception_handler and hasattr(request, 'exception'):
ret.append(exception_handler(request, request.exception))
else:
ret.append(extract_item(request))
return ret
...
用起來就很簡單了
```python
import ggrequests as grequests
urls = [
'http://www.baidu.com',
'http://www.qq.com',
'http://www.163.com',
'http://www.zhihu.com',
'http://www.toutiao.com',
'http://www.douban.com'
]
rs = (grequests.get(u) for u in urls)
response_list = grequests.map(rs, gtimeout=10)
for response in response_list:
print(response)