如何阻止 Scrapy CrawlSpider 跟踪比要求更多的 URL?

Posted

技术标签:

【中文标题】如何阻止 Scrapy CrawlSpider 跟踪比要求更多的 URL?【英文标题】:How to stop Scrapy CrawlSpider from following more URLs than required? 【发布时间】:2020-02-05 03:17:36 【问题描述】:

我想用 scrapy 编写一个从网站上提取 pdf 的爬虫。 到目前为止,爬虫在下载 pdf 方面工作良好。 然而,它遵循许多链接的方式,尽管我已经尝试了几种方法来阻止它这样做。

按照我的理解,我可以限制 scrapy 的 Crawlspider 使用带有 LinkExtractor 的规则跟踪链接。

我已经构建了一个自定义的 LinkExtractor(并且还尝试在没有自定义 Linkextractor 的情况下直接构建规则,但产生了相同的结果。)

基本上我只想从页面中提取 PDF,不应该抓取任何不以 .pdf 结尾的链接。

到目前为止,以下代码有效,仅使用 parse_docs() 方法保存 PDF,但是,我希望永远不会将非 pdf 链接发送到 parse_docs() 函数。

我也尝试在 Linkextractor 中使用 deny 属性(想法 1)或将 linkextractor 限制为仅一个特定的 PDF(想法 2),但是很多 index.php?id= 链接不断被抓取。

(抱歉代码太长了,不过我觉得这样你就可以直接运行文件了,不用重新编译一半的爬虫,如果需要缩短,请随意)

# -*- coding: utf-8 -*-
import scrapy

import re
from itertools import chain
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
EXTENSIONS = [".pdf"]

class CustomLinkExtractor(LinkExtractor):
    def __init__(self, *args, **kwargs):
        super(CustomLinkExtractor, self).__init__(*args, **kwargs)
        # Keep the default values in "deny_extensions" *except* for those types we want
        self.deny_extensions = [ext for ext in self.deny_extensions if ext not in EXTENSIONS]
        self.allow = (r'.*\.pdf',) 
        #self.deny = ('index\.php',) #idea 1

class BremenSpider(CrawlSpider):
    name = 'bremen'
    allowed_domains = ['www.bremische-buergerschaft.de',"bremische-buergerschaft.de"]
    start_urls = ['https://www.bremische-buergerschaft.de/index.php?id=570']

    def __init__(self, *args, **kwargs):
        self.rules = (
            Rule(CustomLinkExtractor(), callback="parse_docs"),
            #idea 2
            #Rule(LinkExtractor(allow = ('/dokumente/wp19/land/protokoll/P19L0076.pdf')), callback="parse_docs"),
            )
        super(BremenSpider, self).__init__(*args, **kwargs)


    def parse_docs(self, response):
        if hasattr(response, "text"):
            # The response is text - we assume html. Normally we'd do something
            # with this, but this demo is just about pdf content, so...
            self.logger.info("not parsing url: %s", response.url)
            pass
        else:
            extension = list(filter(lambda x: response.url.lower().endswith(x), EXTENSIONS))[0]
            if extension:
                # This is a pdf 
                path = response.url.split('/')[-1]                
                self.logger.info('Saving PDF %s', path)
                with open(path, 'wb') as f:
                    f.write(response.body) 

我希望只抓取带有 index.php?id=570 和 .pdf 链接的 start_url,但是当我在 CLI 上运行抓取工具时,它还会抓取大量其他 index.php?... 链接。

我误解了 CLI 输出还是我的 LinkExtractor 不正确?

【问题讨论】:

请参阅***.com/help/mcve 【参考方案1】:

pdf(不带点)包含在scrapy.linkextractors.IGNORED_EXTENSIONS 中,因此默认情况下会被忽略。我认为以下应该可以解决您的问题:

from scrapy.linkextractors import IGNORED_EXTENSIONS
CUSTOM_IGNORED_EXTENSIONS = IGNORED_EXTENSIONS.copy()
CUSTOM_IGNORED_EXTENSIONS.remove('pdf')

然后,在蜘蛛的rules 属性中,您可以使用以下链接提取器定义规则: LinkExtractor(allow=r'.*\.pdf', deny_extensions=CUSTOM_IGNORED_EXTENSIONS)

【讨论】:

这涉及如何下载 pdf 的问题,但这实际上工作正常。我得到了所有的 pdf,但在这个过程中,scrapy 遵循了许多 URL,我找不到阻止它这样做的方法。【参考方案2】:

您是否尝试将规则的follow 参数设置为 False?

Rule(LinkExtractor, callback=..., follow=False)

【讨论】:

以上是关于如何阻止 Scrapy CrawlSpider 跟踪比要求更多的 URL?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用scrapy中的CrawlSpider单击带有javascript onclick的链接?

如何在Scrapy CrawlSpider中找到当前的start_url?

Scrapy框架--CrawlSpider

Scrapy - 了解 CrawlSpider 和 LinkExtractor

Python网络爬虫之Scrapy框架(CrawlSpider)

爬虫学习 16.Python网络爬虫之Scrapy框架(CrawlSpider)