资讯动态

批量文档敏感词扫描工具:八种格式文本提取与匹配实践

发布时间:2026/10/14 10:15:35 来源:尧图企业网站定制
1. 项目缘起与整体设计思路日常工作中文档流转几乎无处不在。合同、报表、汇报材料、会议纪要动辄几十上百个文件在部门之间来回传递。但凡涉及多人协作的场景就绕不开一个很现实的问题这些文件里有没有不该出现的内容比如客户信息、内部定价、人员名单、未公开的经营数据。靠人工一个个打开翻看效率低不说还容易漏。我所在的团队就遇到过这种情况——一次对外资料打包发出后才发现某份表格里藏着一列内部成本价场面相当尴尬。这个项目的目标很明确给定一批Office文件和PDF、纯文本文件自动把里面的文字提取出来再按照预设的敏感词规则做匹配最后输出一份“哪些文件、哪一处、命中了什么”的报告。支持的格式覆盖了日常最常见的八种doc、docx、xls、xlsx、ppt、pptx、pdf、txt。说白了它就是一个批量文档文本提取加敏感内容扫描的小工具。适合谁来参考我觉得三类人比较对口。第一类是行政、法务、合规岗位的同事需要定期做文件自查第二类是有一定编程基础、想自己搭一套内部检查流程的开发者第三类是对文档解析感兴趣、想了解不同格式底层结构的技术爱好者。哪怕你完全没写过代码只要跟着思路走也能理解每一步在干什么后面用现成脚本跑起来并不难。整体设计上我把它拆成了三个相对独立的环节文本提取层、规则匹配层、结果输出层。这样拆的好处是每一层都可以单独替换或升级。比如今天用关键词匹配明天想换成更复杂的规则引擎只需要动中间那一层提取层完全不用改。这种“管道式”的结构是我在做过几个类似需求后总结出来的比把所有逻辑揉在一个脚本里要稳得多。为什么强调“独立”因为文档解析本身坑就很多。不同格式的二进制结构差异巨大doc是老的复合文档格式docx/xlsx/pptx本质是zip压缩包里面装XMLpdf是排版描述语言txt最单纯。如果提取层和匹配层耦合在一起一旦某个格式解析出问题整个流程都会崩。分开之后某个文件解析失败最多是这一个文件跳过不影响其他文件继续扫描。还有一点设计上的取舍不做实时扫描只做批量离线处理。原因是实时扫描对性能要求高而且容易误伤正常编辑操作。批量处理可以在下班后跑或者手动触发对业务干扰最小。这个选择看起来保守但实际用下来最省心。2. 八种文件格式的文本提取核心细节2.1 doc与docx新旧两代格式的提取差异docx的处理相对友好因为它本质是一个zip包解压后能看到word/document.xml正文内容都在这个XML里。用Python的话python-docx这个库几行就能把段落文字读出来。但要注意它默认只读正文段落表格里的文字需要单独遍历document.tables页眉页脚也不在默认范围内。我踩过的坑是有一次扫描一份合同正文没命中敏感词结果敏感信息藏在页眉的公司内部编号里差点漏掉。后来我补了一段专门读页眉页脚的逻辑。doc就麻烦多了。它是微软早期的复合二进制格式没有现成的轻量库能完美解析。常见的做法有两种一是用antiword这类命令行工具转成文本二是调用LibreOffice的无头模式做格式转换。我实测下来antiword对纯文字段落效果不错但表格和文本框经常丢失。LibreOffice转换更完整但依赖环境较重启动也慢。如果doc文件量不大我倾向于用LibreOffice转成docx再走docx的流程这样表格、页眉都能保住。注意doc格式里如果嵌入了图片形式的文字任何文本提取方法都读不出来这种情况只能靠OCR但OCR不在本项目范围内需要单独处理。2.2 xls与xlsx单元格、公式与隐藏 sheet表格类文件的敏感信息往往藏在你想不到的地方。xlsx用openpyxl读取时默认读的是活动sheet但一个工作簿可能有多个sheet有些还被隐藏了。我见过有人把内部数据放在隐藏sheet里以为别人看不到结果扫描时如果只读活动sheet就漏了。所以我的做法是遍历所有sheet包括隐藏的。单元格的值也分几种情况。普通文本直接读cell.value就行但公式单元格读出来的是公式本身比如A1B1不是计算结果。如果你关心的是计算结果里有没有敏感数字需要用data_onlyTrue参数打开工作簿这样读到的是缓存的计算值。但要注意如果这个文件从来没被Excel打开过缓存值可能是None。这个细节很容易被忽略。xls是老格式xlrd库新版本已经不支持xls以外的格式了但读xls还是可以的。不过xlrd读xls时对公式的处理和xlsx不太一样需要单独测试。我的经验是xls文件如果不多统一转成xlsx再处理能省掉很多兼容性麻烦。2.3 ppt与pptx幻灯片、备注与母版PPT的文本分布在好几个地方幻灯片正文、演讲者备注、母版占位符。很多人只扫正文忽略了备注。实际上备注里经常写着“这页不要对外”“数据待确认”之类的话这些恰恰是敏感信号。pptx用python-pptx可以遍历slides每个slide里的shapes如果有text_frame就能读到文字。备注在slide.notes_slide.notes_text_frame里。母版里的文字一般不会太多但公司模板可能在母版里放了内部标识扫一下也无妨。ppt老格式同样建议转成pptx再处理理由和doc类似老格式的解析库支持太弱。2.4 pdf文本层与扫描件的分水岭PDF是最容易让人误判的格式。有些PDF是文字版用pdfplumber或PyPDF2能直接提取文字有些是扫描件本质是一堆图片文本提取出来是空的。我一开始没注意这个区别扫了一批扫描件结果显示“无敏感内容”实际上里面全是敏感信息只是没被读出来。判断方法很简单提取一页文字如果字符数极少比如少于20个基本可以判定是扫描件或图片型PDF。这种情况要么跳过并标记“需人工复核”要么接入OCR。我在项目里选择的是标记出来因为OCR的准确率和性能开销都需要额外评估不适合混在主流程里。另外PDF的文本提取顺序有时会乱。比如双栏排版的文档提取出来可能是左栏一行右栏一行交替出现。这对关键词匹配影响不大因为我们是按词匹配不是按句匹配但如果你的规则依赖上下文就要注意这个顺序问题。2.5 txt编码问题是最大的坑txt看起来最简单但编码问题能让人抓狂。GBK、UTF-8、UTF-8 with BOM、甚至GB2312不同来源的文件编码五花八门。直接按UTF-8读遇到GBK文件就报错或乱码。我的做法是用chardet先探测编码再按探测结果读取。但chardet也不是百分百准短文本尤其容易误判。所以我会加一层兜底如果按探测编码读出来包含大量替换字符\ufffd就换一种编码重试。还有一个细节有些txt是Windows下生成的换行符是\r\n有些是Unix的\n。这个对关键词匹配没影响但如果你的敏感词跨行就要先把换行统一处理掉。3. 敏感词匹配策略与实操过程3.1 规则设计从简单关键词到组合条件最基础的匹配就是关键词命中。比如维护一个敏感词列表逐个在提取出的文本里查找。但实际用起来纯关键词误报率不低。举个例子“价格”这个词本身不敏感但“成本价格”“内部价格”就敏感。如果只匹配“价格”会把所有正常讨论价格的文档都标出来。我的改进思路是分层规则。第一层是强敏感词命中即报警比如具体的项目代号、内部系统名称。第二层是弱敏感词加上下文比如“价格”单独出现不报但“价格”和“内部”在同一段出现就报。第三层是正则模式比如身份证号、手机号、银行卡号这类有固定格式的用正则匹配比关键词更准。规则文件我用的是JSON格式方便非技术人员修改。结构大概是每个规则有name、typekeyword/regex/combo、patterns、severity几个字段。这样行政同事也能自己加词不用找我改代码。3.2 匹配时的文本预处理提取出来的文本不能直接拿去匹配要先做几步清洗。第一步是统一大小写英文敏感词不区分大小写。第二步是去除多余空白因为PDF提取出来的文字经常带一堆空格和换行比如“内 部 价 格”这种直接匹配“内部价格”是匹配不上的。我的做法是把所有空白字符空格、制表符、换行先替换成单个空格再针对中文场景把空格去掉。但这里有个权衡去掉所有空格后“A B”和“AB”就分不清了。对于英文单词去掉空格会破坏词边界。所以我的策略是中文文本去掉空格英文文本保留空格但压缩连续空格。判断依据是文本中中文字符的占比超过一定阈值就按中文处理。第三步是分块。整篇文本做匹配命中后很难定位到具体位置。我会按段落切分每个段落单独匹配这样报告里能精确到“第几段命中”。对于表格按单元格切分对于PPT按幻灯片和形状切分。3.3 完整实操流程与参数说明整个流程我用Python串起来核心步骤如下。第一步遍历输入目录按扩展名分类文件。第二步对每个文件调用对应的提取函数拿到一个“文本块列表”每个块带有位置信息比如“sheet1!A3”或“slide2”。第三步对每个文本块跑规则匹配记录命中的规则名、命中位置、命中片段。第四步汇总结果输出成CSV和HTML两种格式。参数方面有几个关键点。并发数我用的是concurrent.futures的线程池默认4个线程。为什么不是越多越好因为文档解析是IO密集和CPU密集混合的操作线程太多反而会因为GIL和磁盘争抢导致整体变慢。实测4到8个线程比较合适具体看机器配置。单文件超时设了30秒。有些损坏的PDF或超大的xlsx会卡住没有超时机制整个流程就挂在那里了。超时后标记该文件为“解析失败”继续处理下一个。输出报告里我保留了几个字段文件名、文件路径、命中规则、命中位置、命中片段前后各截20个字符、严重级别。这样复核的人一眼就能看到问题在哪不用再打开原文件找。# 文本块结构示例 text_blocks [ {location: sheet1!A3, text: 内部成本价120元}, {location: slide2, text: 本页数据请勿外传}, ]提示命中片段截取时如果敏感词在文本开头或结尾要注意边界处理避免切片越界报错。这个bug我写过两次都是因为没判断索引范围。4. 常见问题排查与避坑经验实录4.1 解析失败与乱码问题速查实际跑起来解析失败是家常便饭。我整理了一个速查表覆盖了大部分情况。问题现象可能原因排查方法解决方式docx读取报错文件损坏或非标准docx用zip工具尝试解压标记失败跳过xlsx公式读不到值未用data_only打开检查cell.value类型改用data_onlyTruepdf提取为空扫描件或图片型PDF统计提取字符数标记需人工复核txt乱码编码判断错误查看替换字符数量换编码重试pptx备注读不到备注页不存在检查notes_slide属性加空值判断文件名含特殊字符路径编码问题打印文件路径统一用UTF-8处理路径乱码问题我再补充一个经验如果一批文件来自同一个来源编码往往是一致的。可以先拿几个文件试读确定编码后再批量处理比每个文件都探测一遍要快。4.2 性能优化与误报处理性能上最大的瓶颈是PDF解析和LibreOffice转换。PDF解析慢是因为要逐页渲染文本层大文件尤其明显。我的优化是先用文件大小做粗筛超过50MB的PDF单独排队处理避免拖慢小文件。LibreOffice转换则是启动一次进程很慢但可以批量转换把多个doc一次性转完再退出比一个个转快好几倍。误报处理是另一个大头。刚开始跑的时候报告里一堆“疑似敏感”复核的人看几页就不想看了。后来我做了两件事一是给规则加白名单比如“价格”在“价格表模板”这个固定短语里出现就不报二是按严重级别排序强敏感词排最前面弱敏感词放后面复核的人可以先看高优先级的。还有一个容易被忽略的点敏感词本身也要做变体处理。比如“内部”可能被写成“内 部”“内-部”“內 部”繁体。如果规则里只写“内部”这些变体就漏了。我的做法是在规则里支持简单的变体展开把常见分隔符和繁体写法都考虑进去。这个工作量不大但效果立竿见影。4.3 实操心得与独家建议最后分享几条我踩坑踩出来的经验。第一条先小批量试跑再全量。我一开始图快直接拿几千个文件跑结果规则没调好报告出来全是误报白跑一趟。后来改成先拿20个文件试规则调准了再放大省了很多时间。第二条保留原始提取文本。有时候报告里显示命中了但复核的人想看看上下文如果每次都重新解析文件就很慢。我会把提取出的文本按文件存一份到临时目录方便复查。当然这些临时文件本身也可能含敏感信息用完要及时清理或者加密存储。第三条规则要版本化。敏感词列表不是一成不变的今天加几个明天删几个如果没有版本记录出了问题很难追溯是哪版规则导致的。我用git管理规则文件每次修改都提交这样随时能回滚。第四条不要追求100%自动化。文档格式千奇百怪总会有解析不了的情况。与其花大量时间处理边缘case不如把解析失败的清单列出来让人工去处理。自动化解决80%的常规文件剩下20%人工兜底整体效率已经比纯人工高太多了。这个项目后续还可以扩展的方向不少比如接入OCR处理扫描件、把规则引擎换成支持逻辑表达式的、或者做一个简单的Web界面让非技术人员上传文件自助扫描。不过那是后话了当前这套流程跑下来日常的文件自查已经够用了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑