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

Python技术问询:无参考文献标题的双栏PDF参考文献移除方案

无明确参考文献标题的PDF文本提取优化方案

问题描述

我编写了如下Python代码,用于提取在线双栏PDF中的手稿文本。由于目标PDF没有明确的“References”或“Bibliography”章节标题,多次尝试检测并移除提取文本中的参考文献均未成功。请问针对这种无参考文献标题的情况,有什么移除参考文献的可行方案?

现有代码

import fitz  # PyMuPDF
import requests
import io

def extract_text_from_pdf(pdf_file):
    # 从流中打开PDF文件
    doc = fitz.open(stream=pdf_file, filetype="pdf")
    full_text = []

    for page_num in range(len(doc)):
        page = doc[page_num]
        blocks = page.get_text("dict")["blocks"]

        # 分析页面宽度以检测分栏结构
        page_width = page.rect.width
        mid_x = page_width / 2  # 页面中线,用于拆分左右栏

        left_column = []
        right_column = []

        for block in blocks:
            if "bbox" in block:
                x0, y0, x1, y1 = block["bbox"]  # 提取文本块的边界框

                # 将文本块归类到左栏或右栏
                if x1 <= mid_x:
                    left_column.append(block)
                elif x0 >= mid_x:
                    right_column.append(block)

        # 按垂直位置(顶部)对每栏的文本块排序
        left_column.sort(key=lambda b: b["bbox"][1])
        right_column.sort(key=lambda b: b["bbox"][1])

        # 提取每栏的文本并拼接
        page_text = []
        for column in [left_column, right_column]:
            for block in column:
                if "lines" in block:
                    block_text = ""
                    for line in block["lines"]:
                        for span in line["spans"]:
                            block_text += span["text"] + " "
                    page_text.append(block_text.strip())

        # 合并左右栏文本作为当前页面内容
        full_text.append("\n".join(page_text))

    return "\n\n".join(full_text)

# 从URL获取PDF
url = 'https://hal.science/hal-04206682/document'

try:
    response = requests.get(url)
    response.raise_for_status()  # 请求失败时抛出异常
    pdf_file = io.BytesIO(response.content)  # 将PDF内容加载到内存

    # 提取PDF文本
    text = extract_text_from_pdf(pdf_file)
    print(text)
except requests.exceptions.RequestException as e:
    print(f"下载PDF时出错: {e}")

补充说明

上述代码可正确识别双栏PDF结构并提取文本,但无法区分图注(Figure)文本与手稿主文本,导致图注文本会混入主文本中对应位置,也不清楚如何移除该部分内容。


解决方案

一、移除无标题参考文献的可行方案

1. 基于格式特征匹配识别

参考文献条目通常有明显格式规律,可通过正则匹配连续符合规律的段落来定位:

  • 常见特征:以数字编号(如[1]、1.)开头、包含作者名+年份+文献来源组合、外文作者姓氏大写开头
  • 实现示例:
    import re
    
    def remove_references(text):
        # 匹配典型参考文献条目格式
        ref_pattern = re.compile(r'^\s*(\[\d+\]|\d+\.)\s+[A-Z][a-z]+(?:\s+[A-Z]\.)?,?.*', re.MULTILINE)
        lines = text.split('\n')
        ref_start = -1
        consecutive_matches = 0
        # 阈值:连续匹配5条则判定为参考文献起始
        threshold = 5
    
        for idx, line in enumerate(lines):
            if ref_pattern.match(line):
                consecutive_matches += 1
                if consecutive_matches >= threshold and ref_start == -1:
                    ref_start = idx
            else:
                consecutive_matches = 0
    
        if ref_start != -1:
            return '\n'.join(lines[:ref_start])
        return text
    

2. 基于页面位置过滤

参考文献几乎都集中在文档末尾,可直接跳过最后若干页或页面底部区域:

  • 实现思路:
    1. 获取PDF总页数,处理时跳过最后1-3页(可根据文档类型调整)
    2. 或分析文本块的垂直位置,页面底部70%以下区域的文本块优先判定为参考文献(需结合格式验证)

3. 基于字体与排版特征识别

参考文献字体通常比正文小,行间距更紧凑:

  • 实现思路:利用PyMuPDF的span["size"]获取字体大小,统计页面内字体大小分布,当连续出现多块小字体文本且符合参考文献格式时,排除该区域

二、移除图注的方案

图注通常包含Figure X/Fig. X/Table X关键词,且位置紧邻图片:

  • 实现思路(集成到原提取函数中):
    def extract_text_from_pdf(pdf_file):
        doc = fitz.open(stream=pdf_file, filetype="pdf")
        full_text = []
    
        for page_num in range(len(doc)):
            page = doc[page_num]
            blocks = page.get_text("dict")["blocks"]
            page_width = page.rect.width
            mid_x = page_width / 2
            left_column = []
            right_column = []
    
            # 先标记图片附近的图注块
            caption_blocks = set()
            for block in blocks:
                if block["type"] == 1:  # 图片块
                    img_y0, img_y1 = block["bbox"][1], block["bbox"][3]
                    # 查找图片上下20px范围内的文本块
                    for text_block_idx, text_block in enumerate(blocks):
                        if text_block["type"] == 0:
                            tb_y0, tb_y1 = text_block["bbox"][1], text_block["bbox"][3]
                            if abs(tb_y0 - img_y1) < 20 or abs(tb_y1 - img_y0) < 20:
                                # 检查是否包含图注关键词
                                block_text = ""
                                if "lines" in text_block:
                                    for line in text_block["lines"]:
                                        for span in line["spans"]:
                                            block_text += span["text"]
                                if any(key in block_text for key in ["Figure", "Fig.", "Table"]):
                                    caption_blocks.add(text_block_idx)
    
            # 处理文本块时跳过图注块
            for block_idx, block in enumerate(blocks):
                if block_idx in caption_blocks:
                    continue
                if "bbox" in block:
                    x0, y0, x1, y1 = block["bbox"]
                    if x1 <= mid_x:
                        left_column.append(block)
                    elif x0 >= mid_x:
                        right_column.append(block)
    
            # 后续排序、提取逻辑保持不变
            left_column.sort(key=lambda b: b["bbox"][1])
            right_column.sort(key=lambda b: b["bbox"][1])
            page_text = []
            for column in [left_column, right_column]:
                for block in column:
                    if "lines" in block:
                        block_text = ""
                        for line in block["lines"]:
                            for span in line["spans"]:
                                block_text += span["text"] + " "
                        page_text.append(block_text.strip())
            full_text.append("\n".join(page_text))
    
        return "\n\n".join(full_text)
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 02:57:33