如何使用Scrapy解析PDF?

How to use Scrapy to parse PDFs?

我想下载在网站上找到的所有 PDF,例如https://www.stadt-koeln.de/politik-und-verwaltung/bekanntmachungen/amtsblatt/index.html。我也尝试过使用规则,但我认为这里没有必要。

这是我的方法:

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

class PDFParser(scrapy.Spider):
    name = 'stadt_koeln_amtsblatt'

    # URL of the pdf file
    start_urls = ['https://www.stadt-koeln.de/politik-und-verwaltung/bekanntmachungen/amtsblatt/index.html']

    rules = (
        Rule(LinkExtractor(allow=r'.*\.pdf', deny_extensions=CUSTOM_IGNORED_EXTENSIONS), callback='parse', follow=True),
    )

    def parse(self, response):
        # selector of pdf file.
        for pdf in response.xpath("//a[contains(@href, 'pdf')]"):
            yield scrapy.Request(
                url=response.urljoin(pdf),
                callback=self.save_pdf
            )

    def save_pdf(self, response):
        path = response.url.split('/')[-1]
        self.logger.info('Saving PDF %s', path)
        with open(path, 'wb') as f:
            f.write(response.body)

好像有两个问题。使用xpath提取所有pdf链接时的第一个:

TypeError: Cannot mix str and non-str arguments

第二个问题是关于处理 pdf 文件本身。我只想将它存储在本地的特定文件夹或类似文件夹中。如果有人有此类网站的工作示例,那就太好了。

要下载文件,您需要使用 FilesPipeline。这需要您在 ITEM_PIPELINES 中启用它,然后在您生成的项目中提供一个名为 file_urls 的字段。在下面的示例中,我创建了 FilesPipeline 的扩展,以保留网站上提供的 pdf 文件名。这些文件将保存在当前目录

中名为downloaded_files 的文件夹中

docs

中阅读有关文件管道的更多信息
import scrapy
from scrapy.pipelines.files import FilesPipeline

class PdfPipeline(FilesPipeline):
    # to save with the name of the pdf from the website instead of hash
    def file_path(self, request, response=None, info=None):
        file_name = request.url.split('/')[-1]
        return file_name

class StadtKoelnAmtsblattSpider(scrapy.Spider):
    name = 'stadt_koeln_amtsblatt'
    start_urls = ['https://www.stadt-koeln.de/politik-und-verwaltung/bekanntmachungen/amtsblatt/index.html']

    custom_settings = {
        "ITEM_PIPELINES": {
            PdfPipeline: 100
        },
        "FILES_STORE": "downloaded_files"
    }

    def parse(self, response):
        links = response.xpath("//a[@class='download pdf pdf']/@href").getall()
        links = [response.urljoin(link) for link in links] # to make them absolute urls

        yield {
            "file_urls": links
        }