第13讲:PDF 智能处理 Skill 开发

第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, PdfWriter
import os

def 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 页拆分
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 pdfplumber

def 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 Converter

def 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_path
import os

def 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, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import io

def 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, Tool
import pdfplumber
from pypdf import PdfReader, PdfWriter

class 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 re
import pdfplumber

def 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)

# 导出为 Excel
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):
"""提取单张发票信息"""
# 使用 OCR 识别扫描件发票
# 或使用 pdfplumber 提取电子发票
# 这里简化处理
return {
'invoice_no': '',
'date': '',
'amount': '',
'seller': '',
'buyer': ''
}

六、实战练习

练习 1:PDF 合并工具

创建一个 Skill,实现以下功能:

  1. 接收多个 PDF 文件
  2. 按文件名排序后合并
  3. 生成目录页(显示各文件起始页码)
  4. 返回合并后的文件

练习 2:PDF 内容搜索

创建一个 Skill,实现以下功能:

  1. 在多个 PDF 中搜索关键词
  2. 返回包含关键词的文件列表
  3. 显示关键词出现的页码和上下文
  4. 生成搜索结果报告

练习 3:批量加水印

创建一个 Skill,实现以下功能:

  1. 接收文件夹路径和水印文字
  2. 为文件夹内所有 PDF 添加水印
  3. 支持自定义水印透明度
  4. 保存到新文件夹,保留原文件

七、常见问题

Q1:扫描件 PDF 无法提取文字怎么办?

解决方案

  • 使用 OCR 技术识别扫描件
  • 推荐库:pytesseract + pdf2image
  • 先转图片再识别文字

Q2:PDF 转 Word 后排版错乱怎么办?

解决方案

  • 使用 pdf2docx 库,保留原排版
  • 对于复杂排版,考虑使用专业工具
  • 转换后手动微调

Q3:如何处理加密的 PDF?

解决方案

  • 请求用户提供密码
  • 使用 pypdf 的解密功能
  • 注意:仅处理用户有权访问的文件

八、下节预告

下一讲我们将学习 PPT 智能生成 Skill 开发,包括:

  • PPT 内容自动生成
  • 模板应用与样式统一
  • 图表自动插入
  • 批量幻灯片处理

加入学习群

👉 加入AI编程学习交流群

点击加入


本讲是《AI Skills 从入门到实践》系列课程的第13讲。

🎓 AI 编程实战课程

想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!