第13讲:PDF 智能处理 Skill 开发 掌握 PDF 文档的自动化处理技能,实现内容提取、格式转换、合并拆分等操作,让 PDF 处理不再繁琐。
一、场景分析 1.1 用户痛点 PDF 是办公中最常用的文档格式之一,但处理起来往往很麻烦:
内容提取困难 :PDF 是固定格式,无法直接复制编辑,需要专门工具提取文字格式转换复杂 :PDF 转 Word/Excel 时经常排版错乱合并拆分繁琐 :多个 PDF 需要合并,或者一个大 PDF 需要拆分成多个小文件批量处理低效 :几百个 PDF 需要统一加水印或加密,手动操作不现实信息检索不便 :在大量 PDF 中搜索特定内容效率低下1.2 典型应用场景 场景 需求描述 Skill 价值 合同管理 批量提取合同关键信息(金额、日期、条款) 自动化信息提取 发票处理 识别发票 PDF 内容,录入财务系统 OCR + 数据提取 报告合并 将多个部门报告合并为一份完整文档 一键合并 文档归档 按规则拆分扫描件,分类存储 智能拆分归档 内容审核 检查 PDF 中的敏感信息 自动扫描标记
二、核心功能设计 2.1 Skill 功能架构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 📄 PDF 智能助手 ├── 内容提取 │ ├── 文字提取 │ ├── 表格提取 │ ├── 图片提取 │ └── 元数据读取 ├── 格式转换 │ ├── PDF → Word │ ├── PDF → Excel │ ├── PDF → 图片 │ └── PDF → HTML ├── 文档操作 │ ├── 合并 PDF │ ├── 拆分 PDF │ ├── 旋转页面 │ └── 重新排序 ├── 文档保护 │ ├── 添加水印 │ ├── 加密保护 │ ├── 权限设置 │ └── 数字签名 └── 智能处理 ├── 内容搜索 ├── 批量重命名 ├── 压缩优化 └── 质量检测
2.2 技术选型 PDF 处理的核心技术栈:
功能 Python 库 说明 基础操作 PyPDF2 / pypdf 合并、拆分、旋转 内容提取 pdfplumber / PyMuPDF 文字、表格提取 格式转换 pdf2docx / pdf2image 转 Word/图片 OCR 识别 pytesseract + pdf2image 扫描件识别 高级处理 ReportLab 生成 PDF、加水印
三、技术实现 3.1 Coze 平台实现 3.1.1 基础操作代码 PDF 合并功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pypdf import PdfReader, PdfWriterimport osdef merge_pdfs (file_list, output_path ): """ 合并多个 PDF 文件 Args: file_list: PDF 文件路径列表 output_path: 输出文件路径 """ writer = PdfWriter() for file_path in file_list: reader = PdfReader(file_path) for page in reader.pages: writer.add_page(page) with open (output_path, 'wb' ) as output_file: writer.write(output_file) return output_path
PDF 拆分功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 def split_pdf (file_path, split_config ): """ 拆分 PDF 文件 Args: file_path: 源 PDF 路径 split_config: 拆分配置 - type: 'range' 按页码范围 / 'every' 每N页拆分 - pages: 页码范围列表(如 [[0,5], [5,10]]) - every_n: 每N页拆分 """ reader = PdfReader(file_path) total_pages = len (reader.pages) output_files = [] if split_config['type' ] == 'range' : for i, (start, end) in enumerate (split_config['pages' ]): writer = PdfWriter() for page_num in range (start, min (end, total_pages)): writer.add_page(reader.pages[page_num]) output_file = f"{file_path.replace('.pdf' , '' )} _part{i+1 } .pdf" with open (output_file, 'wb' ) as f: writer.write(f) output_files.append(output_file) elif split_config['type' ] == 'every' : n = split_config['every_n' ] for i in range (0 , total_pages, n): writer = PdfWriter() for page_num in range (i, min (i + n, total_pages)): writer.add_page(reader.pages[page_num]) output_file = f"{file_path.replace('.pdf' , '' )} _part{i//n+1 } .pdf" with open (output_file, 'wb' ) as f: writer.write(f) output_files.append(output_file) return output_files
3.1.2 内容提取代码 文字提取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import pdfplumberdef extract_text (file_path, options=None ): """ 提取 PDF 文字内容 Args: file_path: PDF 文件路径 options: 提取选项 - pages: 指定页码列表,None 表示全部 - preserve_layout: 是否保留布局 """ options = options or {} pages = options.get('pages' ) preserve_layout = options.get('preserve_layout' , True ) extracted_content = [] with pdfplumber.open (file_path) as pdf: page_numbers = pages if pages else range (len (pdf.pages)) for page_num in page_numbers: if page_num < len (pdf.pages): page = pdf.pages[page_num] text = page.extract_text( layout=preserve_layout ) extracted_content.append({ 'page' : page_num + 1 , 'text' : text }) return extracted_content
表格提取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def extract_tables (file_path, page_num=None ): """ 提取 PDF 中的表格 Args: file_path: PDF 文件路径 page_num: 指定页码,None 表示全部页面 """ tables = [] with pdfplumber.open (file_path) as pdf: pages_to_process = [pdf.pages[page_num]] if page_num else pdf.pages for i, page in enumerate (pages_to_process): page_tables = page.extract_tables() for table in page_tables: tables.append({ 'page' : page_num + 1 if page_num else i + 1 , 'data' : table }) return tables
3.1.3 格式转换代码 PDF 转 Word:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pdf2docx import Converterdef pdf_to_word (pdf_path, output_path=None ): """ PDF 转换为 Word Args: pdf_path: PDF 文件路径 output_path: 输出 Word 路径,默认同名 """ if not output_path: output_path = pdf_path.replace('.pdf' , '.docx' ) cv = Converter(pdf_path) cv.convert(output_path, start=0 , end=None ) cv.close() return output_path
PDF 转图片:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from pdf2image import convert_from_pathimport osdef pdf_to_images (pdf_path, output_dir=None , dpi=200 ): """ PDF 转换为图片 Args: pdf_path: PDF 文件路径 output_dir: 输出目录 dpi: 图片分辨率 """ if not output_dir: output_dir = os.path.dirname(pdf_path) images = convert_from_path(pdf_path, dpi=dpi) image_paths = [] base_name = os.path.basename(pdf_path).replace('.pdf' , '' ) for i, image in enumerate (images): image_path = os.path.join(output_dir, f"{base_name} _page{i+1 } .png" ) image.save(image_path, 'PNG' ) image_paths.append(image_path) return image_paths
3.1.4 文档保护代码 添加水印:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 from pypdf import PdfReader, PdfWriterfrom reportlab.pdfgen import canvasfrom reportlab.lib.pagesizes import letterimport iodef create_watermark (text, opacity=0.3 ): """创建水印 PDF""" packet = io.BytesIO() c = canvas.Canvas(packet, pagesize=letter) c.setFont("Helvetica" , 60 ) c.setFillColorRGB(0.5 , 0.5 , 0.5 , alpha=opacity) c.saveState() c.translate(300 , 400 ) c.rotate(45 ) c.drawCentredString(0 , 0 , text) c.restoreState() c.save() packet.seek(0 ) return PdfReader(packet) def add_watermark (input_path, output_path, watermark_text ): """ 为 PDF 添加水印 Args: input_path: 源 PDF 路径 output_path: 输出路径 watermark_text: 水印文字 """ watermark = create_watermark(watermark_text) writer = PdfWriter() reader = PdfReader(input_path) watermark_page = watermark.pages[0 ] for page in reader.pages: page.merge_page(watermark_page) writer.add_page(page) with open (output_path, 'wb' ) as output_file: writer.write(output_file) return output_path
加密保护:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def encrypt_pdf (input_path, output_path, password ): """ 加密 PDF 文件 Args: input_path: 源 PDF 路径 output_path: 输出路径 password: 密码 """ reader = PdfReader(input_path) writer = PdfWriter() for page in reader.pages: writer.add_page(page) writer.encrypt(password) with open (output_path, 'wb' ) as output_file: writer.write(output_file) return output_path
3.2 OpenClaw 平台实现 OpenClaw 的 PDF Skill 更加简洁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from openclaw import Skill, Toolimport pdfplumberfrom pypdf import PdfReader, PdfWriterclass PDFSkill (Skill ): name = "PDF智能助手" description = "自动化处理 PDF 文档" @Tool def extract_text (self, file: str , pages: list = None ) -> str : """提取 PDF 文字内容""" with pdfplumber.open (file) as pdf: text = "" page_range = pages or range (len (pdf.pages)) for i in page_range: text += f"\n--- 第{i+1 } 页 ---\n" text += pdf.pages[i].extract_text() return text @Tool def merge (self, files: list , output: str ) -> str : """合并多个 PDF""" writer = PdfWriter() for f in files: reader = PdfReader(f) for page in reader.pages: writer.add_page(page) with open (output, 'wb' ) as f: writer.write(f) return f"已合并到 {output} " @Tool def split (self, file: str , pages: list , output_prefix: str ) -> list : """按页码拆分 PDF""" reader = PdfReader(file) output_files = [] for i, (start, end) in enumerate (pages): writer = PdfWriter() for p in range (start, end): writer.add_page(reader.pages[p]) output_file = f"{output_prefix} _part{i+1 } .pdf" with open (output_file, 'wb' ) as f: writer.write(f) output_files.append(output_file) return output_files
四、Prompt 设计 4.1 系统 Prompt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 你是 PDF 智能助手,专门帮助用户处理 PDF 文档。 你可以执行以下操作: 1. 内容提取:提取文字、表格、图片 2. 格式转换:PDF ↔ Word/Excel/图片 3. 文档操作:合并、拆分、旋转、重排序 4. 文档保护:添加水印、加密、权限设置 5. 智能处理:内容搜索、批量重命名、压缩 处理流程: 1. 理解用户的 PDF 处理需求 2. 询问必要的参数(文件路径、页码范围等) 3. 确认操作内容 4. 执行处理 5. 返回处理结果和文件 注意事项: - 处理前确认文件可访问 - 大文件处理时提示等待时间 - 提供处理摘要(处理了多少页、提取了什么内容) - 涉及敏感文档时提醒用户注意安全
4.2 意图识别示例 用户输入 识别意图 提取参数 "把这几个 PDF 合并成一个" 合并 文件列表 "提取这个 PDF 的前5页" 拆分 文件路径、页码范围 "把 PDF 转成 Word" 格式转换 源文件、目标格式 "给这个 PDF 加上机密水印" 加水印 文件路径、水印文字 "提取这个合同里的表格" 表格提取 文件路径、页码
五、实战案例 5.1 案例一:合同信息提取 场景 :法务部门需要从大量合同 PDF 中提取关键信息(金额、日期、签约方)。
解决方案 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import reimport pdfplumberdef extract_contract_info (pdf_path ): """提取合同关键信息""" info = { 'amount' : None , 'dates' : [], 'parties' : [], 'duration' : None } with pdfplumber.open (pdf_path) as pdf: full_text = "" for page in pdf.pages: full_text += page.extract_text() amount_pattern = r'(?:人民币|¥|¥)\s*([\d,\.]+)(?:元|万元)?' amounts = re.findall(amount_pattern, full_text) if amounts: info['amount' ] = amounts[0 ] date_pattern = r'(\d{4}年\d{1,2}月\d{1,2}日|\d{4}-\d{2}-\d{2})' info['dates' ] = re.findall(date_pattern, full_text) party_pattern = r'([甲乙]方|[买卖]方):\s*([^\n]+)' parties = re.findall(party_pattern, full_text) info['parties' ] = [p[1 ].strip() for p in parties] return info
5.2 案例二:发票批量处理 场景 :财务部门每月需要处理大量发票 PDF,提取信息录入系统。
解决方案 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 def batch_process_invoices (pdf_folder ): """批量处理发票 PDF""" import os import pandas as pd results = [] for filename in os.listdir(pdf_folder): if filename.endswith('.pdf' ): pdf_path = os.path.join(pdf_folder, filename) invoice_info = extract_invoice_info(pdf_path) invoice_info['filename' ] = filename results.append(invoice_info) df = pd.DataFrame(results) output_path = os.path.join(pdf_folder, '发票汇总.xlsx' ) df.to_excel(output_path, index=False ) return output_path def extract_invoice_info (pdf_path ): """提取单张发票信息""" return { 'invoice_no' : '' , 'date' : '' , 'amount' : '' , 'seller' : '' , 'buyer' : '' }
六、实战练习 练习 1:PDF 合并工具 创建一个 Skill,实现以下功能:
接收多个 PDF 文件 按文件名排序后合并 生成目录页(显示各文件起始页码) 返回合并后的文件 练习 2:PDF 内容搜索 创建一个 Skill,实现以下功能:
在多个 PDF 中搜索关键词 返回包含关键词的文件列表 显示关键词出现的页码和上下文 生成搜索结果报告 练习 3:批量加水印 创建一个 Skill,实现以下功能:
接收文件夹路径和水印文字 为文件夹内所有 PDF 添加水印 支持自定义水印透明度 保存到新文件夹,保留原文件 七、常见问题 Q1:扫描件 PDF 无法提取文字怎么办? 解决方案 :
使用 OCR 技术识别扫描件 推荐库:pytesseract + pdf2image 先转图片再识别文字 Q2:PDF 转 Word 后排版错乱怎么办? 解决方案 :
使用 pdf2docx 库,保留原排版 对于复杂排版,考虑使用专业工具 转换后手动微调 Q3:如何处理加密的 PDF? 解决方案 :
请求用户提供密码 使用 pypdf 的解密功能 注意:仅处理用户有权访问的文件 八、下节预告 下一讲我们将学习 PPT 智能生成 Skill 开发 ,包括:
PPT 内容自动生成 模板应用与样式统一 图表自动插入 批量幻灯片处理 加入学习群 👉 加入AI编程学习交流群
本讲是《AI Skills 从入门到实践》系列课程的第13讲。
🎓 AI 编程实战课程 想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!