通过使用python发送并发请求进行刮擦

时间:2014-08-14 05:40:53

标签: python web-scraping grequests

我有python 3.4,我安装了请求和一些其他必要的程序到web scrape。我的问题是,我想要刮掉大约7000页(只是html / text),并且不想一次性完成所有操作,我想要有一些延迟,所以我请勿使用太多请求命中服务器,否则可能会被禁止。我听说过greets,但显然他们没有用python 3.4(实际错误说它找不到vcvarsall.bat但是在文档中我没有看到任何支持3.4)。有没有人知道可以管理网址请求的替代程序?换句话说,我并不是想尽快抓住所有东西,而是缓慢而稳定。

1 个答案:

答案 0 :(得分:1)

我建议您使用自己的多线程程序来执行请求。我发现concurrent.futures是多线程处理这类请求的最简单方法,特别是使用ThreadPoolExecutor。他们甚至在文档中有一个简单的多线程url请求示例。

至于问题的第二部分,它实际上取决于您想要限制请求的数量/方式。对我来说,设置一个足够低的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()