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

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

相关推荐
WSSWWWSSW23 分钟前
Seaborn数据可视化实战:Seaborn时间序列可视化入门
python·信息可视化·数据分析·matplotlib·seaborn
云天徽上1 小时前
【数据可视化-96】使用 Pyecharts 绘制主题河流图(ThemeRiver):步骤与数据组织形式
开发语言·python·信息可视化·数据分析·pyecharts
codeyanwu1 小时前
nanoGPT 部署
python·深度学习·机器学习
quaer2 小时前
print(2 ** 3)
开发语言·python
翔云1234563 小时前
Python 中 SQLAlchemy 和 MySQLdb 的关系
数据库·python·mysql
三婶儿3 小时前
在没有客户端的客户环境下,如何用 Python 一键执行 MySQL 与达梦数据库 SQL
运维·后端·python
Freak嵌入式4 小时前
一文速通 Python 并行计算:教程总结
开发语言·python
hweiyu004 小时前
Python办公之Excel(openpyxl)、PPT(python-pptx)、Word(python-docx)
python·powerpoint·excel
waynaqua5 小时前
FastAPI开发AI应用五:模型新增图片理解
python·openai·fastapi