如何用Python提取PDF中非标准表单的复选框与单选框选中状态?
提取非标准PDF复选框/单选框状态的Python方案
你的情况确实是这些复选框属于渲染后的图形元素,而非PDF标准交互式表单字段,所以表单字段相关API无法读取。以下是两种可行的Python解决方案:
方案一:用PyMuPDF(fitz)分析页面图形元素
PyMuPDF可以提取页面中的所有图形路径,通过判断复选框的形状(矩形)是否被填充,或者是否存在打勾的路径,来识别选中状态。
示例代码:
import fitz # PyMuPDF def check_checkbox_status(pdf_path, page_num=-1): doc = fitz.open(pdf_path) page = doc[page_num] # 取最后一页,和原代码逻辑一致 # 获取页面所有图形元素 drawings = page.get_drawings() checkbox_states = [] # 遍历图形,筛选复选框相关元素 for drawing in drawings: # 复选框通常是矩形,先筛选矩形路径 if drawing["type"] == "rect": rect = drawing["rect"] # 检查是否有填充(选中的复选框可能是填充的矩形) has_fill = drawing["fill"] is not None and drawing["fill"] != (1,1,1) # 排除白色填充 # 或者检查是否存在打勾的路径(有些是空心框加勾) has_checkmark = False for path in drawing["items"]: if path[0] == "c": # 贝塞尔曲线,打勾常用这种路径 has_checkmark = True break if has_fill or has_checkmark: # 获取该复选框附近的文本,关联对应选项 nearby_text = page.get_text("text", clip=rect + fitz.Rect(0,0,50,0)) # 向右扩展区域取文本 checkbox_states.append((nearby_text.strip(), "选中")) else: nearby_text = page.get_text("text", clip=rect + fitz.Rect(0,0,50,0)) checkbox_states.append((nearby_text.strip(), "未选中")) doc.close() return checkbox_states # 调用示例 states = check_checkbox_status("data/test.pdf") for item in states: print(f"选项:{item[0]},状态:{item[1]}")
说明:
- 不同工具生成的复选框图形逻辑可能不同,需要根据实际PDF调整判断条件(比如填充色、路径形状)
get_drawings()能获取所有矢量图形,比纯文本提取更精准捕捉图形状态
方案二:结合OCR识别(适合复杂图形场景)
如果图形规则不统一,可将PDF页面转为图片,用OCR工具识别选中标记(比如√、X),再关联对应文本。
示例代码(依赖PyMuPDF和pytesseract):
import fitz import pytesseract from PIL import Image def ocr_checkbox_status(pdf_path, page_num=-1): doc = fitz.open(pdf_path) page = doc[page_num] # 将页面转为图片 pix = page.get_pixmap(dpi=300) # 高DPI提升识别精度 img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples) # OCR识别所有文本和位置 ocr_data = pytesseract.image_to_data(img, output_type=pytesseract.Output.DICT) checkbox_states = [] # 遍历OCR结果,查找包含选中标记的区域 for i in range(len(ocr_data["text"])): text = ocr_data["text"][i].strip() if text in ["√", "X", "✓", "×"]: # 常见选中标记 # 获取标记右侧的文本(对应选项) x, y = ocr_data["left"][i], ocr_data["top"][i] # 查找同一行附近的文本 for j in range(len(ocr_data["text"])): if abs(ocr_data["top"][j] - y) < 10 and ocr_data["left"][j] > x: option_text = ocr_data["text"][j].strip() checkbox_states.append((option_text, "选中")) break elif text in ["Yes", "No", "Check-1", "Check-2", "Check-3"]: # 你的选项文本 # 检查该文本左侧是否有选中标记 x, y = ocr_data["left"][i], ocr_data["top"][i] has_mark = False for j in range(len(ocr_data["text"])): if abs(ocr_data["top"][j] - y) < 10 and ocr_data["left"][j] < x - 10: mark = ocr_data["text"][j].strip() if mark in ["√", "X", "✓", "×"]: has_mark = True break status = "选中" if has_mark else "未选中" checkbox_states.append((text, status)) doc.close() return checkbox_states # 调用示例 states = ocr_checkbox_status("data/test.pdf") for item in states: print(f"选项:{item[0]},状态:{item[1]}")
说明:
- 需要先安装Tesseract OCR引擎,并配置好环境变量
- 可根据实际选中标记调整匹配的字符集合,提升识别准确率
内容的提问来源于stack exchange,提问作者Prahlad Yeri
相关产品推荐
相关产品推荐

