大家好呀,我是你们的花姐!上周公司法务部的小美跟我吐槽,说她每天就像个人肉扫描仪,要在几百份合同里找什么金额、签约方这些信息。我好奇问了一句:"你们天天挖这些数据到底图啥?" 她当场给我上了一课...
一、搞懂小美的需求
小美巴拉巴拉说了一大堆,我总结了下核心其实就是:法务部需要从大量合同中提取关键信息,用于大额合同监控、签约方背景核查、有效期动态追踪等。
简单说就是法务部需从300份PDF合同中提取「合同金额」「签约方」「有效期」等字段 假如我们的合同是下面这种样式
二、Python自动化三件套
第一步:装备你的数字助理
在电脑搜索栏输入"cmd"打开小黑窗,粘贴这两行魔法:
pip install pdfplumber pandas
(这是在给你的电脑安装两个小帮手:PDF拆解专家+数据整理大师)
第二步:复制花姐的智能扫描仪
新建"合同小助手.py"文件,粘贴以下代码:
import pdfplumber
import re
import pandas as pd
import os
def contract_scanner(pdf_path):
try:
with pdfplumber.open(pdf_path) as pdf:
text = ''.join([page.extract_text() for page in pdf.pages if page.extract_text()]) # 防止某些页面没有文本
if not text:
print(f"警告: 无法从 {pdf_path} 提取文本。")
return None
# 信息提取规则:使用正则表达式进行匹配
try:
# 提取合同总价
amount_match = re.search(r'合同总价:\s*¥([\d,]+)', text)
amount = amount_match.group(1) if amount_match else None
# 提取甲乙方
parties_match = re.search(r'甲方:\s*(.*?)\n乙方:\s*(.*?)\n', text)
partyA, partyB = (parties_match.group(1), parties_match.group(2)) if parties_match else (None, None)
# 提取有效期至
validity_match = re.search(r'有效期至:\s*(20\d{2}-\d{2}-\d{2})', text)
validity = validity_match.group(1) if validity_match else None
# 提取签订日期
signed_on_match = re.search(r'签订日期:\s*(\d{4}-\d{2}-\d{2})', text)
signed_on = signed_on_match.group(1) if signed_on_match else None
return [amount, partyA, partyB, validity, signed_on]
except Exception as e:
print(f"提取信息时发生错误:{e}")
return None
except Exception as e:
print(f"处理文件 {pdf_path} 时发生错误:{e}")
return None
# 批量处理流程
all_contracts = []
for file in os.listdir('contracts'):
if file.endswith('.pdf'):
contract_data = contract_scanner(f'contracts/{file}')
if contract_data:
# 将文件名添加到数据中
contract_data.append(file)
all_contracts.append(contract_data)
# 生成结构化数据并保存为 Excel 文件
if all_contracts:
# 表头改为中文,并将文件名列添加到DataFrame
df = pd.DataFrame(all_contracts,
columns=['合同总价', '甲方', '乙方', '有效期至', '签订日期', '文件名']
)
df.to_excel('合同数据库.xlsx', index=False)
print("合同数据已保存到 '合同数据库.xlsx'")
else:
print("没有提取到任何合同数据。")
第三步:见证奇迹
- 把所有合同PDF扔进"contracts"文件夹
- 双击运行这个py文件
- 打开生成的Excel,你会看到这样的魔法阵:
核心代码解析
这个脚本是用来扫描PDF合同,提取特定信息,然后生成Excel文件的。主要用了pdfplumber库来提取文本,然后用正则表达式匹配需要的信息,最后用pandas保存成Excel,属于Python基础编程的范畴。
-
导入必要的库:
import pdfplumber import re import pandas as pd import ospdfplumber用来“打开”PDF文件,re用来查找特定的文本模式,pandas负责将提取的数据变成表格,os用来处理文件操作。🔍 -
定义扫描合同的函数:
def contract_scanner(pdf_path): try: with pdfplumber.open(pdf_path) as pdf: text = ''.join([page.extract_text() for page in pdf.pages if page.extract_text()])这个函数就像一个“合同扫描仪”📄,它从给定的 PDF 文件中提取文本。你可以把它想象成用放大镜去查看文件内容,看看能不能找到我们需要的信息。
-
处理没有文本的情况:
if not text: print(f"警告: 无法从 {pdf_path} 提取文本。") return None如果 PDF 文件里没有文本,那就像找到了一个空白的纸张,什么都没有!所以我们就给出一个“警告”,告诉你文件里面什么也没有。
-
用正则表达式提取合同信息:
amount_match = re.search(r'合同总价:\s*¥([\d,]+)', text)正则表达式是搜索文本的超级大法,像是在合同里寻找“合同总价”这一行,它会匹配文本里符合格式的部分,比如价格是多少!💰 其实,
re.search就是“钓鱼”的时候丢下的“鱼钩”,看看能不能钓到合同里包含价格的部分。 -
提取甲乙方信息:
parties_match = re.search(r'甲方:\s*(.*?)\n乙方:\s*(.*?)\n', text)然后,我们还要查找合同的甲方和乙方是谁。用正则表达式就像是在合同里找名字,“甲方”和“乙方”的名字就藏在特定的地方,它们不容易逃脱我们的法眼!👀
-
处理错误的情况:
except Exception as e: print(f"提取信息时发生错误:{e}") return None万一在提取过程中遇到错误,比如格式不对,系统会及时提醒,避免你在数据里踩坑!😅
-
批量处理多个合同文件:
all_contracts = [] for file in os.listdir('contracts'): if file.endswith('.pdf'): contract_data = contract_scanner(f'contracts/{file}') if contract_data: contract_data.append(file) all_contracts.append(contract_data)这部分是为了处理文件夹里一大堆的合同文件,如果文件名以
.pdf结尾,就丢给我们的“合同扫描仪”去扫描,然后把扫描到的信息放到all_contracts这个大盒子里!📦 -
保存数据为 Excel 文件:
if all_contracts: df = pd.DataFrame(all_contracts, columns=['合同总价', '甲方', '乙方', '有效期至', '签订日期', '文件名']) df.to_excel('合同数据库.xlsx', index=False) print("合同数据已保存到 '合同数据库.xlsx'")最后,我们把这些扫描到的数据整理成一个 Excel 文件。就像是把一堆杂乱无章的纸张整理成一本整齐的文件夹📂,并且还给每个合同加上了文件名,防止以后找不到是哪一个合同。👩💻
-
没提取到数据怎么办:
else: print("没有提取到任何合同数据。")如果没有提取到数据,那就告诉你“没有合同数据”——这个时候,你就知道是时候检查一下是不是合同内容本身有问题了!😬
扩展学习建议
这段代码展示了如何从PDF合同文件中提取关键信息,并将提取到的数据保存为Excel表格。感兴趣的同学可以根据自己需求进一步拓展:
1. 扩展正则表达式的应用
- 更多字段提取:当前代码提取了合同总价、甲乙方、有效期至和签订日期,可以考虑扩展提取更多合同信息,例如:合同编号、付款方式、违约条款、合同状态等。
- 正则表达式优化:当前的正则表达式较为简单,有时可能会出现匹配不精确的情况。可以尝试使用更复杂的正则模式,或者结合机器学习模型提高提取准确性。
2. 处理复杂的PDF结构
- 多列/表格提取:如果合同中有表格结构,
pdfplumber提供了更强大的表格提取功能。你可以尝试提取表格数据并将其结构化。 - 处理扫描版PDF:如果合同是扫描版PDF,
pdfplumber可能无法直接提取文本。在这种情况下,可以结合OCR技术(如Tesseract)进行图像文字识别。
3. 提高错误处理和健壮性
- 捕获更多的异常:除了文本提取失败,还可以考虑捕获PDF打开失败、文件损坏、权限问题等其他错误。
- 日志记录:使用
logging模块替换print语句,记录详细的错误信息,方便后续的调试和分析。
4. 优化数据存储和管理
- 数据库存储:目前数据保存为Excel文件,可以考虑将数据存储到数据库(如MySQL、PostgreSQL等),便于大规模数据管理和查询。
- 数据清洗:在存储数据之前,可以对提取的信息进行进一步的清洗,例如去掉多余的空格,格式化日期等,保证数据的一致性和准确性。
5. 批量处理和性能优化
- 多线程或异步处理:当前代码是顺序处理多个文件,若处理文件数较多时,可能会导致性能瓶颈。可以使用多线程处理,提升效率。
- 分批次处理:对合同文件进行分批处理,避免一次性处理过多文件时内存占用过高。可以根据文件大小或者处理时间进行分批。
6. 界面和可视化
- 图形用户界面(GUI):你可以考虑为该工具添加一个图形用户界面,使用户可以轻松上传PDF文件,并查看提取结果。例如,使用
tkinter或PyQt构建GUI。 - 数据可视化:将提取的合同数据进行可视化分析(如合同总价分布、甲乙方数量统计等),可以使用
matplotlib或seaborn进行图表绘制。
7. 自动化和定时任务
- 定期扫描新合同:如果合同文件夹中有新的文件不断增加,可以将这个功能自动化,每天定时扫描并提取新合同数据。
- 通知和报告:如果程序提取到有异常(如无法提取某些信息),可以通过邮件等方式通知相关人员。
通过以上扩展,你可以让这个项目更加健壮、灵活,并能处理更复杂的合同信息提取任务。
花姐说:
技术不是要取代法务同学,而是把你们从重复劳动中解放出来。就像当初Excel取代算盘,Python也不过是我们新的工具伙伴。哪怕你暂时看不懂代码,先学会用这些工具,就能把时间花在更有价值的地方——比如研究怎么用法律AI预防风险。