如何从PDF文件中提取文本?

357

我正在尝试使用Python提取PDF文件中包含的文本。

我正在使用PyPDF2包(版本1.27.2),并拥有以下脚本:

import PyPDF2

with open("sample.pdf", "rb") as pdf_file:
    read_pdf = PyPDF2.PdfFileReader(pdf_file)
    number_of_pages = read_pdf.getNumPages()
    page = read_pdf.pages[0]
    page_content = page.extractText()
print(page_content)

当我运行代码时,我的输出结果与PDF文档中的不同:

 ! " # $ % # $ % &% $ &' ( ) * % + , - % . / 0 1 ' * 2 3% 4
5
 ' % 1 $ # 2 6 % 3/ % 7 / ) ) / 8 % &) / 2 6 % 8 # 3" % 3" * % 31 3/ 9 # &)
%

我如何提取PDF文档中原样的文本?


8
请使用一个好的PDF查看器——如果可能的话,使用Adobe的标准Acrobat Reader复制文本。你得到了相同的结果吗?不同之处不在于文本,而是在于字体——字符代码映射到其他值。并非所有PDF都包含正确的数据来恢复这种情况。 - Jongware
我尝试了另一个文档,它可以工作。是的,看起来问题出在PDF本身。 - Simplicity
7
该PDF包含一个字符CMap表,因此在本线程中讨论的限制和解决方法是相关的 - https://dev59.com/VVHTa4cB1Zd3GeqPV_Tm. - dwarring
3
PDF文件中确实包含正确的CMAP,因此将临时字符映射转换为纯文本非常简单。但是,需要进行额外的处理才能检索到正确的文本顺序。Mac OS X的Quartz PDF渲染器是一个非常棘手的工具!在它最初的呈现顺序中,我收到了"m T’h iuss iisn ga tosam fopllloew DalFo dnogc wumithe ntht eI tutorial"。只有通过x坐标排序后,我才得到了一个更有可能正确的结果:"This is a sample PDF document I’m using to follow along with the tutorial"。 - Jongware
1
PyPDF2在单词之间/内添加随机空格,非常难以处理。 - YuMei
显示剩余4条评论
34个回答

307
我正在寻找一个适用于Python 3.x和Windows的简单解决方案。很遗憾,textract似乎没有提供支持,但如果你正在寻找一个适用于Windows/Python 3的简单解决方案,请尝试使用tika包,非常直观地用于阅读PDF文件。

Tika-Python是Apache Tika™ REST服务的Python绑定,允许在Python社区中本地调用Tika。

from tika import parser # pip install tika

raw = parser.from_file('sample.pdf')
print(raw['content'])

请注意,Tika是用Java编写的,因此您需要安装Java运行时环境。

37
我测试了pypdf2和tika,并尝试安装但未成功安装textract和pdftotext。 Pypdf2返回了99个单词,而tika从我的测试发票中返回了858个单词。 所以我最终选择了tika。 - Stian
31
我一直遇到“RuntimeError: Unable to start Tika server”错误。 - Nav
5
如果您需要在目录中递归地运行此操作以处理所有的PDF文件,请使用此脚本 - Hope
5
对于遇到“无法启动Tika服务器”错误的用户,我按照这里所建议的链接安装了最新版本的Java来解决问题。在Mac Os X上,我使用 brew 遵循了这个答案进行了安装。 - glS
3
它会将一个大小为76MB的 tika-server.jar 文件下载到 C:\Users\User\AppData\Local\Temp 目录中。如果我稍后清理 temp,有没有办法使它保持永久?它还需要安装JAVA虚拟机,是这样吗? - Basj
显示剩余7条评论

192

pypdf最近有很大的改进。根据数据,它与pdfminer.six相当或更好。

pymupdf / tika / PDFium比pypdf更好,但差异变得非常小 -(主要是在设置新行时)。核心部分是它们速度更快。但它们不是纯Python,这意味着您可能无法执行它们。而且一些许可证可能过于限制,以至于您不能使用它们。

查看基准测试。此基准测试主要考虑英文文本,但也包括德文文本。它不包括:

  • 任何关于表格的特殊内容(只是文本存在,而不涉及格式)
  • 阿拉伯语测试(RTL语言)
  • 数学公式。

这意味着如果您的用例需要这些点,您可能会感知到质量不同。

话虽如此,2022年11月的结果如下:

Quality

Speed

pypdf

我在2022年成为了pypdf和PyPDF2的维护者! 社区在2022年大大改进了文本提取功能。不妨试试看 :-)

from pypdf import PdfReader

reader = PdfReader("example.pdf")
text = ""
for page in reader.pages:
    text += page.extract_text() + "\n"

请注意,以下这些包已经不再维护:
  • PyPDF2, PyPDF3, PyPDF4
  • pdfminer(不带 .six)

pymupdf

import fitz # install using: pip install PyMuPDF

with fitz.open("my.pdf") as doc:
    text = ""
    for page in doc:
        text += page.get_text()

print(text)

其他 PDF 库

  • pikepdf 不支持文本提取(source

3
谢谢!阅读PDF文件的最简单方法毫无疑问是使用这种方式。 - martin36
除此之外,有时它只是找不到页面中的文本... - Raf
1
@Raf 如果你有一个 PDF 文件的例子,请创建一个 issue:https://github.com/pymupdf/PyMuPDF/issues - 负责这个项目的开发者非常活跃。 - Martin Thoma
3
这是截至2022年1月23日的最新可行解决方案。 - Hissaan Ali
过去我一直在处理PDF文件时感到困难,但是这次使用pypdf的实现简直轻而易举。工作做得非常棒,非常感谢! - undefined
显示剩余4条评论

85

1
适用于PDF、epub等各种格式——能够处理即使是PDFMiner无法处理的PDF文件。 - Ulad Kasach
8
textractPoppler:pdftotext (以及其他工具)的封装。 - onewhaleid
1
@ArunKumar:在AWS Lambda中使用任何非内置的东西,您都必须将它及其所有额外的依赖项包含在您的捆绑包中。 - Jeff Learman
@DavidBrown 如果你在 pip install pocketsphinx 之前安装了 conda install swig,然后再安装 pip install textract,这似乎是使其工作的咒语。 - hobs
4
"textract" 似乎已经停止维护(出处)。请直接使用 "pdfminer.six" 或 pymupdf - Martin Thoma
显示剩余5条评论

62

看一下 PyPDF2<=1.26.0 的代码:

import PyPDF2
pdf_file = open('sample.pdf', 'rb')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
page = read_pdf.getPage(0)
page_content = page.extractText()
print page_content.encode('utf-8')

输出结果为:

!"#$%#$%&%$&'()*%+,-%./01'*23%4
5'%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&)
%

使用相同的代码从201308FCR.pdf读取PDF文件时,输出正常。

文档解释了这个原因:

def extractText(self):
    """
    Locate all text drawing commands, in the order they are provided in the
    content stream, and extract the text.  This works well for some PDF
    files, but poorly for others, depending on the generator used.  This will
    be refined in the future.  Do not rely on the order of text coming out of
    this function, as it will change if this function is made more
    sophisticated.
    :return: a unicode string object.
    """

@VineeshTP:你是否得到了page_content的任何内容?如果是,那么请尝试使用不同于(utf-8)的编码方式,看看是否有帮助。 - Quinn
我发现用Python读取PDF最好的库是“tika”。 - Vineesh TP
未找到201308FCR.pdf文件。 - Chaitanya Bapat
@Matin Thoma,从PDF中提取Python代码时,是否有可能保留格式? - Alexander Cska

47

尝试了textract(似乎有太多依赖关系),pypdf2(无法从我测试的pdf中提取文本)和tika(速度太慢)后,我最终使用了xpdf的pdftotext(如另一个答案中已建议的那样)并直接从Python调用二进制文件(您可能需要调整pdftotext的路径):

import os, subprocess
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
args = ["/usr/local/bin/pdftotext",
        '-enc',
        'UTF-8',
        "{}/my-pdf.pdf".format(SCRIPT_DIR),
        '-']
res = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = res.stdout.decode('utf-8')

有一个pdftotext可以做基本相同的事情,但是这个假设pdftotext在/usr/local/bin中,而我在AWS Lambda中使用它并希望从当前目录中使用它。

顺便说一下:要在Lambda上使用此功能,您需要将二进制文件和libstdc++.so的依赖项放入Lambda函数中。我个人需要编译xpdf。由于这些说明会使答案变得冗长,所以我将它们放在我的个人博客中。


6
天哪,它有效了!!终于有一个解决方案可以按正确的顺序提取文本!我想抱抱你感谢这个答案!(或者如果你不喜欢拥抱,这里有一杯虚拟的咖啡/啤酒/...) - DonQuiKong
8
很高兴能够帮到你!点赞的感觉就像拥抱一样,所以我很好! - hansaplast
简单...很棒的开箱即用思维! - shantanu pathak
请再给PyPDF2一个机会。我们已经对它进行了很多改进 :-) - Martin Thoma

19

我尝试了许多Python PDF转换器,我想更新这篇评论。 Tika是最好的之一。但PyMuPDF是@ehsaneha用户带来的好消息。

我写了一个代码来比较它们: https://github.com/erfelipe/PDFtextExtraction,希望能帮助你。

Tika-Python是一个Python绑定到Apache Tika™ REST服务的库,允许在Python社区中本地调用Tika。

from tika import parser

raw = parser.from_file("///Users/Documents/Textos/Texto1.pdf")
raw = str(raw)

safe_text = raw.encode('utf-8', errors='ignore')

safe_text = str(safe_text).replace("\n", "").replace("\\", "")
print('--- safe text ---' )
print( safe_text )

5
非常感谢.encode('utf-8', errors='ignore') - Evgeny
属性错误:模块“os”没有“setsid”属性。 - keramat
当以'rb'模式打开文件时,这对我很有效。with open('../path/to/pdf','rb') as pdf: raw = str(parser.from_file(pdf)) text = raw.encode('utf-8', errors='ignore') - gl3yn

13
你可能想使用经过时间验证的 xPDF 和衍生工具来提取文本,因为 pyPDF2 在文本提取方面仍然存在 各种问题
长话短说,PDF 中的文本编码方式有很多变化,可能需要解码 PDF 字符串本身,然后需要与 CMAP 映射,接着可能需要分析单词和字母之间的距离等等。
如果 PDF 文件已损坏(即显示正确的文本,但复制时却出现垃圾字符),而你确实需要提取文本,则可以考虑将 PDF 转换为图像(使用 ImageMagik),然后使用 OCR 工具 Tesseract 从图像中获取文本。

返回翻译文本:-1,因为OP正在询问如何在Python中读取pdf文件,尽管有一个xpdf包装器可用于Python,但维护情况较差。 - cduguet
你可能想再试一下 PyPDF2(注意大写)。 - Martin Thoma

10

在某些情况下,PyPDF2会忽略空格并使得结果文本混乱不堪,但我使用PyMuPDF并非常满意。您可以使用此链接获取更多信息。


pymupdf是我观察到的最佳解决方案,不需要像pdftotext或tika一样的额外C++库或Java。 - Kay
pymypdf确实是最好的解决方案,无需额外的服务器或库,它可以处理PyPDF2、PypDF3和PyPDF4无法检索到文本字符串的文件。非常感谢! - Andrea Bisello
要安装pymupdf,请运行pip install pymupdf==1.16.16。使用这个特定版本是因为今天最新版本(17)无法工作。我选择了pymupdf,因为它可以提取文本换行字段到新行字符\n。所以我用pymupdf从pdf中提取文本到一个字符串,然后使用my_extracted_text.splitlines()将文本分割成行,并放入一个列表中。 - erickfis
PyMuPDF真的很令人惊讶。谢谢。 - erfelipe
页面不存在。 - Nouman

10

pdftotext 是最好、最简单的一个!同时 pdftotext 也保留了原始文件的结构。

我尝试过 PyPDF2、PDFMiner 和其他一些工具,但它们都没有给出令人满意的结果。


在安装pdf2text时,出现了以下信息:“Collecting PDFMiner (from pdf2text)”,所以我现在不理解这个答案。 - zhy
2
pdf2text和pdftotext是不同的。您可以使用答案中的链接。 - Dharam
好的。那有点令人困惑。 - zhy
你可能想再试一下 PyPDF2。我们已经对它进行了很多改进。 - Martin Thoma

10

我在这里找到了一个解决方案 PDFLayoutTextStripper

它很好,因为它可以 保留原始PDF的布局

它是用Java编写的,但我已经添加了一个网关来支持Python。

示例代码:

from py4j.java_gateway import JavaGateway

gw = JavaGateway()
result = gw.entry_point.strip('samples/bus.pdf')

# result is a dict of {
#   'success': 'true' or 'false',
#   'payload': pdf file content if 'success' is 'true'
#   'error': error message if 'success' is 'false'
# }

print result['payload']

PDFLayoutTextStripper的示例输出: 在此输入图片描述

您可以在使用Python进行文本提取中了解更多详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接