分包商准入资料一键生成
用户只需提供公司名称(营业执照全称),产出 4 份文件:填好且无标黄的考察记录表(附件1)、合规风险审批表(附件2)、资质复查截图(附件3式样)、安全生产许可证复查截图(附件4式样)。
第一步:确认输入并解码模板
- 确认公司全称。若用户只给简称,先联网检索列出候选企业(名称+属地+统一社会信用代码)请用户确认,不得自行假设。
- 若工作目录已有同名附件(附件1~4),优先使用用户目录中的版本;否则用内置模板:
python <技能目录>/scripts/fill_docs.py decode --b64dir <技能目录>/references/templates_b64 --out <工作目录>/tpl
<技能目录>即本 SKILL.md 所在目录。脚本仅用 Python 标准库,本机任意 Python 3.8+ 均可(Windows 下优先用 managed python 绝对路径)。- 解码产物固定为 4 个简单文件名:
tpl/att1.docx(附件1 考察记录表,已从 .doc 转换)、tpl/att2.docx(附件2 审批表)、tpl/att3.png(资质复查式样)、tpl/att4.png(安许复查式样)。 - 若用户目录已有同名附件(附件1~4),优先使用用户目录中的版本;此时附件1若为 .doc,先用 Word/WPS COM 转换为 .docx(PowerShell:
$doc.SaveAs([ref]<目标.docx>, [ref]16),目标目录必须已存在,否则 SaveAs 静默失败)。
第二步:联网检索企业信息
检索并交叉验证以下字段,来源优先级:国家企业信用信息公示系统 > 全国建筑市场监管公共服务平台 > 企查查/爱企查等:
| 字段 | 说明 |
|---|---|
| 统一社会信用代码 | 必查 |
| 法定代表人或授权委托人 | 必查 |
| 联系电话 | 公开渠道常缺失,查不到填"待补充" |
| 企业资质 | 类别+等级+证书号+有效期(来自 jzsc 平台详情页) |
| 注册资本金 | 必查 |
| 企业地址 | 注册地址或经营地址 |
| 分包商近三年业绩 | 公开渠道常缺失,填"待补充"并提示用户提供 |
严禁编造。查不到的一律填"待补充"并在交付时列明。
第三步:官方平台复查并截图
> 🔥 首选数据源:天津住建委公共服务平台 szzj.zfcxjs.tj.gov.cn:31293(2026-09-20 新增,验证码已可全自动通过)
>
> 只要企业在天津注册(或需查其天津资质),优先走这条:一条命令、无窗口、无人工拖滑块、字段比 jzsc 更全。
>
> bash
> # 先起一个 headless Chrome(常驻,供 CDP 连接)
> bash scripts/bo_chrome_up.sh <root> 9225
> # 一条命令跑完:搜索 → 自动过滑块 → 进详情 → 翻页 → 拼完整长图
> TJ_CDP=http://127.0.0.1:9225 node scripts/tj_qual_shot.mjs "<公司全称>" <outdir>
>
>
> 产出:<outdir>/<公司名>-资质核验详情_完整.png(推荐交付,含企业信息卡片 + 表头 + 全部资质行)、<公司名>-列表.png、_tj_all_<公司名>.json。
>
> 为何能全自动:该站是自研 verifition 拼图滑块(非极验),无客户端风控自检,且 /captcha/get 每次返回全新 token + 新图,可无限重试不消耗成本。实测连跑 15 次 100% 通过,平均 1.4 轮/次,单次约 0.5 秒。
> 关键实现(已封装在 scripts/tj_slider.mjs):
> - 缺口定位用 SAD 暴力搜索(滑块图 alpha>200 像素作模板,滑窗求平均绝对差),比 NCC/白色轮廓法稳(白色轮廓会被图上的拼图形装饰物误导)。
> - 置信门控:gapY==0 且 局部锐度≥1.3 且 次优比≥1.15 → 才提交;否则丢弃换新图(不浪费 token)。此法把通过率从 75% 提到 100%。
> - 位移直接提交 x = 缺口像素 offset,不做换算。
> - pointJson = AES-128-ECB/PKCS7,key = UTF8(secretKey) → base64,明文 {"x":<num>,"y":5}。
> - 通关后必须再调页面真实 Vue 组件回调 comp.captacha({res})(该组件 $options.name==='ViewBsdtQyJbxxList',同时具备 captacha 与 loadData2 方法),否则业务请求仍报"验证过期,请重新验证"。tj_qual_shot.mjs 已内置。
>
> ⚠️ 两个已踩的坑:① 本页截图只能用 fullPage:true,clip 模式会卡在 waiting for fonts to load(该页字体永不加载完);② 不要用 CDP Page.captureScreenshot(会触发宿主 SIGTERM 杀进程)。
若需走住建部 jzsc / zlaq 通道,用「全后台无人值守」一条命令:
bash scripts/bo_auto.sh "<公司全称>" <workdir> <outdir>
# 输出标记:
# BO_AUTO_ZLAQ {...} zlaq 安许截图是否产出
# BO_AUTO_RESULT ok ... 两张截图都成功
# BO_AUTO_RESULT needsManual ... jzsc 被极验风控自检拦截,只出了安许截图
# BO_AUTO_RESULT error ... 其他失败
# 失败时会写 <workdir>/NEED_MANUAL_CAPTCHA.txt 说明待补项(不弹窗、不卡住)
bo_auto.sh 自动起两个 headless Chrome、跑完 zlaq + jzsc、最后自动收掉 Chrome。jzsc 若被客户端风控拦住(headless 下无解),它立即降级标记而不会重试或挂住,绝不影响用户。
需要抓取 jzsc 资质截图(需人工过一次滑块)时才用下面的有窗口流程:
# 1) 后台起常驻 Chrome(每平台一个端口)
bash scripts/bo_chrome_up.sh <root> 9222 9223
# 2) 一条命令并行跑完两平台阶段一(zlaq 全自动 ∥ jzsc 搜索→进详情页)
bash scripts/bo_company.sh "<公司全称>" <workdir> <outdir> 9222 9223
# 3) jzsc 详情页弹滑块拼图 → 跑滑块脚本(脚本内自动拖;被风控拦则转人工兜底)
export CDP_PORT=9223
node scripts/jzsc_slide.mjs "<outdir>/<公司名>-资质复查截图.png" "<公司全称>" <workdir>
# 脚本会打印每轮结果;若出现 riskControl:"client-side-abort" → 转人工兜底(见常见问题)
> 验证码类型:jzsc 现行为滑块拼图(geetest_panelshowslide),走上面第 3 步。
> 若将来回退成点选/空间推理旧题型,才用旧通道:bo_captcha.py 生成 compare.png → 读图写 order.json → bash scripts/bo.sh jzsc-solve。
> bo.sh jzsc-open 现已能自动识别类型并提示该走哪条路。
多家公司:bash scripts/bo_batch.sh <workroot> <outroot> <公司清单文件>(每家公司占 2 个端口,并发跑阶段一)。
绝不要用 agent-browser:它的守护进程在本宿主起不来、open 会无限挂住并拖死 shell(实测连废 3 次、累计 12 分钟)。也不要装 Python 版 playwright(pip install 会卡数分钟),只需 npm i playwright-core。
两张截图的要求:
- 资质复查(附件3式样):访问全国建筑市场监管公共服务平台
https://jzsc.mohurd.gov.cn→ 搜索公司名称 → 进入企业详情页(形如/data/company/detail?id=...,拿到直链后可直接访问),截图须包含:企业基本信息(统一社会信用代码、法定代表人、注册类型、注册属地、经营地址)+ "企业资质资格"页签的资质列表。详情页大概率弹 GeeTest 点选/空间推理验证码,按 playbook 流程处理。 - 安全生产许可证复查(附件4式样):访问全国工程质量安全监管信息平台公共服务门户(现行域名
https://zlaq.mohurd.gov.cn,2026-09 实测;旧域名 zapp.mohurd.gov.cn 已失效)→ "施工安全"下"安全生产许可证信息"查询页 → 输入公司名称查询,截图须包含查询结果列表(企业名称、信用代码、法定代表人、许可证编号、证书状态、发证机关、有效期结束日期)。 - 取证铁律:zlaq 平台列表为混淆字体,取证以页面渲染截图为准,严禁从 DOM 抄数据;编号列被截断时按 playbook 方法处理后再截;查询结果为空也要截图(可作无证证据)。禁止用第三方聚合网站截图替代。
第四步:填写文档并取消标黄
- 把检索结果写入
fields.json(键名必须与下表完全一致,缺省项填"待补充"):
{
"分包商名称": "公司全称",
"统一社会信用代码": "", "法定代表人或授权委托人": "", "联系电话": "",
"企业资质": "", "注册资本金": "", "企业地址": "", "分包商近三年业绩": ""
}
- 执行填写(自动写入标黄单元格、去除全部高亮,附件2 自动填写"第三方名称:"):
python <技能目录>/scripts/fill_docs.py fill \
--att1 <工作目录>/tpl/att1.docx --att2 <工作目录>/tpl/att2.docx \
--company "公司全称" --fields <工作目录>/fields.json --outdir <工作目录>/output
- 校验输出:脚本会打印"残留高亮"数与未定位标签警告,必须确认为 0;如报标签未定位,用
verify子命令复查并人工处理。
第五步:核验与交付
- 按
{公司名}-分包商考察记录表.docx、{公司名}-第三方合规风险等级列表及审批表.docx、{公司名}-资质复查截图.png、{公司名}-安全生产许可证复查截图.png命名,逐一交付。 - 附信息汇总表(字段/取值/来源渠道)与存疑待补事项。
- 红线:模板原件不得修改;附件2 中除"第三方名称"外的风险勾选(☑/□)与审批签署栏一律保持原样,严禁代勾选、代签。
常见问题
- 附件1 标签未定位:多为用户使用了不同版本的模板,改用用户目录附件并先转 .docx。
- 官方平台打不开/验证码过不去:按 anti-bot-playbook.md 处理(域名迁移、验证码流程、混淆字体取证均有现成方案);仍失败则截图失败说明,并将资质字段标注"待补充",交付时说明原因。
- agent-browser 用不了:不要在它身上重试,直接走 playbook 第〇节的流水线。
- jzsc 重开详情页必须传公司名,不能传直链(2026-09 实测):
bo.sh jzsc-open只接受公司名称——传详情直链会被塞进搜索参数(complexname=<url>)而报"未拿到企业详情页"。重试时传公司名重新走搜索流程。 - 单独调
bo.sh jzsc-open不会生成 compare.png(仅点选/空间推理旧题型适用):只有bo_company.sh会串 bo_captcha.py;单独重开验证码后需手动跑python <技能目录>/scripts/bo_captcha.py <workdir>(需 numpy/cv2/PIL,用托管 venvenvs/default的 python),再读图写 order.json。滑块题型不涉及此步。 - jzsc 判据误判:不能用
innerText 含"统一社会信用代码"判成功——标签是静态的,值才是证据。要用「标签后 60 字内出现 18 位代码 + 验证码元素已消失」。 - jzsc 截图超时:不要
fullPage,用clip截可见区。 - jzsc 点错位置(点选/空间推理旧题型):多为坐标换算错了。
background-size:100% auto时元素只显示原图顶部方形区,必须按「可见区」算,两轴用同一个比例k = box宽/图宽。 - jzsc 截图 clip 越界:命中了残留旧标签页(视口可能 292×98)。每次 open 结束要清掉列表页与历史详情页,solve 时取最后一个详情页。
- 空间推理题漏检目标(旧题型):被遮挡物体只剩窄边,分割时不要用 MorphOpen;漏了就照 compare.png 上的坐标网格用
{"points":[[x,y]]}兜底。 - zlaq 编号/发证机关列被截断:改
colgroup的col宽度无效(列数错位 +width属性压缩),必须colgroup.remove()后按nth-child定列宽;末列被裁是白色卡片容器不够宽,需把祖先容器放大到 ~1420px。 - zlaq 搜索框填不进去:可见的是
input.keyword-ipt,#qymc不可见会让fill超时。 - xlsx/docx 输出:
fill_docs.py verify的「残留高亮数」必须为 0。 - 同名企业:必须请用户按属地或信用代码确认后再填写。
- jzsc 验证码已换成滑块拼图(2026-09-16 实测):详情页弹的是
geetest_panelshowslide(拼图对位),不再有点选题的.geetest_item_wrap,老流程报"未抓到验证码元素"。改跑CDP_PORT=9223 node scripts/jzsc_slide.mjs "<输出png>" "<公司全称>" "<workdir>"(流程=开详情页→重新验证→canvas 差分测孔位→人手轨迹拖一发→判据→截图+提取资质数据)。bo.sh jzsc-open已能识别滑块类型并返回needsSlide:true,不再抛误导性的"未抓到验证码元素"。 - 滑块被拒先看接口原因,别瞎重试:监听
api.geevisit.com/ajax.php响应。error_12 / "尝试过多"= 触发频控,冷却约 10 分钟后每 5 分钟只拖一发;连续快速重试(8 秒一次连拖 20 发)会把配额烧光,之后怎么拖都必拒。被拒后拼图块停在松手位置(不自动复位),重开标签页才有新挑战。 error:113 / "网络不给力" / 接口返回 forbidden≠ 频控,是风控硬拦(2026-09-20 实测,重要):判据是这一发根本没发出 POST——监听geevisit的 POST 计数为 0(jzsc_slide.mjs会打印riskControl:"client-side-abort")。极验在滑块自检阶段就判定环境可疑(headless、自动化特征、非常规轨迹)而静默中止,这与error_12的服务端频控完全不是一回事。重试、冷却、换端口、换新 profile 全都无效(实测已试遍:headless/headed、--disable-blink-features=AutomationControlled、launchPersistentContext、CDPPage.addScriptToEvaluateOnNewDocument注入navigator.webdriver=false(已验证生效)、页内合成 PointerEvent/MouseEvent(被isTrusted挡掉))。脚本内自动过滑块在此环境下不可靠,别再投入算力硬刚——直接走人工兜底(见下条)。- 人工兜底(滑块风控唯一可靠解法):跟用户说明"官方平台验证码需人工过一次",让用户在已打开的常驻 Chrome 窗口里手动拖动滑块;用户确认通过后,脚本直接从当前页面判据+截图,无需重跑整个流程(
jzsc_slide.mjs的判据只认页面状态,不校验是谁拖的)。这比反复自动重试稳定得多。 - 🎯 人工过一次后,同机当日可免验证(2026-09-20 实测,批量取证省事关键):用户手工通过滑块后,再新开 Chrome(甚至全新 profile)访问详情页,滑块面板不会再弹(实测
hasSlide:false / panelH:0 / code18:true,页面直接放行)。极验放行凭证按机器+网络环境维度缓存,有一定有效期。⇒ 多家公司批量时只需人工过第一次,后续公司可直接走无窗口bo_auto.sh/jzsc_slide_auto.mjs免验证出图;同一家公司当天重跑也不必再拖。建议流程:bo_auto.sh被拦 → 请用户过一次滑块 → 立刻重跑(通常直接成功)。 - jzsc 验证码题型会变,脚本需按型分流(2026-09-20 溯源,解释"以前为什么能全自动"):≤2026-09-16 上午是图标/文字点选题(题面印在图片里,如"请依次点击:钥匙、公交车、仙人掌"),脚本读图即可自动按序点击 → 全自动通过(历史案例:张家口方格 09-15、河北锦翼川 09-16 08:02 抓到 prompt"请点击与小型物体有相同形状的大型物体");09-16 下午起升级为滑块拼图,headless 无解。分界点铁证:同一天
09-16 14:25同命令由ok:true变为未抓到验证码元素 .geetest_item_wrap。判断当前题型:bo.sh jzsc-open返回needsSlide:true(滑块)或带prompt字段(点选)。点选题自动解流程仍在包里(bo_captcha.py+bo.sh jzsc-solve),题型一旦回退即可直接复用。 - 用户要求「后台运行、不要弹浏览器」时(2026-09-20 实测):直接用
scripts/bo_auto.sh(全 headless,无任何窗口)。代价是 jzsc 资质截图几乎必失败(headless 下极验客户端自检拦截,postCount=0),脚本会自动降级为needsManual并写NEED_MANUAL_CAPTCHA.txt,只交付安许截图 + 文档,资质字段标"待补充"。不要为了"不弹窗"去硬试滑块,无解。(例外:已按上一条人工过一次、处于免验证期内时,headless 可直接出图。) - headed Chrome 是人工兜底的可行通道(2026-09-20 验证):把
bo_chrome_up.sh里的--headless=new去掉(并加--window-position),滑块面板在可见窗口正常渲染;用户手动拖一次即通过,随后同一个 CDP 连接直接判据+截图,无需重跑。注意宿主里tasklist要MSYS_NO_PATHCONV=1。这是唯一可靠路径,但会弹窗。 - 滑块孔位检测必须用连通域,不能用逐列计数(2026-09-20 修正,曾导致全部失败):旧法「
bg/fullbg逐像素 diff>45 后取列计数 >5 的最小 x」有致命 bug——截图上常有一个顶部干扰连通域(典型 x52-97 / y0-37)与真实孔位(x97-140 / y70-117)在 x=97 处相接,列计数会把两者并成一片,取到 x=52 → 拖距少算约 45px,必然失败。正确做法:对 diff 掩码做 4 邻域连通域分析,然后按「纵向区间与拼图块纵向区间(slice alpha>60 的 y 范围)重合度 ×3 + 面积接近度 ×2」打分,取最高分分量。已实现于jzsc_slide.mjs,校准依据:算出的 target 与极验接口自回的ypos一致(如ypos=54↔ 实测孔顶 60)。
天津 :31293 数据源专属坑(2026-09-20)
/captcha/get必须用根路径:POST https://szzj.zfcxjs.tj.gov.cn:31293/captcha/get。写成/api/captcha/get、/prod-api/...、/crcc-purportal-manage/...全部 405。同理校验是根路径/captcha/check。- 别靠点 UI 刷新按钮换图:不生效,会复用同一 token,导致第 2 轮起连环
6110 验证码已失效。正确做法:每轮直接fetch('/captcha/get')拿新 token(实测每次 token 都变、图也变),零成本无限重试。 - 只调 API 不算通关:POST
/captcha/check返回0000后,页面业务请求仍报"验证过期,请重新验证",因为前端把通关凭证存在组件 state 里。必须调真实组件回调:
js // 从 Vue 根实例深度遍历找列表组件(name='ViewBsdtQyJbxxList') const root = document.querySelector('#app').__vue__; let target = null; const walk = (c, d) => { if (!c || d > 25) return; if (!target && typeof c.captacha === 'function' && typeof c.loadData2 === 'function') target = c; (c.$children || []).forEach(ch => walk(ch, d + 1)); }; walk(root, 0); target.captacha({ res: checkResponse }); // 组件内部读 e.res.repData.secondKey,并自动触发 loadData2 拉列表
secondKey只在/captcha/check成功响应里有,/captcha/get里是null。调完captacha会自动拉数据,不用再点查询按钮。 - 位移直接提交缺口像素值:
x = offset。实测用310×offset/400、offset×400/310等换算值必失败(返回6111)。 - 截图只能用
fullPage:true:该页有字体永不加载完,clip模式会卡在waiting for fonts to load...直到超时。技能里 jzsc 用 clip 能成,是因那页没这个问题,不能照搬。 - 禁用 CDP
Page.captureScreenshot:在本机(Windows + WorkBuddy 宿主)会触发 SIGTERM 杀进程,连无clip的裸调用都会崩。只能用page.screenshot()。 - 分页表格拼长图要防行重复:Ant Design 每页 10 行,需逐页截图后拼接。裁切规则:企业信息卡片区(到
.ant-table-thead的 y 为止)、表头(只取 1 次)、数据行(每页全取)。若把第 1 页table.y + table.h整块当作"顶部"再叠一次 tbody,会导致前 10 行重复。 - 必须强制从列表页
#/ViewBsdtQyJbxxList开始并只保留一个 31293 标签页:多标签并存时ctx.pages().find()可能选到别的页面(比如残留的详情页),会把详情表当搜索结果读,表现为"列表行数=10 但内容全是资质"。开跑前page.goto列表页 + 关掉多余同域标签页。 - 自研 PNG 解码器(纯 JS)读上一行必须用独立
prevBuffer:写成out[(y-1)*stride + x]会与就地重建的line冲突,导致整图变黑(实测平均亮度 8.6,正常应 249.3)。正确写法:line.copy(out, y*stride); prev = line;。