夜雨聆风学习资料网

ARTICLE · 1331509

你删光了正文里的公司名,Word文档属性还在替你署名

你删光了正文里的公司名,Word文档属性还在替你署名

招标文件里有一句话,不少投标人第一次见都当耳边风:“投标文件出现投标人名称或者其他可以识别投标人的标记的,按无效投标处理。”

暗标评审,一个名字都不许有。多数人的应对是把落款删掉、封面换掉,再从头到尾通读一遍确认没有公司名。这些动作都对,但不够——Word会在你看不见的地方替你署名。这个脚本的由来就是一次险情:交付前做自检,正文已经逐段确认干净,抱着试试的心态右键看了眼文件属性,作者栏里躺着一个真名。从那以后,交暗标前用脚本搜身成了固定动作。

名字都藏在哪:三处重灾区

第一处,文档属性。右键文件打开“详细信息”,作者、修改者两个字段就躺在那里。公司电脑装Office时通常默认写入员工姓名,你在工位上写的每一稿,属性里都带着真名。删正文救不了它,属性跟着文件走,转成PDF都未必清得掉——很多PDF导出选项会把Word里的作者字段原样带过去。

第二处,页眉页脚。正文改得再干净,页眉里挂着的公司名、页脚里留的邮箱,你多半一页没动过。整理稿子的人十个有九个只看正文,评审专家翻文件可不管哪一页是你看漏的。

第三处,表格和路径。联系人塞在表格里:“张工 13812345678”。正文里交代交付路径:“存档于C:\Users\zhangsan\Documents\final\”——zhangsan就是张三的拼音。这类痕迹不叫公司名,却一样能识别出人。

把后果说透:暗标废标不是风格问题,是硬条款。评标委员会认定出现可识别标记,直接按无效投标处理,没有申辩空间。前期与甲方的技术沟通、方案里熬的夜、团队报的价,全跟着这一处痕迹作废。更麻烦的是暗标往往一式多份、涉及多个章节文件,一处漏了处处漏,靠眼睛逐段找,找到的永远只是你恰好看见的那些。

交给脚本:一次搜身,四类规则

我把这几年的自查动作写成了一个脚本dark_bid_scan.py,交给AI和正则去干重复劳动。它做四件事:

▸用四条规则扫全文:手机号、邮箱、统一社会信用代码、Windows本地路径。手机号是11位1开头的数字,邮箱是通用格式,统一社会信用代码按18位编码规则写正则——营业执照号塞在表格里,一样是身份痕迹;本地路径专抓C盘用户目录,路径里的用户名往往就是你的拼音;

▸按你给的姓名、公司名等关键词逐处比对,关键词可以叠多次,公司简称、曾用名都能加进来;

▸检查Word文档属性里的author、last_modified_by、title、subject、comments、category六个字段。别小看title和comments,很多人在文件属性备注里写“XX公司专用版”,一样露;

▸覆盖范围包括正文、表格、页眉、页脚——正是上面三处重灾区。

这四类只是最常踩的痕迹。凡是能识别出投标人的标记——座机号、QQ、微信、项目编号里嵌的缩写、图片里的水印——都一样按废标风险处理。脚本是筛子,不是保单。

检查结果分两档:命中和人工确认。属性字段非空但不含你给的关键词时,脚本既不放过也不冤枉,标成“人工确认”留给人判断。退出码0是干净、2是命中,可以直接接进批处理当闸门。

实跑记录

先造一份埋雷演示件,把公司名、姓名、手机号、邮箱、本地路径、文档属性author全部埋进去,再跑脚本:

=== 暗标匿名自检报告 === 文件:演示_埋雷版.docx [命中] 正文|公司关键词|华信工程咨询有限公司 [命中] 正文|本地路径泄漏|C:\Users\zhangsan\Documents\final\ [命中] 表格|手机号|13812345678 [命中] 表格|姓名关键词|张工 [命中] 页眉(节1)|公司关键词|华信工程咨询有限公司 [命中] 页脚(节1)|邮箱|zhanggong@huaxin-consult.com [命中] 文档属性|author|张工(含关键词“张工”) [命中] 文档属性|comments|张工 2026-10-20 修改(含关键词“张工”) [提醒·人工确认] 文档属性|last_modified_by|李四(华信) [提醒·人工确认] 文档属性|title|XX项目实施方案 结论:8处命中,未过匿名自检(退出码2)

8处命中、2条提醒:正文和页眉的公司名、表格里的手机号和姓名、正文里的本地路径、页脚的邮箱、属性里的author和comments,全部被抓出来;last_modified_by“李四(华信)”不含完整公司名,脚本没硬判,标了人工确认。

再跑一份属性清干净的对照件,结论未命中,退出码0——它能确认干净,不是只会喊狼来了。

脚本管不到的地方

docx文本层之外还有四路要人守:

▸文件名。“XX公司技术方案.docx”这种名字,交上去就是明牌。文件名检查一行shell就够:ls *.docx | grep 公司名;

▸PDF层。定稿转PDF后要拿PDF文本再抽一遍,再右键看一次PDF属性,作者字段有没有跟过去;

▸图片。扫描章、截图水印、组织架构图里的公司名,脚本不读图,靠人在合成前过目。

▸文本框和艺术字。“投标专用”、“内部资料”这类字,标书里常放在文本框和艺术字里,脚本扫不到这一层,合成前人工过目。

四路都过,才算真干净。

你怎么用

安装依赖后一行命令:

pip install python-docx python dark_bid_scan.py 标书.docx --name 张三 --company 某某实业 --more 13800138000

整个标书拆成几十份章节docx的,用循环一次扫完:

for f in *.docx; do python dark_bid_scan.py "$f" --name 张三 --company 某某实业; done

退出码2的文件留下来改,改完重跑,全部退出码0再合成PDF。放进交标流程就是三步:改完稿跑一遍脚本、按报告逐处清理、全绿之后转PDF再走一遍文件名和PDF属性检查。半小时的自检,换掉的是整个项目组半个月白干的概率。

还有一个反向用法:跟别人合作联营投标、或者拿到第三方做过一半的文件时,先跑一遍搜身再签合同——对方文档属性里藏着谁、路径里写着谁,一眼看穿,免得文件本身先替人泄了底。

三点限度说清楚:一,脚本只扫docx文本层,最终交的PDF版本要拿PDF文本再跑一路;二,关键词要喂全——公司简称、曾用名、英文注册名、项目组花名,都算可识别标记;三,它替代不了人收尾那遍通读,评审席上没有脚本的位置,它只是把你从靠眼睛找针里捞出来。

暗标查的不是你写没写名字,是Word替不替你写。删得掉的是正文,删不掉的是习惯——把这次搜身变成交标前的固定动作,名字才算真正删干净。

附:完整脚本

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """暗标匿名自检:扫出Word里藏着的公司名、姓名、联系方式和本地路径。  用法:     python dark_bid_scan.py 标书.docx --name 张三 --company 某某实业 --more 13800138000  退出码:0=未命中,2=有命中(可直接接进批处理做闸门) 依赖:pip install python-docx """ import argparse import re import sys  from docx import Document  RE_PHONE = re.compile(r'(?<!\d)1[3-9]\d{9}(?!\d)') RE_EMAIL = re.compile(r'[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}') RE_USCC = re.compile(r'(?<![0-9A-Z])[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}(?![0-9A-Z])') RE_PATH = re.compile(r'[A-Z]:\\(?:Users|Documents and Settings)\\[^\s,。;、"”]*') DOCX_PROPS = ('author', 'last_modified_by', 'title', 'subject', 'comments', 'category')   def iter_texts(doc):     """按位置逐段产出(位置标签, 文本):正文、表格、页眉、页脚。"""     for p in doc.paragraphs:         if p.text.strip():             yield '正文', p.text     for t in doc.tables:         for row in t.rows:             for cell in row.cells:                 if cell.text.strip():                     yield '表格', cell.text     for i, sec in enumerate(doc.sections, 1):         for label, part in (('页眉', sec.header), ('页脚', sec.footer)):             for p in part.paragraphs:                 if p.text.strip():                     yield f'{label}(节{i})', p.text             for t in part.tables:                 for row in t.rows:                     for cell in row.cells:                         if cell.text.strip():                             yield f'{label}(节{i})表格', cell.text   def main():     ap = argparse.ArgumentParser(description='暗标匿名自检')     ap.add_argument('docx', help='要检查的Word文件')     ap.add_argument('--name', action='append', default=[], help='编写人姓名,可多次')     ap.add_argument('--company', action='append', default=[], help='公司名关键词,可多次')     ap.add_argument('--more', action='append', default=[], help='其他自定义关键词,可多次')     args = ap.parse_args()      doc = Document(args.docx)     rules = [         ('手机号', RE_PHONE),         ('邮箱', RE_EMAIL),         ('统一社会信用代码', RE_USCC),         ('本地路径泄漏', RE_PATH),     ]     keywords = ([('公司关键词', c) for c in args.company]                 + [('姓名关键词', n) for n in args.name]                 + [('自定义关键词', m) for m in args.more])     rules += [(label, re.compile(re.escape(v))) for label, v in keywords]      hits, warns = [], []     for where, text in iter_texts(doc):         for rule_name, rex in rules:             for m in rex.finditer(text):                 hits.append((where, rule_name, m.group(0)))      core = doc.core_properties     name_set = set(args.name) | set(args.company) | set(args.more)     for field in DOCX_PROPS:         val = str(getattr(core, field, '') or '').strip()         if not val:             continue         kw = next((k for k in name_set if k in val), None)         if kw:             hits.append(('文档属性', field, f'{val}(含关键词“{kw}”)'))         else:             warns.append(('文档属性', field, val))      print('=== 暗标匿名自检报告 ===')     print(f'文件:{args.docx}')     for where, rule_name, snippet in hits:         print(f'[命中] {where}|{rule_name}|{snippet[:40]}')     for where, field, val in warns:         print(f'[提醒·人工确认] {where}|{field}|{val[:40]}')     if hits:         print(f'结论:{len(hits)}处命中,未过匿名自检(退出码2)')         sys.exit(2)     print('结论:未命中(退出码0)')   if __name__ == '__main__':     main()

把你的姓名和公司名换进去就能跑。唯一依赖python-docx,pip装完即用。

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料