您可以像这样从 PDF 中提取文本:

from PyPDF2 import PdfReader

reader = PdfReader("example.pdf")
page = reader.pages[0]
print(page.extract_text())

您还可以选择限制要提取的文本方向,例如:

# extract only text oriented up
print(page.extract_text(0))

# extract text oriented up and turned left
print(page.extract_text((0, 90)))

Using a visitor(使用访客)

您可以使用访问者功能来控制要处理和提取页面的哪一部分。您提供的访问者函数将为每个运算符或每个文本片段调用。

在函数 extract_text 的参数 visitor_text 中提供的函数有五个参数:当前转换矩阵、文本矩阵、字体字典和字体大小。在大多数情况下,当前位置的 x 和 y 坐标位于当前变换矩阵的索引 4 和 5 中。

在未知字体的情况下,字体字典可能是无。如果不是 None 它可能例如包含键“/BaseFont”和值“/Arial,Bold”。

警告:在复杂的文档中,计算出的位置可能是错误的。

参数 visitor_operand_before 中提供的函数有四个参数:操作数、操作数参数、当前转换矩阵和文本矩阵。

示例 2:将矩形和文本提取到 SVG 文件中

以下示例将此 PDF 文档的第 3 页转换为 SVG 文件。

这样的 SVG 导出可能有助于理解页面中发生的事情。

from PyPDF2 import PdfReader
import svgwrite

reader = PdfReader("GeoBase_NHNC1_Data_Model_UML_EN.pdf")
page = reader.pages[2]

dwg = svgwrite.Drawing("GeoBase_test.svg", profile="tiny")


def visitor_svg_rect(op, args, cm, tm):
    if op == b"re":
        (x, y, w, h) = (args[i].as_numeric() for i in range(4))
        dwg.add(dwg.rect((x, y), (w, h), stroke="red", fill_opacity=0.05))


def visitor_svg_text(text, cm, tm, fontDict, fontSize):
    (x, y) = (tm[4], tm[5])
    dwg.add(dwg.text(text, insert=(x, y), fill="blue"))


page.extract_text(
    visitor_operand_before=visitor_svg_rect, visitor_text=visitor_svg_text
)
dwg.save()

这里生成的SVG是自下而上的,因为PDF和SVG的坐标系不同。

不幸的是,在复杂的 PDF 文档中,提供给访问者功能的坐标可能是错误的。

为什么文本提取很难

从 PDF 中提取文本可能非常棘手。在某些情况下,没有明确的答案预期结果应该是什么样子:

  1. Paragraphs: 一个段落的文本是否应该在原始 PDF 的相同位置有换行符,或者它应该是一个文本块?

  2. Page numbers: 它们应该包含在摘录中吗?

  3. Headers and Footers: 类似于页码 - 是否应该提取它们?

  4. Outlines: 是否应该提取轮廓?

  5. Formatting: 如果文本是粗体或斜体,它应该包含在输出中吗?

  6. Tables: 文本提取是否应该跳过表格?它应该只提取文本吗?边框是否应该以某种类似 Markdown 的方式显示,或者结构是否应该存在,例如作为 HTML 表格?你将如何处理合并的单元格?

  7. Captions: 是否应包括图像和表格标题?

  8. Ligatures: Unicode 符号 U+FB00 是两个小写字母“f”的单个符号 ff。应该将其解析为 Unicode 符号“ff”还是两个 ASCII 符号“ff”?

  9. SVG images: 是否应该提取文本部分?

  10. Mathematical Formulas: 他们应该被提取吗?公式有索引和嵌套分数。

  11. Whitespace characters: 对于 3cm 的垂直空白应该提取多少行?如果有 3cm 的水平空白,应该提取多少个空格?你什么时候提取制表符,什么时候提取空格?

  12. Footnotes: 提取多页正文时,脚注应该放在哪里?

  13. Hyperlinks and Metadata: 它应该被提取吗?它应该以哪种格式放置在哪里?

  14. Linearization: 假设您在段落之间有一个浮动图形。你是先完成段落还是在中间放置图形文本?

还有一些问题,大多数人会同意正确的输出,但 PDF 存储信息的方式很难实现:

  1. Tables: 通常,表格只是绝对定位的文本。在最坏的情况下,任何一个字母都可以被绝对定位。这使得很难分辨列/行在哪里。

  2. Images: 有时 PDF 不包含显示的文本,而是图像。当您无法复制文本时,您会注意到这一点。然后是在背景中包含图像和文本层的 PDF 文件。这通常发生在扫描文档时。虽然今天的扫描软件(OCR)已经很不错了,但偶尔还是会出现故障。 PyPDF2 不是 OCR 软件;它将无法检测到这些故障。 PyPDF2 也永远无法从图像中提取文本。

最后还有 PyPDF2 将处理的问题。如果您发现此类文本提取错误,请与我们分享 PDF,以便我们进行处理!

OCR 与文本提取

光学字符识别 (OCR) 是从图像中提取文本的过程。执行此操作的软件称为 OCR 软件。 tesseract OCR 引擎是最广为人知的开源 OCR 软件。

PyPDF2 不是 OCR 软件。

数字生成与扫描的 PDF 文件

PDF 文档可以包含图像和文本。 PDF 文件不以语义上有意义的方式存储文本,而是以一种便于在屏幕上显示或打印文本的方式。由于这个原因,从 PDF 中提取文本很困难。

如果您扫描文档,生成的 PDF 通常会显示扫描图像。然后扫描仪还运行 OCR 软件并将识别出的文本放在图像的背景中。扫描仪 OCR 软件的结果可以通过 PyPDF2 提取。但是,在这种情况下,建议直接使用 OCR 软件,因为错误会累积:OCR 软件在识别文本方面并不完美。然后它以一种不适用于文本提取的格式存储文本,PyPDF2 可能会在解析该格式时出错。

因此,我会区分三种类型的 PDF 文档:

  • Digitally-born PDF files: 该文件是在计算机上以数字方式创建的。它可以包含图像、文本、链接、大纲项目(又名书签)、JavaScript ……如果放大很多,文本看起来仍然清晰。

  • Scanned PDF files: 扫描了任意数量的页面。然后将图像存储在 PDF 文件中。因此,该文件只是这些图像的容器。你不能复制文本,你没有链接、大纲项目、JavaScript。

  • OCRed PDF files: 扫描仪运行 OCR 软件并将识别出的文本放在图像的背景中。因此您可以复制文本,但它看起来仍然像扫描件。如果放大足够大,您可以识别像素。

我们可以一直使用 OCR 吗?

您现在可能想知道始终使用 OCR 软件是否有意义。如果 PDF 文件是数字生成的,您可以将其渲染为图像。

我建议不要那样做。

PyPDF2 等文本提取软件可以使用 PDF 中的更多信息,而不仅仅是图像。它可以了解字体、编码、典型字符距离和类似主题。

这意味着 PyPDF2 在处理容易混淆的字符(例如 ​oO0ö​)时具有明显的优势。 PyPDF2 永远不会混淆字符。它只是读取文件中的内容。

PyPDF2 在处理稀有字符时也有优势,例如. OCR 软件将无法正确识别笑脸符号。

试图阻止文本提取

如果共享 PDF 文档的人想要阻止文本提取,有多种方法可以做到:

  1. 将 PDF 的内容存储为图像

  2. 使用乱码字体

但是,如果人们仍应能够阅读文档,则不能完全阻止文本提取。在最坏的情况下,人们可以截屏、打印、扫描并在其上运行 OCR。