如何使用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
}
我想下载在网站上找到的所有 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
}