杭州国立公证处-公正摇号 会不定期公布杭州各个楼盘的购房意向登记汇总表和摇号结果,里面公开的数据是很全面的,对于想要分析一波数据搞点事情的人来说,挺有吸引力的。

但当你兴冲冲地去官网下载完数据,一看傻眼了,为啥这个数据是 PDF 格式的,明明可以上传为 Excel 的。如果页数少点的话,没准可以手动粘贴到 Excel里,但当映入眼帘的是一个多达 500 页的 PDF,想让我手动粘到 Excel 是不可能的,这辈子都不可能。

身为一名互联网行业的数据分析师,要是获取到了数据却只能眼睁睁的看着,没法下手,这是绝对不允许的。

于是,开始搜 Python 从 PDF 中提取 Excel 表格的教程,第一个搜到的是 Tabula,专门用于从 PDF 中提取 Excel 表格,官网如下:tabulatabula.technology

Github 地址在这里:chezou/tabula-pygithub.com

python 将PDF 转成图片 python如何将pdf转化为excel_CSV

先安装一下,使用:

pip install tabula-py

特别注意的是,tabula-py 运行时依赖于Java 环境,所以还得安装一下Java。

装好后,用起来也非常简单,下面是一个简单的例子:

import tabula
tabula.convert_into('HZ_YaoHao.pdf', 'HZ_YaoHao.csv', output_format = 'csv')

其中 HZ_YaoHao.pdf 文件中的数据是这个样子的:

只需要一行代码,就可以把 PDF 文件中的表格转为 csv,真的是相当简单哪。

结果看一眼转为 CSV 的数据,怎么有种乱不糟糟的感觉 。。。

对比一下原来的 PDF 文件,会发现,在涉及到 换行的地方,转换的 CSV 文件都会出现问题,比如标题 是否无房家庭,就被拆成了是否无房、家庭,而且分布在文件中的不同行,还有查档编号有两行的,也会被拆分到不同的行,使数据看起来很乱。

看来问题不是这么简单就解决的,不过如果 PDF 表格数据没有换行,而且比较规整的话,使用 Tabula 的性价比还是非常高的,简单一行代码就能搞定。

需要注意的是,上述代码默认只会转化 PDF 的第一页,想要转换所有页数的话,加一个 pages 参数,使 pages = 'all' 即可。

tabula.convert_into('HZ_YaoHao.pdf','HZ_YaoHao.csv',output_format='csv',pages='all')

接下来,又搜到了 pdfplumber,可以从 PDF 中提取出表格、文本、矩形和线条的信息,同时支持可视化调试,看上去挺高大上的。

Github 地址如下:jsvine/pdfplumbergithub.com

python 将PDF 转成图片 python如何将pdf转化为excel_CSV_02

先安装一下:

pip install pdfplumber

使用一下试试:

import pdfplumber
pdf = pdfplumber.open('HZ_YaoHao.pdf')
print(pdf.pages)
pdfplumber 调用 Open 方法打开 PDF 文件,输出 pages 信息,部分结果如下:
[, ,
... ]

可见,pdf.pages 返回的是一个列表,列表里是每一页的 Page 对象,所以通过遍历这个列表,就可以拿到 PDF 文件每一页的信息。

我们来捋一下思路:先拿到 PDF 文件的某一页,比如第一页 pdf.pages[0],然后从中提取出表格数据,转成 Pandas 中的 DataFrame 格式 ( 不懂 Pandas 的同学可以移步我的专栏:Python 数据分析利器 -- Pandas ),输出为CSV 或 Excel 文件,搞定,代码可以这样实现:

import pdfplumber
import pandas as pd
# 打开 PDF 文件
pdf = pdfplumber.open('HZ_YaoHao.pdf')
# 获取 PDF 文件的第一页信息
page0 = pdf.pages[0]
# 从 PDF 中提取表格
table = page0.extract_table()
# 将表格数据转化为 DataFrame 格式
yaohao_df = pd.DataFrame(table)
# 输出第一行数据
print(yaohao_df.loc[0])
# 保存到 CSV 文件
yaohao_df.to_csv('yaohao.csv', index = False, header = True)

第一行输出结果如下:

0 购房登记号

1 购房人姓名

2 购房人证件号码

3 是否无房\n家庭

4 查档编号

5 其他购房人及家庭成员

6 其他购房人及家庭成员证件号码

Name: 0, dtype: object

可以看到,对于原表格中有换行的 是否无房家庭,转化完后会多出一个换行符 \n 。

再来看一下 CSV 文件中的数据:

可以发现,是否无房家庭因为有换行符 \n,所以进行了换行,同理,A0004 和 A0005 两行因为原 PDF 表格中有上下两行,也进行了换行。也就是说,如果 PDF 表格中的某一个单元格有多行,pdfplumber 在解析其中的表格时都会添加一个 \n 的换行符,这样问题就简单了,把转换后的所有字符串中的 \n 替换为空字符串,问题是不是就可以解决了,我们来尝试一下,

在调用 yaohao_df.to_csv( ) 之前添加一行:

yaohao_df.replace(to_replace = r'\n', value = '', regex = True, inplace = True)

使用正则表达式,将 yaohao_df 中的所有 \n 替换为空,CSV 文件结果如下:

这样的结果看起来就整齐多了,不足的是首行 0,1,2,3,4,5,6,让人看起来不是很舒服,原因是PDF 表格中的标题行也被当成了 DataFrame 中的一行,这个需要特殊处理一下,同时上述程序只处理了第 1 页,需要改成处理所有的页码,完整的程序如下:

import pdfplumber
import pandas as pd
pdf = pdfplumber.open('HZ_YaoHao.pdf')
total_pd = pd.DataFrame()
pdf_columns = list()
for page in range(len(pdf.pages)):
print(page)
if len(pdf.pages) > 0:
temp_table = pdf.pages[page].extract_table()
if page == 0:
temp_df = pd.DataFrame(temp_table[1:], columns = temp_table[0])
temp_df.columns = [ temp.replace('\n', '') for temp in temp_df.columns ]
pdf_columns = temp_df.columns
else:
temp_df = pd.DataFrame(temp_table)
temp_df.columns = pdf_columns
temp_df.replace(to_replace = r'\n', value = '', regex = True, inplace = True)
total_pd = pd.concat([total_pd, temp_df], ignore_index = True)
# 保存到 CSV 文件
total_pd.to_csv('yaohao.csv', header = True, index = False)
# 保存到 Excel 文件
total_pd.to_excel('yaohao.xlsx', header = True, index = False)

来看看最终的效果,CSV 和 Excel 文件各 547 行:


至此,杭州摇号 PDF 中的购房意向登记汇总表 数据就完美的转化成了 CSV 和 Excel 格式,但当你试图把它套用在摇号结果的 PDF 中时,却发现根本不起作用,原 PDF 中的数据如下:

因为程序不会识别这是一个表格,看来摇号结果的 PDF 又是另一种处理思路了。

另一个问题,官网已经有 150 多个楼盘的数据了,一个一个去下载真的很麻烦啊,有没有办法一次性下载所有的 PDF 文件,然后一次性用程序处理呢?

当然可以啊,用 Python 写个爬虫抓一下数据,把所有文件存到某个文件目录下,然后统一把该目录下的 PDF 文件转化为 CSV 和 Excel 文件就好啦,且听下回分解。