Scrapy 使用 Deltafetch 进行增量爬取

发布于 2024-11-26 15:53:14 字数 5204 浏览 6 评论 0

我们开发的一些爬虫设计成一次性爬取并抓取我们所需的数据。另一方面,许多爬虫需要周期性地爬取,以便让我们的数据集保持最新。

在这些周期爬虫中,我们只对最后一次爬取的最新页面感兴趣。例如,我们有一个从一堆网络媒体网点爬取文章的爬虫。该爬虫一天执行一次,并且它们首先从预定义的首页检索文章 URL。然后,从每篇文章上提取标题、作者、日期和内容。这种方法通常会导致许多重复结果,并且使得每次我们运行爬虫时,爬取的数量越来越多。

幸运的是,我们并不是第一个有这个问题的人。社区已经有了解决方法: scrapy-deltafetch 插件 。你可以用这个插件进行增量爬取。DeltaFetch 的主要目的是避免请求那些之前已经爬过的页面,即使它在之前的执行中已经出现了。它只会对那些之前没有提取任何项的页面、爬虫的 start_urls 属性中的 URL、或者在爬虫的 start_requests 方法中生成的 Request 进行请求。

DeltaFetch 的工作原理是,对爬虫回调中生成的每一个 Item 和 Request 对象进行拦截。对于 Item,它计算相关的 Request 标识符(又名, 指纹(fingerprint) ),并将其存储到一个本地数据库中。对于 Request,Deltafetch 计算 Request fingerprint,并在在其已存在数据库的时候丢弃该 Request。

现在,看看如何为你的 Scrapy 爬虫设置 Deltafetch。

开始使用 DeltaFetch

首先,用 pip 安装 DeltaFetch:


    $ pip install scrapy-deltafetch

然后,你必须在你的项目的 settings.py 文件中启用它:


    SPIDER_MIDDLEWARES = {
        'scrapy_deltafetch.DeltaFetch': 100,
    }
    DELTAFETCH_ENABLED = True

使用 DeltaFetch

这个爬虫 有一个爬取 books.toscrape.com 的蜘蛛。它通过所有列出的页面进行导航,访问每本书的详细页面,获取一些数据,例如书标题、描述和目录。该爬虫每天执行一次,以捕获对应目录中包含的新书。无需访问那些已经爬过的书页面,因为由爬虫收集的数据通常不会改变。

想看看 Deltafetch 的使用, clone 这个 repo ,其中,已经在 settings.py 启用了 DeltaFetch,然后运行:


    $ scrapy crawl toscrape

等它结束,然后看看 Scrapy 在最后记录的统计数据:


    2016-07-19 10:17:53 [scrapy] INFO: Dumping Scrapy stats:
    {
        'deltafetch/stored': 1000,
        ...
        'downloader/request_count': 1051,
        ...
        'item_scraped_count': 1000,
    }

除此之外,你会看到爬虫进行了 1051 次请求来爬取 1000 个项,而 DeltaFetch 存储了 1000 个请求的 fingerprint。这意味着,只有 51 个页面请求没有生成 item,因此下次还会继续访问他们。

现在,再次运行该爬虫,你会看到许多像这样的日志信息:


    2016-07-19 10:47:10 [toscrape] INFO: Ignoring already visited: 
    <GET http://books.toscrape.com/....../index.html>

而在统计数据中,你会看到,跳过了 1000 个请求,因为在之前的爬取中,已经爬到了 item。现在,该爬虫并未提取任何 item,并且它只进行了 51 次请求,它们所有都是之前没有爬取到 item 的页面:


    2016-07-19 10:47:10 [scrapy] INFO: Dumping Scrapy stats:
    {
        'deltafetch/skipped': 1000,
        ...
        'downloader/request_count': 51,
    }

修改数据库键

默认情况下,DeltaFetch 使用一个 Request fingerprint 来区分 Request。该 fingerprint 是一个基于规范 URL、HTTP 方法和请求体计算的哈希值。

一些网站对于相同的数据会有多个 URL。例如,一个电子商务网站可能有指向同一个产品的 URL,如下所示:

在这些情况下,Request fingerprint 并不适用,因为规范的 URL 将会不同,即使 item 是相同的。在这个例子中,我们可以使用产品的 ID 作为 DeltaFetch 键。

DeltaFetch 允许我们在初始化 Request 时,通过传递一个名为 deltafetch_key 的元参数来自定义键:


    from w3lib.url import url_query_parameter

    ...

    def parse(self, response):
        ...
        for product_url in response.css('a.product_listing'):
            yield Request(
                product_url,
                meta={'deltafetch_key': url_query_parameter(product_url, 'id')},
                callback=self.parse_product_page
            )
        ...

通过这种方式,DeltaFetch 将会忽略对重复页面进行请求,即使它们有不同的 URL。

重置 DeltaFetch

如果你想要重新爬取页面,可以通过传递一个 deltafetch_reset 参数给你的爬虫,来重置 DeltaFetch 缓存:


    $ scrapy crawl example -a deltafetch_reset=1

在 Scrapy Cloud 上使用 DeltaFetch

你也可以对运行在 Scrapy Cloud 之上的爬虫使用 DeltaFetch。仅需在你项目的 Addons 页面启用 DeltaFetch 和 DotScrapy Persistence 插件。后者是用来允许你的爬虫访问.scrapy 文件夹,该文件夹是 DeltaFetch 存储其数据库的地方。

Deltafetch 在我们已经看到的那些情况下是非常方便的。 请记住,Deltafetch 只是避免了发送请求到之前已经生成了 item 的页面,并且仅当这些请求尚未由爬虫的 start_urls 或者 start_requests 生成。 那些来自于没有直接爬取到 item 的页面,在每一次你运行你的爬虫的时候,将仍会抓取。

你可以看看 github 上该项目页以获取更多信息: http://github.com/scrapy-plugins/scrapy-deltafetch

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

方觉久

暂无简介

文章
评论
24 人气
更多

推荐作者

kaipeng

文章 0 评论 0

吐个泡泡

文章 0 评论 0

沧桑㈠

文章 0 评论 0

御宅男

文章 0 评论 0

泪眸﹌

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文