Python中更高效解析PDF的方法求教
问题
我需要解析PDF提取特定信息,目前用pypdf能提取文本,但因为PDF带格式,整理成可用格式太麻烦。
具体需求:
- 从目标PDF的表格里提取
Asset、Transaction Type、Amount字段 - 如果没法完整提取表格,至少要单独提取:股票代码(比如
(CSCO))、资产类型(比如[ST])、交易类型(比如S)、金额
现有代码能提取文本,但结果不理想,想找更优方案:
import pypdf import io import requests as re import pandas as pd from bs4 import BeautifulSoup import pickle import fnmatch import re as rx url = 'https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2020/20017693.pdf' c = io.BytesIO(re.get(url = url).content) pdf = pypdf.PdfReader(c) text = "" for page in pdf.pages: text += page.extract_text() + "\n" substring = text.split("\n") holding = fnmatch.filter(substring, '*(*)*') htype = fnmatch.filter(substring, '*[[]*[]]*')
优化方案
方法1:用专门的PDF表格提取库(推荐)
这类库能直接识别PDF内的表格结构,比纯文本提取效率高得多,推荐使用camelot-py或tabula-py。
以camelot-py为例:
- 安装依赖:
pip install camelot-py[cv]
- 提取表格代码:
import camelot import requests import io url = 'https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2020/20017693.pdf' pdf_content = io.BytesIO(requests.get(url).content) # 提取全页表格,用lattice模式适配带边框的表格 tables = camelot.read_pdf(pdf_content, pages='all', flavor='lattice') # 目标表格为第一个,转为DataFrame并清理 df = tables[0].df # 重置表头,移除无效行 df.columns = ['Asset', 'Transaction Date', 'Transaction Type', 'Amount', 'Comment'] df = df.drop([0, 1]) # 输出需要的字段 print(df[['Asset', 'Transaction Type', 'Amount']])
该方法直接获取结构化表格数据,仅需简单清理即可使用。
方法2:正则优化文本提取(表格提取库失效时备用)
若PDF格式特殊导致表格提取库适配不佳,可通过正则精准匹配目标字段:
import pypdf import io import requests import re import pandas as pd url = 'https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2020/20017693.pdf' c = io.BytesIO(requests.get(url).content) pdf = pypdf.PdfReader(c) text = "" for page in pdf.pages: text += page.extract_text() + "\n" # 正则匹配每行的完整结构,捕获关键字段 pattern = r'(?P<asset>.+\([A-Z]+\).+\[[A-Z]+\])\s+(?P<trans_date>\d{1,2}/\d{1,2}/\d{4})\s+(?P<trans_type>[A-Z])\s+(?P<amount>.+)\s*(?P<comment>.*)' results = [] for match in re.finditer(pattern, text): asset_info = match.group('asset') # 单独提取股票代码和资产类型 stock_code = re.search(r'\(([A-Z]+)\)', asset_info).group(1) asset_type = re.search(r'\[([A-Z]+)\]', asset_info).group(1) results.append({ '股票代码': stock_code, '资产类型': asset_type, '交易类型': match.group('trans_type'), '金额': match.group('amount'), '资产描述': asset_info }) # 转为DataFrame查看结果 df = pd.DataFrame(results) print(df)
该正则表达式精准匹配行结构,相比fnmatch的模糊匹配,结果更可靠。
补充说明
- 若选择
tabula-py,安装命令为pip install tabula-py,可根据官方文档调整参数适配不同PDF格式。 - 若遇到扫描版PDF(图片格式),需先用OCR工具(如
pytesseract)转成可编辑文本后再提取,本次目标PDF为可编辑文本,无需此步骤。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

