我想使用 PDFMiner 从 PDF 文件中提取所有文本框和文本框坐标。
许多其他 Stack Overflow 帖子解决了如何以有序方式提取所有文本的问题,但我如何才能完成获取文本和文本位置的中间步骤?
给定一个 PDF 文件,输出应该类似于:
489, 41, "Signature"
500, 52, "b"
630, 202, "a_g_i_r"
原文由 pnj 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是一个复制粘贴就绪的示例,它列出了 PDF 中每个文本块的左上角,我认为它应该适用于任何不包含其中包含文本的“Form XObjects”的 PDF:
from pdfminer.layout import LAParams, LTTextBox
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
fp = open('yourpdf.pdf', 'rb')
rsrcmgr = PDFResourceManager()
laparams = LAParams()
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
interpreter = PDFPageInterpreter(rsrcmgr, device)
pages = PDFPage.get_pages(fp)
for page in pages:
print('Processing next page...')
interpreter.process_page(page)
layout = device.get_result()
for lobj in layout:
if isinstance(lobj, LTTextBox):
x, y, text = lobj.bbox[0], lobj.bbox[3], lobj.get_text()
print('At %r is text: %s' % ((x, y), text))
上面的代码基于 PDFMiner 文档中的 执行布局分析 示例,以及 pnj ( https://stackoverflow.com/a/22898159/1709587 ) 和 Matt Swain ( https://stackoverflow.com/a/ ) 的示例 25262470⁄1709587 )。我对前面的示例做了一些更改:
PDFPage.get_pages()
,这是创建文档的简写,检查它 is_extractable
,并将它传递给 PDFPage.create_pages()
LTFigure
s,因为 PDFMiner 目前无论如何都无法干净地处理其中的文本。LAParams
允许您设置一些参数来控制 PDF 中的单个字符如何被 PDFMiner 神奇地分组为行和文本框。如果您对这种分组是一件需要发生的事情感到惊讶,那么在 pdf2txt 文档 中它是合理的:
在实际的 PDF 文件中,文本部分可能会在运行过程中分成几个块,具体取决于创作软件。因此,文本提取需要拼接文本块。
LAParams
的参数与大多数 PDFMiner 一样,未记录,但您可以 在源代码中 或通过调用 help(LAParams)
在您的 Python shell 中查看它们。 一些 参数的含义在 https://pdfminer-docs.readthedocs.io/pdfminer_index.html#pdf2txt-py 中给出,因为它们也可以作为参数传递给 pdf2text
在命令行中。
上面的 layout
对象是一个 LTPage
,它是一个可迭代的“布局对象”。这些布局对象中的每一个都可以是以下类型之一……
LTTextBox
LTFigure
LTImage
LTLine
LTRect
…或其子类。 (特别是,您的文本框可能都是 LTTextBoxHorizontal
s。)
文档中的这张图片显示了 LTPage
结构的更多细节:
上述每种类型都有一个 .bbox
属性,其中包含一个 ( x0 , y0 , x1 , y1 ) 元组,分别包含对象的左、下、右和上坐标。 y 坐标表示距页面 底部 的距离。如果使用从上到下的 y 轴更方便,您可以从页面的高度中减去它们 .mediabox
:
x0, y0_orig, x1, y1_orig = some_lobj.bbox
y0 = page.mediabox[3] - y1_orig
y1 = page.mediabox[3] - y0_orig
除了 bbox
, LTTextBox
es 还有一个 .get_text()
方法,如上所示,将文本内容作为字符串返回。 Note that each LTTextBox
is a collection of LTChar
s (characters explicitly drawn by the PDF, with a bbox
) and LTAnno
s ( PDFMiner 根据相距很远的字符添加到文本框内容的字符串表示中的额外空格;这些没有 bbox
)。
本答案开头的代码示例结合了这两个属性来显示每个文本块的坐标。
最后,值得注意的是, 与 上面引用的其他 Stack Overflow 答案不同,我不会费心递归到 LTFigure
s。尽管 LTFigure
s 可以包含文本,但 PDFMiner 似乎无法将该文本分组为 LTTextBox
es(您可以自己尝试来自 https://stackoverflow.com/ 的示例 PDF a/27104504/1709587 ) 而是生成一个 LTFigure
直接包含 LTChar
对象。原则上,您可以弄清楚如何将它们拼凑成一个字符串,但 PDFMiner(从 20181108 版开始)无法为您完成。
不过,希望您需要解析的 PDF 不使用其中包含文本的 Form XObjects,因此此警告不适用于您。
原文由 Mark Amery 发布,翻译遵循 CC BY-SA 4.0 许可协议
2 回答5.1k 阅读✓ 已解决
2 回答1.1k 阅读✓ 已解决
4 回答1k 阅读✓ 已解决
3 回答1.1k 阅读✓ 已解决
3 回答1.2k 阅读✓ 已解决
1 回答1.7k 阅读✓ 已解决
1 回答1.2k 阅读✓ 已解决
完全披露,我是 pdfminer.six 的维护者之一。它是 python 3 的 pdfminer 的社区维护版本。
如今,pdfminer.six 有多个 API 可以从 PDF 中提取文本和信息。对于以编程方式提取信息,我建议使用
extract_pages()
。这允许您检查页面上的所有元素,这些元素按布局算法创建的有意义的层次结构排序。以下示例是一种显示层次结构中所有元素的 pythonic 方式。它使用 pdfminer.six 示例目录中的 simple1.pdf。
输出显示层次结构中的不同元素。每个的边界框。以及该元素包含的文本。
( 此处、 此处 和 此处 的类似答案,我会尽量使它们保持同步。)