使用Python发送并发请求进行抓取
我现在用的是Python 3.4,并且安装了requests库和一些其他必要的程序来进行网页抓取。我的问题是,我想抓取大约7000个页面(只是html或文本),但我不想一次性抓取完。我希望能设置一个延迟,这样就不会对服务器发出太多请求,避免被封禁。我听说过grequests,但好像它不支持Python 3.4(实际错误提示是找不到vcvarsall.bat,而在文档中我也没看到对3.4的支持)。有没有人知道其他可以管理网址请求的替代程序?换句话说,我并不是想要尽快抓取所有内容,而是希望能慢慢来,稳扎稳打。
1 个回答
2
我建议你自己写一个多线程程序来处理请求。我发现使用 concurrent.futures
是实现这类请求的最简单方法,特别是用 ThreadPoolExecutor
。他们的文档里甚至有一个简单的多线程网址请求示例。
至于问题的第二部分,实际上这取决于你想限制请求的多少和方式。对我来说,设置一个足够低的 max_workers
参数,并在我的函数中加入 time.sleep
等待时间,就足以避免任何问题,即使是在抓取成千上万的页面时也是如此,但这显然还要看你要抓取的网站。实现某种批处理或等待机制应该不难。
下面的代码虽然没有经过测试,但希望能给你一个起点。从这里开始,你可能需要根据自己的需求修改 get_url_data
(或者你使用的其他函数),比如进行解析或保存数据。
import concurrent.futures as futures
import requests
from requests.exceptions import HTTPError
urllist = ...
def get_url_data(url, session):
try:
r = session.get(url, timeout=10)
r.raise_for_status()
except HTTPError:
return None
return r.text
s = requests.Session()
try:
with futures.ThreadPoolExecutor(max_workers=5) as ex:
future_to_url = {ex.submit(get_url_data, url, s): url
for url in urlist}
results = {future_to_url[future]: future.result()
for future in futures.as_completed(future_to_url)}
finally:
s.close()