标星★公众号爱你们♥
量化投资与机器学习编辑部报道
近期原创文章:
♥5种机器学习算法在预测股价的应用(代码+数据)
♥Two Sigma用新闻来预测股价走势,带你吊打Kaggle
♥2万字干货:利用深度学习最新前沿预测股价走势
♥机器学习在量化金融领域的误用!
♥基于RNN和LSTM的股市预测方法
♥如何鉴别那些用深度学习预测股价的花哨模型?
♥优化强化学习Q-learning算法进行股市
♥WorldQuant 101 Alpha、国泰君安 191 Alpha
♥基于回声状态网络预测股票价格(附代码)
♥计量经济学应用投资失败的7个原因
♥配对交易千千万,强化学习最NB!(文档+代码)
♥关于高盛在Github开源背后的真相!
♥新一代量化带货王诞生!Oh My God!
♥独家!关于定量/交易求职分享(附真实试题)
♥Quant们的身份危机!
♥AQR最新研究 | 机器能“学习”金融吗?
还在为抓取各种PDF格式的财务、数据报表而烦恼吗?
还在为自己手工操作导致的效率低下而烦恼吗?
还在担心没有趁手的兵器吗?
今天,公众号为大家介绍一款神器:
PDFPlumbe
轻松玩转PDF,痛快抓数据!助你一臂之力!
获取全部代码,见文末
关于PDFPlumbe
PDFPlumb最适合提取电脑生成的PDF,而不是扫描的PDF。它是在pdfminer和pdfmine.six基础上设计的。
适用版本:Python2.7、3.1、3.4、3.5和3.6。
安装PDFPlumbe
pip install pdfplumber
要使用pdfplumber的可视化调试工具,还需要在计算机上安装ImageMagick(/index.php),说明如下:
http://docs.wand-/en/latest/guide/install.html#install-imagemagick-debian
具体参数、提取流程与可视化我们将以案例进行展示,更详细的内容,请大家在文末下载安装包自行查看。
案例一
pdf = pdfplumber.open("../pdfs/ca-warn-report.pdf") p0 = pdf.pages[0] im = p0.to_image() imimportpdfplumber
使用 .extract_table 获取数据:
table[:3]table = p0.extract_table()
使用pandas将列表呈现为一个DataFrame,并在某些日期内删除多余的空格。
df = pd.DataFrame(table[1:], columns=table[0]) forcolumn in["Effective", "Received"]: df[column] = df[column].str.replace(" ", "")importpandas aspd
大功告成!
具体是如何产生的呢?
红线代表pdfplumber在页面上找到的线,蓝色圆圈表示这些线的交叉点,淡蓝色底纹表示从这些交叉点派生的单元格。
案例二:从PDF中提取图形数据
report = pdfplumber.open("../pdfs/ag-energy-round-up--02-24.pdf").pages[0] im = report.to_image() imimportpdfplumber
页面对象具有 .curves 属性,该属性包含在页面上找到的一个curve对象列表。本报告包含12条曲线,每图4条:
12 report.curves[0]len(report.curves)
将它们传递.draw_lines 确定曲线的位置:
im.draw_lines(report.curves, stroke="red", stroke_width=2)
我们通过循环使用四种颜色的调色板来获得更好的显示感:
colors = [ "gray", "red", "blue", "green"] fori, curve inenumerate(report.curves): stroke = colors[i%len(colors)] im.draw_circles(curve["points"], radius=3, stroke=stroke, fill="white") im.draw_line(curve["points"], stroke=stroke, stroke_width=2) imim.reset()
案例三
pdf = pdfplumber.open("../pdfs/background-checks.pd") p0 = pdf.pages[0] im = p0.to_image() imimportpdfplumber
使用 PageImage.debug_tablefinder() 来检查表格:
im.reset().debug_tablefinder()
默认设置正确地标识了表的垂直边界,但是没有捕获每组5个states/territories之间的水平边界。所以:
使用自定义 .extract_table:
因为列由行分隔,所以我们使用 vertical_strategy="lines"
因为行主要由文本之间的沟槽分隔,所以我们使用 horizontal_strategy="text"
由于文本的左、右端与竖线不是很齐平,所以我们使用 intersection_tolerance: 15
"vertical_strategy": "lines", "horizontal_strategy": "text", "intersection_x_tolerance": 15 } im.reset().debug_tablefinder(table_settings)table_settings = {
forrow intable[:5]: print(row)table = p0.extract_table(table_settings)
清理数据(页眉页脚等):
" • ".join(core_table[0])core_table = table[3:3+56]
" • ".join(core_table[-1])
"state", "permit", "handgun", "long_gun", "other", "multiple", "admin", "prepawn_handgun", "prepawn_long_gun", "prepawn_other", "redemption_handgun", "redemption_long_gun", "redemption_other", "returned_handgun", "returned_long_gun", "returned_other", "rentals_handgun", "rentals_long_gun", "private_sale_handgun", "private_sale_long_gun", "private_sale_other", "return_to_seller_handgun", "return_to_seller_long_gun", "return_to_seller_other", "totals" ]COLUMNS = [
ifi == 0: returnx ifx == "": returnNone returnint(x.replace(",", "")) fromcollections importOrderedDict defparse_row(row): returnOrderedDict((COLUMNS[i], parse_value(i, cell)) fori, cell inenumerate(row)) data = [ parse_row(row) forrow incore_table ] Now here's the first row, parsed: data[0]defparse_value(i, x):
案例四
importre fromcollections importOrderedDict pdf = pdfplumber.open("../pdfs/san-jose-pd-firearm-sample.pdf") p0 = pdf.pages[0] im = p0.to_image() imimportpdfplumber
我们在pdfplumber检测到的每个 char 对象周围绘制矩形。通过这样做,我们可以看到报表主体的的每一行都有相同的宽度,并且每个字段都填充了空格(“”)字符。这意味着我们可以像解析标准的固定宽度数据文件一样解析这些行。
im.reset().draw_rects(p0.chars)
使用 page .extract_text(…) 方法,逐行抓取页面上的每个字符(文本):
print(text)text = p0.extract_text()
清理数据(页眉页脚等):
core = re.search(core_pat, text).group(1) print(core)core_pat = pile(r"LOCATION[\-\s]+(.*)\n\s+Flags = e", re.DOTALL)
在这份报告中,每f一个irearm占了两行。下面的代码将表拆分为two-line,然后根据每个字段中的字符数解析出字段:
line_groups = list(zip(lines[::2], lines[1::2])) print(line_groups[0])lines = core.split("\n")
returnOrderedDict([ ("type", first_line[:20].strip()), ("item", first_line[21:41].strip()), ("make", first_line[44:89].strip()), ("model", first_line[90:105].strip()), ("calibre", first_line[106:111].strip()), ("status", first_line[112:120].strip()), ("flags", first_line[124:129].strip()), ("serial_number", second_line[0:13].strip()), ("report_tag_number", second_line[21:41].strip()), ("case_file_number", second_line[44:64].strip()), ("storage_location", second_line[68:91].strip()) ]) parsed = [ parse_row(first_line, second_line) forfirst_line, second_line inline_groups ]defparse_row(first_line, second_line):
parsed[:2]
通过DataFrame进行展示:
columns = list(parsed[0].keys()) pd.DataFrame(parsed)[columns]mport pandas aspd
获取代码
在后台输入(严格大小写)
Pdfplumber_文件
—End—
量化投资与机器学习微信公众号,是业内垂直于Quant、MFE、CST、AI等专业的主流量化自媒体。公众号拥有来自公募、私募、券商、银行、海外等众多圈内18W+关注者。每日发布行业前沿研究成果和最新量化资讯。
你点的每个“在看”,都是对我们最大的鼓励