本文为你展现,如何用Python把许多PDF文件的文本内容批量提取出来,而且整理存储到数据框中,以便于后续的数据分析。python
最近,读者们在后台的留言,愈发五花八门了。git
写了几篇关于天然语言处理的文章后,一种呼声渐强:github
老师,pdf中的文本内容,有没有什么方便的方法提取出来呢?shell
我能体会到读者的心情。数据库
我展现的例子中,文本数据都是直接能够读入数据框工具作处理的。它们可能来自开放数据集合、网站API,或者爬虫。浏览器
可是,有的时候,你会遇到须要处理指定格式数据的问题。安全
例如pdf。bash
许多的学术论文、研究报告,甚至是资料分享,都采用这种格式发布。微信
这时候,已经掌握了诸多天然语言分析工具的你,会很有“拔剑四顾心茫然”的感受——明明知道如何处理其中的文本信息,但就是隔着一个格式转换的问题,作不来。数据结构
怎么办?
办法天然是有的,例如专用工具、在线转换服务网站,甚至还能够手动复制粘贴嘛。
可是,我们是看重效率的,对不对?
上述办法,有的须要在网上传输大量内容,花费时间较多,并且可能带来安全和隐私问题;有的须要专门花钱购买;有的干脆就不现实。
怎么办?
好消息是,Python就能够帮助你高效、快速地批量提取pdf文本内容,并且和数据整理分析工具无缝衔接,为你后续的分析处理作好基础服务工做。
本文给你详细展现这一过程。
想不想试试?
为了更好地说明流程,我为你准备好了一个压缩包。
里面包括本教程的代码,以及咱们要用到的数据。
请你到 这个网址 下载本教程配套的压缩包。
下载后解压,你会在生成的目录(下称“演示目录”)里面看到如下内容。
演示目录里面包含:
pdf_extractor.py
: 利用pdfminer.six编写的辅助函数。有了它你就能够直接调用pdfminer提供的pdf文本内容抽取功能,而没必要考虑一大堆恼人的参数;demo.ipynb
: 已经为你写好的本教程 Python 源代码 (Jupyter Notebook格式)。另外,演示目录中还包括了2个文件夹。
这两个文件夹里面,都是中文pdf文件,用来给你展现pdf内容抽取。它们都是我几年前发表的中文核心期刊论文。
这里作2点说明:
pdf文件夹内容以下:
newpdf文件夹内容以下:
数据准备好了,下面咱们来部署代码运行环境。
要安装Python,比较省事的办法是装Anaconda套装。
请到 这个网址 下载Anaconda的最新版本。
请选择左侧的 Python 3.6 版本下载安装。
若是你须要具体的步骤指导,或者想知道Windows平台如何安装并运行Anaconda命令,请参考我为你准备的 视频教程 。
安装好Anaconda以后,打开终端,用cd命令进入演示目录。
若是你不了解具体使用方法,也能够参考 视频教程 。
咱们须要安装一些环境依赖包。
首先执行:
pip install pipenv
复制代码
这里安装的,是一个优秀的 Python 软件包管理工具 pipenv 。 安装后,请执行:
pipenv install --skip-lock
复制代码
pipenv 工具会依照Pipfile,自动为咱们安装所须要的所有依赖软件包。
终端里面会有进度条,提示所需安装软件数量和实际进度。
装好后,根据提示咱们执行:
pipenv shell
复制代码
这样,咱们就进入本教程专属的虚拟运行环境了。
注意必定要执行下面这句:
python -m ipykernel install --user --name=py36
复制代码
只有这样,当前的Python环境才会做为核心(kernel)在系统中注册,而且命名为py36。
此处请确认你的电脑上已经安装了 Google Chrome 浏览器。
咱们执行:
jupyter notebook
复制代码
默认浏览器(Google Chrome)会开启,并启动 Jupyter 笔记本界面:
你能够直接点击文件列表中的第一项ipynb文件,能够看到本教程的所有示例代码。
你能够一边看教程的讲解,一边依次执行这些代码。
可是,我建议的方法,是回到主界面下,新建一个新的空白 Python 3 笔记本(显示名称为 py36 的那个)。
请跟着教程,一个个字符输入相应的内容。这能够帮助你更为深入地理解代码的含义,更高效地把技能内化。
当你在编写代码中遇到困难的时候,能够返回参照 demo.ipynb
文件。
准备工做结束,下面咱们开始正式输入代码。
首先,咱们读入一些模块,以进行文件操做。
import glob
import os
复制代码
前文提到过,演示目录下,有两个文件夹,分别是pdf和newpdf。
咱们指定 pdf 文件所在路径为其中的pdf
文件夹。
pdf_path = "pdf/"
复制代码
咱们但愿得到全部 pdf 文件的路径。用glob,一条命令就能完成这个功能。
pdfs = glob.glob("{}/*.pdf".format(pdf_path))
复制代码
看看咱们得到的 pdf 文件路径是否正确。
pdfs
复制代码
['pdf/复杂系统仿真的微博客虚假信息扩散模型研究.pdf',
'pdf/面向影子分析的社交媒体竞争情报搜集.pdf',
'pdf/面向人机协同的移动互联网政务门户探析.pdf']
复制代码
经验证。准确无误。
下面咱们利用 pdfminer 来从 pdf 文件中抽取内容。咱们须要从辅助 Python 文件 pdf_extractor.py
中读入函数 extract_pdf_content
。
from pdf_extractor import extract_pdf_content
复制代码
用这个函数,咱们尝试从 pdf 文件列表中的第一篇里,抽取内容,而且把文本保存在 content 变量里。
content = extract_pdf_content(pdfs[0])
复制代码
咱们看看 content 里都有什么:
content
复制代码
显然,内容抽取并不完美,页眉页脚等信息都混了进来。
不过,对于咱们的许多文本分析用途来讲,这可有可无。
你会看到 content 的内容里面有许多的 \n
,这是什么呢?
咱们用 print
函数,来显示 content 的内容。
print(content)
复制代码
能够清楚看到,那些 \n
是换行符。
经过一个 pdf 文件的抽取测试,咱们创建了信心。
下面,咱们该创建辞典,批量抽取和存储内容了。
mydict = {}
复制代码
咱们遍历 pdfs 列表,把文件名称(不包含目录)做为键值。这样,咱们能够很容易看到,哪些pdf文件已经被抽取过了,哪些尚未抽取。
为了让这个过程更为清晰,咱们让Python输出正在抽取的 pdf 文件名。
for pdf in pdfs:
key = pdf.split('/')[-1]
if not key in mydict:
print("Extracting content from {} ...".format(pdf))
mydict[key] = extract_pdf_content(pdf)
复制代码
抽取过程当中,你会看到这些输出信息:
Extracting content from pdf/复杂系统仿真的微博客虚假信息扩散模型研究.pdf ...
Extracting content from pdf/面向影子分析的社交媒体竞争情报搜集.pdf ...
Extracting content from pdf/面向人机协同的移动互联网政务门户探析.pdf ...
复制代码
看看此时字典中的键值都有哪些:
mydict.keys()
复制代码
dict_keys(['复杂系统仿真的微博客虚假信息扩散模型研究.pdf', '面向影子分析的社交媒体竞争情报搜集.pdf', '面向人机协同的移动互联网政务门户探析.pdf'])
复制代码
一切正常。
下面咱们调用pandas,把字典变成数据框,以利于分析。
import pandas as pd
复制代码
下面这条语句,就能够把字典转换成数据框了。注意后面的reset_index()
把原先字典键值生成的索引也转换成了普通的列。
df = pd.DataFrame.from_dict(mydict, orient='index').reset_index()
复制代码
而后咱们从新命名列,以便于后续使用。
df.columns = ["path", "content"]
复制代码
此时的数据框内容以下:
df
复制代码
能够看到,咱们的数据框拥有了pdf文件信息和所有文本内容。这样你就可使用关键词抽取、情感分析、类似度计算等等诸多分析工具了。
篇幅所限,咱们这里只用一个字符数量统计的例子来展现基本分析功能。
咱们让 Python 帮咱们统计抽取内容的长度。
df["length"] = df.content.apply(lambda x: len(x))
复制代码
此时的数据框内容发生如下变化:
df
复制代码
多出的一列,就是 pdf 文本内容的字符数量。
为了在 Jupyter Notebook 里面正确展现绘图结果,咱们须要使用如下语句:
%matplotlib inline
复制代码
下面,咱们让 Pandas 把字符长度一列的信息用柱状图标示出来。为了显示的美观,咱们设置了图片的长宽比例,而且把对应的pdf文件名称以倾斜45度来展现。
import matplotlib.pyplot as plt
plt.figure(figsize=(14, 6))
df.set_index('path').length.plot(kind='bar')
plt.xticks(rotation=45)
复制代码
可视化分析完成。
下面咱们把刚才的分析流程整理成函数,以便于未来更方便地调用。
咱们先整合pdf内容提取到字典的模块:
def get_mydict_from_pdf_path(mydict, pdf_path):
pdfs = glob.glob("{}/*.pdf".format(pdf_path))
for pdf in pdfs:
key = pdf.split('/')[-1]
if not key in mydict:
print("Extracting content from {} ...".format(pdf))
mydict[key] = extract_pdf_content(pdf)
return mydict
复制代码
这里输入是已有词典和pdf文件夹路径。输出为新的词典。
你可能会纳闷为什么还要输入“已有词典”。别着急,一下子我用实际例子展现给你看。
下面这个函数很是直白——就是把词典转换成数据框。
def make_df_from_mydict(mydict):
df = pd.DataFrame.from_dict(mydict, orient='index').reset_index()
df.columns = ["path", "content"]
return df
复制代码
最后一个函数,用于绘制统计出来的字符数量。
def draw_df(df):
df["length"] = df.content.apply(lambda x: len(x))
plt.figure(figsize=(14, 6))
df.set_index('path').length.plot(kind='bar')
plt.xticks(rotation=45)
复制代码
函数已经编好,下面咱们来尝试一下。
还记得演示目录下有个子目录,叫作newpdf
对吧?
咱们把其中的2个pdf文件,移动到pdf目录下面。
这样pdf目录下面,就有了5个文件:
咱们执行新整理出的3个函数。
首先输入已有的词典(注意此时里面已有3条记录),pdf文件夹路径没变化。输出是新的词典。
mydict = get_mydict_from_pdf_path(mydict, pdf_path)
复制代码
Extracting content from pdf/微博客 Twitter 的企业竞争情报搜集.pdf ...
Extracting content from pdf/移动社交媒体用户隐私保护对策研究.pdf ...
复制代码
注意这里的提示,原先的3个pdf文件没有被再次抽取,只有2个新pdf文件被抽取。
我们这里一共只有5个文件,因此你直观上可能没法感觉出显著的区别。
可是,假设你原先已经用几个小时,抽取了成百上千个pdf文件信息,结果你的老板又丢给你3个新的pdf文件……
若是你必须从头抽取信息,恐怕会很崩溃吧。
这时候,使用我们的函数,你能够在1分钟以内把新的文件内容追加进去。
这差异,不小吧?
下面咱们用新的词典,构建数据框。
df = make_df_from_mydict(mydict)
复制代码
咱们绘制新的数据框里,pdf抽取文本字符数量。结果以下:
draw_df(df)
复制代码
至此,代码展现完毕。
总结一下,本文为你介绍了如下知识点:
你以前作的数据分析工做中,遇到过须要从pdf文件抽取文本的任务吗?你是如何处理的?有没有更好的工具与方法?欢迎留言,把你的经验和思考分享给你们,咱们一块儿交流讨论。
喜欢请点赞。还能够微信关注和置顶个人公众号“玉树芝兰”(nkwangshuyi)。
若是你对数据科学感兴趣,不妨阅读个人系列教程索引贴《如何高效入门数据科学?》,里面还有更多的有趣问题及解法。