You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy爬虫抓取PDF后部分元数据未写入CSV问题求助

问题原因和解决方法

核心错误原因

  • PDF链接拼接逻辑错误
    你当前在parse_item里用固定的起始页URL(start变量)拼接相对路径的PDF链接,如果你爬到站点其他子页面的相对路径PDF,拼接出来的链接是错误的,会触发404,自然不会写入CSV。
    修改方法:把parse_item函数里的base_url = start替换成base_url = response.url,用当前页面的URL来拼接相对路径,才能得到正确的PDF链接。

  • 异步并发导致CSV写入冲突
    Scrapy默认是异步并发请求的(默认并发数16),多个PDF下载请求会同时调用add_to_csv方法打开同一个CSV文件写入,会出现写入冲突,导致大量数据丢失。
    临时验证方法:运行爬虫时加参数关闭并发,scrapy crawl pdfspider -s CONCURRENT_REQUESTS=1,如果写入CSV的条数正常,就可以确认是该问题。
    长期解决方法:把CSV写入逻辑迁移到Scrapy自带的Item Pipeline中,Pipeline是单线程串行处理结果的,天然不会出现写入冲突,比你自己实现的写入逻辑更稳定。

  • PDF处理逻辑无异常捕获,任意报错都会中断写入流程
    你当前的get_data和isTagged函数没有任何全局异常捕获,只要遇到加密PDF、损坏PDF、缺少元数据字段、编码不兼容的情况,就会直接抛出异常终止当前请求的执行,不会走到写入CSV的步骤,这也是丢数据的常见原因。
    修改方法:给两个处理函数加全局异常捕获,遇到错误返回默认值,不要中断流程,代码示例如下:

# 修改后的get_data函数
from pdfminer3.pdfparser import PDFParser
from pdfminer3.pdfdocument import PDFDocument
from pdfminer.high_level import extract_pages

def get_data(file):
    try:
        fp = open(file, 'rb')
        parser = PDFParser(fp)
        doc = PDFDocument(parser)
        info = doc.info[0] if doc.info else {}
        # 用get方法取字段,避免KeyError,解码时忽略错误字符
        author = info.get("Author", b"").decode(errors="ignore").strip()
        title = info.get("Title", b"").decode(errors="ignore").strip()
        numPages = len(list(extract_pages(file)))
        return title, author, numPages
    except Exception as e:
        print(f"处理PDF {file} 元数据失败:{str(e)}")
        return ("未知标题", "未知作者", 0)
# 修改后的isTagged函数
from pdfminer3.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer3.pdfdevice import TagExtractor
from pdfminer3.pdfpage import PDFPage
from io import BytesIO

def isTagged(path, password=''):
    try:
        rsrcmgr = PDFResourceManager()
        retstr = BytesIO()
        device = None
        try:
            device = TagExtractor(rsrcmgr, retstr, codec='utf-8')
        except:
            try:
                device = TagExtractor(rsrcmgr, retstr, codec='ascii')
            except:
                print(f"PDF {path} 不支持utf-8和ascii编码")
                return "未知"
        fp = open(path, 'rb')
        interpreter = PDFPageInterpreter(rsrcmgr, device)
        maxpages = 100
        caching = True
        pagenos=set()
        for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password, caching=caching, check_extractable=True):
            interpreter.process_page(page)
        contents = retstr.getvalue().decode(errors="ignore")
        fp.close()
        device.close()
        retstr.close()
        tags = ["<b'Part'", "</b'Sect'", "</b'Art'", "<b'Content'", "<b'Artifact'"]
        for tag in tags:
            if tag in contents:
                return 'tagged'
        return 'not tagged'
    except Exception as e:
        print(f"检测PDF {path} 标签失败:{str(e)}")
        return "未知"
  • 文件名重名覆盖
    你现在直接用URL最后一段作为PDF保存的文件名,如果两个不同的PDF文件名相同,后下载的会覆盖先下载的,先下载的PDF处理时要么读取错误,要么读取到的是后面覆盖后的文件,也会导致数据丢失。
    修改方法:给文件名增加唯一标识,比如对URL做MD5哈希作为前缀:
# 在save_pdf函数中修改文件名生成逻辑
import hashlib
original_file = response.url.split('/')[-1]
url_hash = hashlib.md5(response.url.encode()).hexdigest()
file = f"{url_hash}_{original_file}"
full_path = os.path.join(save_dir, file)
  • allowed_domains配置错误导致PDF链接被过滤
    你当前的输入提示让用户输入根域名前缀(比如google),但Scrapy的allowed_domains需要填写完整的根域名(比如google.com),否则子域名下的PDF链接会被自动过滤,无法下载。
    修改方法:调整输入提示,让用户输入完整的根域名,比如Enter the domain name of the website to be crawled (domain of https://google.com is "google.com"):。

内容的提问来源于stack exchange,提问作者Mat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:57:02