【免费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,比自己写,快准狠。

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

相关推荐
傻啦嘿哟4 分钟前
王者荣耀爬虫:爬取全英雄皮肤数据,用Python做可视化分析
开发语言·爬虫·python
徒慕风流13 分钟前
激光雷达回波信号滤波与时刻鉴别算法:原理、代码实现与仿真验证
python·算法·激光雷达
菜冻鱼17 分钟前
Python-pytorch-数据加载
开发语言·人工智能·pytorch·python·深度学习·机器学习
you鬰19 分钟前
datawhale--llm-algo-leetcod1️⃣
python·datawhale
南京云森杉木桩1 小时前
水利木桩源头直供,质量可靠价格更优
大数据·python
Aaron - Wistron1 小时前
Python基础教程2/4(复合数据结构)
python
小柯南敲键盘1 小时前
跨境电商图片翻译与视频字幕翻译工具推荐
python·音视频
ZC跨境爬虫1 小时前
LeetCode 13. 罗马数字转整数(多解法详解 + Java Python 实现)
java·python·leetcode
machnerrn2 小时前
智慧交通系列(一)-十字路口车辆闯红灯检测告警抓拍系统(附含数据+源码+模型)
人工智能·python·深度学习
现代野蛮人2 小时前
【深度学习实验】—— 利用 RNN 模型进行心脏病预测
pytorch·python·tensorflow·ml