使用Scrapy批量下载网站PDF文件失败求助
解决Scrapy下载PDF文件不符预期的问题
常见问题排查与修复步骤
1. 检查PDF链接提取是否正确
你大概率提取了跳转页/预览页的链接而非PDF文件的直接下载链接。很多网站会把PDF放在详情页里,直接抓取详情页URL下载得到的只会是HTML页面,不是目标PDF。
- 手动打开目标网站,右键检查PDF下载按钮,查看其
href属性,确认是否指向带.pdf后缀的真实地址 - 修改Spider的链接提取逻辑,确保抓取的是直接下载链接:
# 错误示例:抓取了跳转链接 links = response.css('a.pdf-preview::attr(href)').getall() # 正确示例:筛选带.pdf后缀的链接,或直接抓取下载按钮的真实地址 links = [response.urljoin(link) for link in response.css('a.download-btn::attr(href)').getall() if link.endswith('.pdf')]
2. 验证下载请求的响应内容
在Spider中添加日志,打印每个链接的响应头部,确认Content-Type是否为application/pdf:
def parse(self, response): links = [...] # 你的链接提取逻辑 for link in links: yield scrapy.Request( link, callback=self.save_pdf, meta={'target_link': link} ) def save_pdf(self, response): # 打印响应类型,排查是否为PDF content_type = response.headers.get('Content-Type', b'') self.logger.info(f"链接 {response.meta['target_link']} 的内容类型: {content_type}") if b'application/pdf' in content_type: filename = response.url.split('/')[-1] with open(filename, 'wb') as f: f.write(response.body) self.logger.info(f"已保存PDF: {filename}") else: self.logger.warning(f"非PDF内容,跳过链接: {response.meta['target_link']}")
3. 处理动态加载的PDF链接
如果网站用JavaScript渲染PDF下载链接,普通Scrapy请求无法抓取真实地址:
- 改用
scrapy-splash或playwright等工具渲染页面后再提取链接 - 查看浏览器网络请求记录,找到PDF下载的真实API接口,直接请求该接口获取文件
4. 分析运行日志的关键信息
从你的运行日志里重点关注:
- 每个请求的返回状态码(
200不代表是PDF,跳转页也会返回200) - 响应的
Content-Length,PDF文件通常比HTML页面体积大很多 - 是否存在
302重定向,重定向后的地址可能并非PDF文件
修正后的示例Spider代码
import scrapy class PdfDownloadSpider(scrapy.Spider): name = 'toscrape-css2' start_urls = ['你的目标网站URL'] def parse(self, response): # 提取所有带.pdf后缀的直接下载链接 pdf_links = response.css('a[href$=".pdf"]::attr(href)').getall() for link in pdf_links: absolute_url = response.urljoin(link) yield scrapy.Request(absolute_url, callback=self.download_pdf) def download_pdf(self, response): # 确认是PDF格式再保存 if response.headers.get('Content-Type') == b'application/pdf': filename = response.url.split('/')[-1] with open(filename, 'wb') as f: f.write(response.body) self.logger.info(f"成功下载PDF: {filename}") else: self.logger.error(f"非PDF内容,链接: {response.url}")
内容的提问来源于stack exchange,提问作者user2813283
相关产品推荐
相关产品推荐

