You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python定位PDF文件中的数字签名并提取相关信息

问题:使用Python检测PDF数字签名并提取签署人邮箱信息
  • 需求为用Python批量处理多份PDF文件,检测文件是否存在数字签名,签名存在时提取其中的详情信息,本次需要提取的核心字段是签署人邮箱,无邮箱的签名属于例外场景。
  • 最初的实现思路是先把文档内所有签名对象存入列表,再遍历列表读取每个签名的详情,需要确认该方案是否可行,以及签名对象的具体定位方法。
  • 目前网上可检索到的资料大多围绕PDF签名验证、PDF签署功能展开,和当前提取签名属性的需求不匹配。

问题更新

  • 目前已经可以定位到PDF中的签名对象并获取内容,但在解码环节遇到问题。
  • 早期临时定位方案是直接指定签名对象的索引,但不同PDF的签名对象索引不固定,后续优化思路是:签名对象的Type属性固定为Sig,可以遍历所有对象检查Type属性,属性值为Sig即为目标签名对象。
  • 获取到的签名内容类型为pdfreader.types.native.HexString,原计划直接解码该字符串获取数据,但转字节后用utf-8、ascii解码均报错:
    • UTF-8解码报错:'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte
    • ASCII解码报错:'ascii' codec can't decode byte 0x82 in position 1: ordinal not in range(128)
      需要可行的解码/字段提取方案。

解决方案
  • 之前解码报错的核心原因是:签名的content字段本身不存储需要的业务属性,之前控制台输出的签名对象内容不完整(大概率是Visual Studio调试控制台的输出截断问题),数字签名对象实际包含更多直接可读取的属性,本次需要的邮箱信息就直接存储在签名对象的Name属性下,不需要解码HexString内容。
  • 剩下需要解决的是获取PDF文件内的总对象数问题:文档最后一个trailer块中包含Size属性,对应文件内的对象总数。由于pdfreader的PDFTrailer对象没有直接暴露该属性,本次通过字符串操作提取该值。

注意:遍历对象的循环中使用了try-catch兜底逻辑,更严谨的实现应该在读取对象前先判断对象是否存在、是否包含Type属性,不建议直接照搬以下代码,建议根据实际场景补充更严谨的判断逻辑。

完整实现代码如下:

from pdfreader import PDFDocument

filename = r"<filepath.pdf>"
fd = open(filename, "rb")
doc = PDFDocument(fd)
pdf_content = str(fd.read())
nr_of_obj = 0
nr_of_signatures = 0
signature_names = [] # 该场景下存储的是签署人邮箱
s_trailer = 'trailer'
s_startxref = 'startxref'

# 定位文档最后一个trailer块的起止位置,末尾偏移2是为了跳过trailer前后的换行符
last_trailer_start = pdf_content.rfind(s_trailer)+len(s_trailer)+2
last_trailer_end = pdf_content.rfind(s_startxref)-2

# 拼接提取trailer块内容
trailer = ""
for i in range(last_trailer_start, last_trailer_end):
    trailer += pdf_content[i]

# 拆分trailer属性,定位并读取Size字段值(即PDF总对象数)
trailer = trailer.split('/')
for attribute in trailer:
    if attribute.find('Size') >= 0:
        nr_of_obj = int(attribute.replace('Size','').strip())
        break

# 遍历所有对象,筛选Type为Sig的签名对象,提取Name字段
# 注意:不是所有编号对应的对象都存在,也不是所有对象都有Type属性,因此加try-catch兜底
for i in range(1, nr_of_obj):    
    try:
        raw_obj = doc.locate_object(i,0)
        obj = doc.build(raw_obj)
        if obj.Type == 'Sig':
            nr_of_signatures +=1
            signature_names.append(obj.Name)
    except:
        continue
print(nr_of_signatures)
print(signature_names)

内容的提问来源于stack exchange,提问作者Oskars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 21:03:40