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

PDFBox中getCharactersByArticle()仅返回最后一页文本信息的求助

解决PDFBox仅获取最后一页文本位置信息的问题

你遇到的情况很常见——PDFTextStripper内部的charactersByArticle变量在处理每一页时会被重置,所以当你处理完所有页面后,它只保留了最后一页的文本数据。要获取所有页面的文本位置信息,我们需要修改自定义的文本剥离器,让它主动累积每一页的数据。

修改后的解决方案代码

1. 调整CustomPDFTextStripper类

我们需要添加一个全局集合来存储所有页面的文本位置数据,并重写endPage方法,在每一页处理完成后把当前页的数据保存下来:

import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import java.io.IOException;
import java.util.List;
import java.util.Vector;

class CustomPDFTextStripper extends PDFTextStripper {
    // 存储所有页面的文本位置数据:每个元素对应一页的TextPosition列表
    private Vector<List<TextPosition>> allPagesTextData = new Vector<>();

    public CustomPDFTextStripper() throws IOException {
        super();
    }

    @Override
    protected void endPage(org.apache.pdfbox.pdmodel.PDPage page) throws IOException {
        // 把当前页的charactersByArticle数据复制一份保存到全局集合
        // 注意:直接add(charactersByArticle)会引用同一对象,后续页面会覆盖,所以要创建新列表
        allPagesTextData.add(new Vector<>(charactersByArticle.get(0)));
        super.endPage(page);
    }

    public Vector<List<TextPosition>> getAllPagesTextData() {
        return allPagesTextData;
    }
}

2. 修改主方法调用逻辑

现在我们可以从自定义剥离器中获取所有页面的数据,并遍历输出:

import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.TextPosition;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.Vector;

public class PDFTextExtractor {
    public static void main(String[] args) throws IOException {
        String fileName = "apache.pdf";
        PDDocument document = null;
        try {
            PDFParser parser = new PDFParser(new FileInputStream(fileName));
            parser.parse();
            document = parser.getPDDocument();

            StringWriter outString = new StringWriter();
            CustomPDFTextStripper stripper = new CustomPDFTextStripper();
            stripper.writeText(document, outString);

            // 获取所有页面的文本数据
            Vector<List<TextPosition>> allPagesData = stripper.getAllPagesTextData();

            // 遍历每一页
            for (int pageNum = 0; pageNum < allPagesData.size(); pageNum++) {
                List<TextPosition> textPositions = allPagesData.get(pageNum);
                // 遍历当前页的每个文本位置
                for (TextPosition text : textPositions) {
                    System.out.printf("页面 %d | 文本 '%s' | [x: %.2f, y: %.2f, 高度: %.2f, 空格宽度: %.2f, 文本宽度: %.2f, Y缩放: %.2f] | 字体: %s%n",
                            pageNum + 1,
                            text.getCharacter(),
                            text.getXDirAdj(),
                            text.getY(),
                            text.getHeightDir(),
                            text.getWidthOfSpace(),
                            text.getWidthDirAdj(),
                            text.getYScale(),
                            text.getFont().getBaseFont());
                }
            }
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }
}

关键说明

  • 为什么要重写endPage?因为PDFTextStripper在处理每一页前会清空charactersByArticle,所以我们需要在每页处理结束后,及时把当前页的数据复制出来保存。
  • 为什么要创建新列表?直接添加charactersByArticle.get(0)会引用同一个对象,后续页面处理时会覆盖之前的数据,所以必须创建新的列表来存储当前页的副本。

这样修改后,你就能获取到PDF所有页面的文本位置、宽高、字体等信息了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:30:05