返回介绍

5.2 解析 PDF 的编程方法

发布于 2024-01-27 21:43:11 字数 8743 浏览 0 评论 0 收藏 0

处理 PDF 要比 Excel 文件更加困难,因为每一个 PDF 文件的格式都不可预知。(如果你有一系列 PDF 文件,那么就可以对文件进行解析了,因为这些文档的格式很可能是一致的。)

PDF 工具处理文档的方法有很多种,其中一种方法是将 PDF 转换成文本。在我们写作本书的同时,Danielle Cervantes 在 NICAR 上做了一个关于 PDF 工具的演讲,NICAR 是一个针对记者的 listserv1。这个演讲汇总了下列 PDF 解析工具:

1listserv 是一个用来管理电子邮件列表的软件。——译者注

· ABBYY's Transformer

· Able2ExtractPro

· Acrobat Professional

· Adobe Reader

· Apache Tika

· Cogniview's PDF to Excel

· CometDocs

· Docsplit

· Nitro Pro

· PDF XChange Viewer

· pdfminer

· pdftk

· pdftotext

· Poppler

· Tabula

· Tesseract

· xPDF

· Zamzar

除了上面这些工具,你还可以用许多编程语言来解析 PDF,其中包括 Python。

 仅因为你知道类似 Python 这样的工具,并不意味着它总是解决问题的最佳工具。考虑到可用的工具有很多种,你可能会发现用另一个工具来完成部分任务(比如数据提取)更加容易。保持开放的心态,事先对各种可用的工具进行调研。

在 4.1 节中提到过,PyPI 网站是查找 Python 包的好地方。如果搜索“PDF”(https://pypi.python.org/pypi?:action=search&term=pdf&submit=search),你会得到一堆结果,类似图 5-1 给出的那些。

图 5-1:PyPI 网站上的 PDF 包

浏览这些 Python 包,了解一下每个库的详细信息,但分辨不出哪一个库是解析 PDF 的最佳选择。如果你尝试更多的搜索,比如“parse pdf”(解析 pdf),会出现更多的库供你选择,但还是没有明显的最佳选择(搜索结果见 https://pypi.python.org/pypi?:action=search&term=parse+pdf&submit=search)。所以我们用搜索引擎查看一下大家都在用什么库来解析 PDF。

 在搜索库或者答案时,注意观察你找到资料的发布日期。帖子或问题的年代越久远,它过时且不再适用的可能性就越大。先试着将搜索范围限定在过去的两年内,然后仅在需要时再扩大搜索的时间范围。

在阅读了许多教程、文档、博客文章和几篇有用的文章(例如这一篇:http://www.binpress.com/tutorial/manipulating-pdfs-with-python/167)之后,我们决定使用 slate 库(https://pypi.python.org/pypi/slate)。

 slate 能够满足我们的需求,但并非总是如此。放弃并从头开始也是可以的。如果有很多库可供选择的话,选择你认为最合适的那一个,即使有人告诉你它不是“最好的”工具。究竟哪一个工具最好,大家见仁见智。在你学习编程的过程中,“最好的”工具就是你凭直觉选择的那一个。

5.2.1 利用slate库打开并读取PDF

我们决定用 slate 库来解决这个问题,下面我们来安装这个库。在命令行中运行:

pip install slate

现在你已经安装了 slate,你可以创建一个名为 parse_pdf.py 的脚本,将下面的代码保存其中。一定要确保脚本文件和 PDF 文件位于同一文件夹下,或者修改代码中的文件路径。这段代码会打印出文件的前两行内容:

import slate            ➊

pdf = 'EN-FINAL Table 9.pdf'    ➋

with open(pdf) as f:        ➌
  doc = slate.PDF(f)        ➍

for page in doc[:2]:        ➎
  print page

❶ 导入 slate 库。

❷ 创建字符串变量,用于保存文件路径,一定要确保空格和大小写都正确。

❸ 将文件名字符串传入 Python 的 open 函数,这样 Python 就可以打开该文件。Python 将打开的文件保存为变量 f。

❹ 将打开的文件 f 传递给 slate.PDF(f),slate 可以将 PDF 文件解析成可用的格式。

❺ 遍历文档 doc 的前两页并输出,这样我们可以知道程序运行正常。

 通常来说,pip 会安装所有必需的依赖库;但需要包管理器列出这些依赖库。在使用 slate 库或其他库时,如果你得到 ImportError,你应该仔细阅读下一行错误信息,看一下哪个库没有安装。运行代码时如果得到如下错误信息:ImportError: No module named pdfminer.pdfparser,说明安装 slate 时没有正确安装 pdfminer,即使它是必需的库。你需要运行 pip install --upgrade --ignoreinstalled slate==0.3 pdfminer==20110515 来安装 pdfminer(参见 slate 仓库的这个 issue,https://github.com/timClicks/slate/issues/5)。

运行脚本,然后将输出内容与 PDF 中的内容对比一下。

下面是第一页的内容:

TABLE 9Afghanistan 10  11  10  15  40  37  -  -  -  -  90  74  75  74Albania
12  14  9  0  10  99  -  -  -  36  30  75  78  71Algeria 5 y 6 y 4 y 0  2  99
-  -  -  -  68  88  89  87Andorra -   -  -  -  -  100 v -  -  -  -  -  -  -
-Angola 24 x 22 x 25 x -  -  36 x -  -  -  -  -  -  -  -Antigua and Barbuda
-   -   -  -  -  -  -  -  -  -  -  -  -  -Argentina 7 y 8 y 5 y -  -  99 y
-  -  -  -  -  -  -  -Armenia 4  5  3  0  7  100  -  -  -  20  9  70  72
67Australia -   -   -  -  -  100 v -  -  -  -  -  -  -  -Austria -   -
-  -  -  100 v -  -  -  -  -  -  -  -Azerbaijan 7 y 8 y 5 y 1  12  94  -  -
-  58  49  75  79  71Bahamas -   -   -  -  -  -  -  -  -  -  -  -  -
-Bahrain 5 x 6 x 3 x -  -  -  -  -  -  -  -  -  -  -Bangladesh 13  18
8  29  65  31  -  -  -  -  33 y -  -  -Barbados -   -   -  -  -  -  -  -
-  -  -  -  -  -Belarus 1  1  2  0  3  100 y -  -  -  4  4  65 y 67 y 62
yBelgium -   -   -  -  -  100 v -  -  -  -  -  -  -  -Belize 6  7  5
3  26  95  -  -  -  -  9  71  71  70Benin 46  47  45  8  34  80  13  2 y
1  14  47  -  -  -Bhutan 3  3  3  6  26  100  -  -  -  -  68  -  -  -Bolivia (
Plurinational  State of) 26 y 28 y 24 y 3  22  76 y -  -  -  -  16  -  -
-Bosnia and Herzegovina 5  7  4  0  4  100  -  -  -  6  5  55  60
50Botswana 9 y 11 y 7 y -  -  72  -  -  -  -  -  -  -  -Brazil 9 y 11 y 6 y
11  36  93 y -  -  -  -  -  -  -  -Brunei Darussalam -   -   -  -  -  -  -
-  -  -  -  -  -  -Bulgaria -   -   -  -  -  100 v -  -  -  -  -  -  -
-Burkina Faso 39  42  36  10  52  77  76  13  9  34  44  83  84  82Burundi
26  26  27  3  20  75  -  -  -  44  73  -  -  -Cabo Verde 3 x,y 4 x,y 3
x,y 3  18  91  -  -  -  16 y 17  -  -  -Cambodia 36 y 36 y 36 y 2  18  62  -
-  -  22 y 46 y -  -  -Cameroon 42  43  40  13  38  61  1  1 y 7  39
47  93  93  93Canada -   -   -  -  -  100 v -  -  -  -  -  -  -  -Central
African Republic  29  27  30  29  68  61  24  1  11  80 y 80  92  92
92Chad 26  25  28  29  68  16  44  18 y 38  -  62  84  85  84Chile 3 x 3
x 2 x -  -  100 y -  -  -  -  -  -  -  -China -   -   -  -  -  -  -  -  -
-  -  -  -  -Colombia 13 y 17 y 9 y 6  23  97  -  -  -  -  -  -  -  -Comoros
27 x 26 x 28 x -  -  88 x -  -  -  -  -  -  -  -Congo 25  24  25  7  33
91  -  -  -  -  76  -  -  -TABLE 9  CHILD PROTECTIONCountries  and
areasChild labour (%)+ 2005-2012*Child marriage (%) 2005-2012*Birth
registration (%)+ 2005-2012*totalFemale genital mutilation/cutting (%)+
2002-2012*Justification of  wife beating (%) 2005-2012*Violent discipline (%)+
2005-2012*prevalenceattitudestotalmalefemalemarried by 15married by
18womenagirlsbsupport for the practicecmalefemaletotalmalefemale78    THE
STATE OF THE WORLD'S CHILDREN 2014 IN NUMBERS

如果你查看一下 PDF 文件,很容易发现页面中每一行的格式。我们来看一下 page 的数据类型是什么:

for page in doc[:2]:
  print type(page)      ➊

❶ 将代码中的 print page 修改为 print type(page)。

运行代码,输出如下:

<type 'str'>
<type 'str'>

这样我们知道 slate 中的 page 是一个长字符串。这一点很有用,因为现在我们就可以使用字符串方法(想复习字符串方法,可以回看第 2 章)。

总的来说,读取这个 PDF 文件并不难。由于这个文件中只包含表格,几乎没有任何文本,slate 可以很好地解析。在某些情况下,表格被包围在文本中,你可能需要跳过一些行才能获取你想要的数据。如果你需要跳过一些行的话,可以采用上一章 Excel 例子中的方法,创建一个每行递增的计数器,用来找到数据所在的位置,然后利用 4.3 节“什么是索引”中的方法将我们需要的数据提取出来。

我们的最终目标是从 PDF 文件中提取出数据,数据格式与 Excel 文件的输出格式相同。想要做到这一点,我们需要分割字符串,找出每一行的内容。其背后的思考过程是寻找规律,找到每一个新行开始的标志。这听起来可能很简单,但可能会非常复杂。

在处理大型字符串时,人们通常会使用正则表达式(RegEx)。如果你不熟悉正则表达式和如何编写正则表达式的话,这个方法有点困难。如果你准备挑战一下自己,想学习 Python 中正则表达式的更多内容,可以查看 7.2.6 节。对于我们的目标而言,我们将采用一种更简单的方法来提取数据。

5.2.2 将PDF转换成文本

首先我们希望将 PDF 转换成文本,然后再对文本进行解析。如果文件很大或数量很多,这种方法更好。(使用 slate 库的话,每次运行脚本都要对 PDF 进行解析。如果文件很大或很多的话,这种方法既浪费时间又浪费内存。)

我们要用 pdfminer 将 PDF 转换成文本。首先安装这个库:

pip install pdfminer

安装好 pdfminer,你就可以使用一个叫作 pdf2txt.py 的命令,将 PDF 文件转换成文本。现在我们来试一下。运行下面的命令,将 PDF 转换成同一文件夹下的文本文件,这样所有的数据都在同一文件夹下:

pdf2txt.py -o en-final-table9.txt EN-FINAL\ Table\ 9.pdf

第一个参数(-o en-final-table9.txt)是我们想要创建的文本文件。第二个参数(EN-FINAL\ TABLE\ 9.pdf)是我们的 PDF 文件。确保大小写和文件名中的空格正确。空格前面需要加一个反斜线(\)。这叫转义(escaping)。转义是告诉计算机,空格是输入内容的一部分。

利用 Tab 自动补全

给你介绍一位终端里的新朋友:Tab 键。对于上面命令的第二个参数,你可以先输入 EN,然后按两下 Tab 键。如果只有一种备选的话,计算机会自动补全文件名。如果有多种备选,计算机会发出警告音,并返回一系列备选。在输入又长又奇怪的文件夹或文件名时,这种方法极为有用。

试试这个。切换到 home 目录(在基于 Unix 的系统是 cd ~/,在 Windows 上是 cd %cd%)。现在,假设你想进入 Documents 目录。试着输入 cd D,然后按两下 Tab 键。发生了什么?home 目录里还有哪些文件或文件夹以字母 D 开头?(可能是 Downloads 文件夹?)

现在试一下 cd Doc,然后按两下 Tab 键。你应该会看到自动补全成 Documents 文件夹。

运行完这个命令之后,我们创建了这个 PDF 文件的文本格式文件,叫作 en-final-table9.txt。

我们将新文件读入 Python。创建一个新脚本,与前面的脚本保存在同一文件夹下。脚本名叫作 parse_pdf_text.py,或者你认为合适的其他名字。在脚本中写入下列代码:

pdf_txt = 'en-final-table9.txt'
openfile = open(pdf_txt, 'r')

for line in openfile:
  print line

我们可以逐行读取文本,然后打印出每一行,将表格内容以文本格式呈现。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文