爬行有延迟

快速抓取被认为是一种不好的做法。 不断地访问网站的页面会消耗 CPU 和带宽,而强大的网站会识别您的行为并阻止您的 IP。 如果你运气不好,你可能会收到一封令人讨厌的违反服务条款的信!

爬网程序中延迟请求的技术取决于爬网程序的实现方式。 如果您使用Scrapy,那么您可以设置一个参数来通知爬虫在请求之间等待多长时间。 在一个简单的爬虫中,只需顺序处理列表中的 URL,您可以插入一个 thread.sleep 语句。

如果您实现了分布式爬虫集群来分散页面请求的负载,例如使用具有竞争消费者的消息队列,那么事情可能会变得更加复杂。 这可能有许多不同的解决方案,这超出了本文提供的范围。

准备工作

我们将研究使用带有延迟的 Scrapy。 示例位于 05/04_scrape_with_delay.py 中。

如何做

默认情况下,Scrapy 在页面请求之间施加 0 秒的延迟。 也就是说,默认情况下它不会在请求之间等待。

  1. 这可以使用 DOWNLOAD_DELAY 设置进行控制。 为了进行演示,让我们从命令行运行该脚本:

    05 $ scrapy runspider 04_scrape_with_delay.py -s LOG_LEVEL=WARNING
    Parsing: <200 https://blog.scrapinghub.com>
    Parsing: <200 https://blog.scrapinghub.com/page/2/>
    Parsing: <200 https://blog.scrapinghub.com/page/3/>
    Parsing: <200 https://blog.scrapinghub.com/page/4/>
    Parsing: &lt;200 https://blog.scrapinghub.com/page/5/>
    Parsing: <200 https://blog.scrapinghub.com/page/6/>
    Parsing: <200 https://blog.scrapinghub.com/page/7/>
    Parsing: <200 https://blog.scrapinghub.com/page/8/>
    Parsing: <200 https://blog.scrapinghub.com/page/9/>
    Parsing: <200 https://blog.scrapinghub.com/page/10/>
    Parsing: <200 https://blog.scrapinghub.com/page/11/>
    Total run time: 0:00:07.006148
    Michaels-iMac-2:05 michaelheydt$

    这将爬网 blog.scrapinghub.com 上的所有页面,并报告执行爬网的总时间。 LOG_LEVEL=WARNING 删除大部分日志输出,仅给出 print 语句的输出。 这使用了页面之间的默认等待时间 0,导致抓取时间大约为 7 秒。

  2. 可以使用 DOWNLOAD_DELAY 设置来设置页面之间的等待。 以下是页面请求之间五秒的延迟:

    05 $ scrapy runspider 04_scrape_with_delay.py -s DOWNLOAD_DELAY=5 -
    s LOG_LEVEL=WARNING
    Parsing: <200 https://blog.scrapinghub.com>
    Parsing: <200 https://blog.scrapinghub.com/page/2/>
    Parsing: <200 https://blog.scrapinghub.com/page/3/>
    Parsing: <200 https://blog.scrapinghub.com/page/4/>
    Parsing: <200 https://blog.scrapinghub.com/page/5/>
    Parsing: <200 https://blog.scrapinghub.com/page/6/>
    Parsing: <200 https://blog.scrapinghub.com/page/7/>
    Parsing: <200 https://blog.scrapinghub.com/page/8/>
    Parsing: <200 https://blog.scrapinghub.com/page/9/>
    Parsing: <200 https://blog.scrapinghub.com/page/10/>
    Parsing: <200 https://blog.scrapinghub.com/page/11/>
    Total run time: 0:01:01.099267

默认情况下,这实际上不会等待 5 秒。 它将等待 DOWNLOAD_DELAY 秒,但等待时间为 DOWNLOAD_DELAY 的 0.5 到 1.5 倍之间的随机因子。 为什么要这样做? 这会让你的爬虫看起来“不那么机器人化”。 您可以使用 RANDOMIZED_DOWNLOAD_DELAY=False 设置来关闭此功能。

工作原理

该爬虫是作为 Scrapy spider 实现的。 类定义首先声明 spider 名称和起始 URL:

class Spider(scrapy.Spider):
    name = 'spider'
    start_urls = ['https://blog.scrapinghub.com']

parse 方法查找 CSS 'div.prev-post > a',并跟踪这些链接。

scraper 还定义了一个 close 方法,当抓取完成时 Scrapy 会调用该方法:

def close(spider, reason):
    start_time = spider.crawler.stats.get_value('start_time')
    finish_time = spider.crawler.stats.get_value('finish_time')
    print("Total run time: ", finish_time-start_time)

这将访问 spider 爬虫统计对象,检索 spider 的开始和结束时间,并向用户报告差异。

还有更多

该脚本还定义了直接使用 Python 执行脚本时的代码:

if __name__ == "__main__":
    process = CrawlerProcess({
        'DOWNLOAD_DELAY': 5,
        'RANDOMIZED_DOWNLOAD_DELAY': False,
        'LOG_LEVEL': 'DEBUG'
    })
    process.crawl(Spider)
    process.start()

首先创建一个 CrawlerProcess 对象。 可以向此对象传递一个表示用于配置爬网的设置和值的字典。 默认为五秒延迟,无随机化,输出级别为 DEBUG。