【免费AI文档助手开发实战系列】基于正则表达式的PDF脱敏python服务构建(一)

需求

人们在日常分发PDF过程中,需要把银行卡号、姓名、电话等敏感信息进行脱敏,方便分发。

架构设计

技术架构

技术架构分为三层:

界面层:用户可见的,采用vue2进行搭建。

后端服务:使用python3进行搭建,利用python的优势在于可以少代码,利用现成丰富的组件库,去处理PDF,PyMuPDF组件等,另外本身python也支持web应用的开发。

持久层:选择sqlite是因为它轻量,方便进行工具类的应用开发,业务处理比较少,方便快速的出效果。

业务架构

业务架构主要从业务流程、功能角度进行分析,用户侧提供功能,上传PDF,可选择脱敏对象(比如身份证号、邮箱、电话等),脱敏后的结果文件下载。

后台提供脱敏接口处理服务。

核心python代码

后台接口入口代码:

读取文件,然后传递给desensitize_pdf_stream方法进行处理

python 复制代码
@app.post("/desensitize-pdf/")
async def handle_desensitization(file: UploadFile = File(...), rules: List[str] = Form(...), user_email: str = Form(...)):
    if file.content_type != "application/pdf": raise HTTPException(status_code=400, detail="Invalid file type.")
    if not rules: raise HTTPException(status_code=400, detail="No redaction rules selected.")
    pdf_contents = await file.read()
    processed_pdf_stream = desensitize_pdf_stream(pdf_contents, rules)
    log_tool_usage("desensitize", user_email)
    return StreamingResponse(processed_pdf_stream, media_type="application/pdf", headers={"Content-Disposition": f"attachment; filename=desensitized_{file.filename}"})

核心功能

desensitize_pdf_stream 函数接收PDF数据的字节流和一组脱敏规则 (active_rules)。它打开PDF文件,遍历每一页,并调用 redact_precise_page 函数进行处理。所有页面处理完毕后,它将修改后的PDF保存到一个字节缓冲区并返回。

脱敏工作原理

redact_precise_page 函数负责对单页进行具体的脱敏操作:

  1. 提取文本和位置: 它首先从页面中提取所有文本字符及其边界框(位置信息)。

  2. 识别敏感数据 : 它使用预定义的 SENSITIVE_PATTERNS_MAP,在页面文本中查找特定模式(如电话号码、电子邮件和身份证号)。

  3. 遮盖与替换: 对于每一个找到的匹配项:

    • 它确定敏感文本在页面上的精确矩形区域。

    • 它在这个区域上绘制一个白色矩形来遮盖原始文本。

    • 它对匹配到的文本应用一个替换函数 (repl_func) 进行处理(例如,12345678901 变为 123****78901)。

    • 最后,它将这个已脱敏的新文本以相同的字体和大小,重新插入到被遮盖的位置。

python 复制代码
SENSITIVE_PATTERNS_MAP = {
    "phone": (re.compile(r'(?<!\d)1\d{10}(?!\d)'), lambda m: m.group(0)[:3] + '****' + m.group(0)[-4:]),
    "email": (re.compile(r'\b([a-zA-Z0-9])[a-zA-Z0-9._%+-]*([a-zA-Z0-9])@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b'), lambda m: m.group(1) + '**' + m.group(2) + m.group(0)[m.group(0).find('@'):]),
    "id_card": (re.compile(r'\b\d{6}(\d{8})\d{4}\b'), lambda m: m.group(0).replace(m.group(1), '********')),
}

def redact_precise_page(page: fitz.Page, active_rules: List[str]):
    chars = get_char_positions(page)
    if not chars: return
    full_text = ''.join([ch["c"] for ch in chars])
    patterns_to_apply = {key: SENSITIVE_PATTERNS_MAP[key] for key in active_rules if key in SENSITIVE_PATTERNS_MAP}
    for pattern, repl_func in patterns_to_apply.values():
        for match in pattern.finditer(full_text):
            start, end = match.start(), match.end()
            matched_chars = chars[start:end]
            if not matched_chars: continue
            x0, y0, x1, y1 = min(c["bbox"][0] for c in matched_chars), min(c["bbox"][1] for c in matched_chars), max(c["bbox"][2] for c in matched_chars), max(c["bbox"][3] for c in matched_chars)
            rect = fitz.Rect(x0, y0, x1, y1)
            page.draw_rect(rect, color=(1, 1, 1), fill=(1, 1, 1), overlay=True)
            masked_text = repl_func(match)
            fontname = map_pdf_font_to_builtin(matched_chars[0]["font"])
            fontsize = matched_chars[0]["size"]
            insert_point = fitz.Point(rect.x0, rect.y1 - 1)
            page.insert_text(insert_point, masked_text, fontname=fontname, fontsize=fontsize, color=(0, 0, 0))

def desensitize_pdf_stream(pdf_bytes: bytes, active_rules: List[str]) -> io.BytesIO:
    doc = fitz.open(stream=pdf_bytes, filetype="pdf")
    for page in doc:
        redact_precise_page(page, active_rules)
    output_buffer = io.BytesIO()
    doc.save(output_buffer)
    doc.close()
    output_buffer.seek(0)
    return output_buffer

后端服务我采用fastapi进行发布。

前端代码利用AI构建,非常nice,比自己写,快准狠。

最后出来的效果:试用地址,网站上线了注册等其他功能,后续再说,当前功能免费使用,有任何好的文档工具创意,可以评论区留言,我来评估实现,并把设计、代码共享,并进行过工具上线。

相关推荐
数据智能老司机1 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机2 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
c8i3 小时前
django中的FBV 和 CBV
python·django
c8i3 小时前
python中的闭包和装饰器
python
这里有鱼汤7 小时前
小白必看:QMT里的miniQMT入门教程
后端·python
TF男孩17 小时前
ARQ:一款低成本的消息队列,实现每秒万级吞吐
后端·python·消息队列
该用户已不存在1 天前
Mojo vs Python vs Rust: 2025年搞AI,该学哪个?
后端·python·rust
站大爷IP1 天前
Java调用Python的5种实用方案:从简单到进阶的全场景解析
python
用户8356290780511 天前
从手动编辑到代码生成:Python 助你高效创建 Word 文档
后端·python
c8i1 天前
python中类的基本结构、特殊属性于MRO理解
python