影刀RPA深度实战:企业营业执照自动查询与资质审核系统搭建
作者:林焱
一、痛点切入
我之前做企业内部合规审计的时候,最头疼的事情就是供应商资质审核。公司有800多家活跃供应商,每季度都要重新核实一次营业执照是否在有效期内、经营范围是否覆盖采购品类、注册资本是否达标。财务部的两个小姐姐每个季度要花整整两周时间,一家一家去国家企业信用信息公示系统查询,截图、复制粘贴、录入Excel。
错一个就可能导致给无资质供应商付款,这是审计红线。
后来我用影刀RPA搭建了一套自动化审核系统,把整个流程从两周压缩到4小时,准确率100%。这篇文章就完整拆解这个系统的搭建过程。
二、核心方法
场景描述
企业在新供应商准入、存量供应商定期复审时,需要完成以下审核动作:
- 在国家企业信用信息公示系统查询企业基本信息
- 验证营业执照关键字段(统一社会信用代码、法定代表人、注册资本、成立日期、经营范围、经营状态)
- 与供应商提供的资质文件进行交叉比对
- 生成审核结论(通过/不通过/需人工复核)
- 输出审核报告
整体架构
供应商列表(Excel) → 影刀RPA → 公示系统查询 → 数据提取 → 对比验证 → 审核报告(Excel)分步操作
第1步:准备供应商名单
在Excel中准备好待审核的供应商名单,表头如下:
| 供应商名称 | 统一社会信用代码 | 提供注册资本 | 提供经营范围 | 营业执照到期日 |
|---|
第2步:打开公示系统并搜索
国家企业信用信息公示系统网址:https://www.gsxt.gov.cn/
这个网站的反爬机制极其严格,我之前试过直接发HTTP请求,基本都会被拦截。影刀RPA的浏览器自动化的优势就在这里——模拟真实用户操作,不会被识别为爬虫。
影刀操作流程:
- 使用「打开网页」指令,打开公示系统首页
- 使用「等待元素出现」等待搜索框加载(这里有个坑,后文会说)
- 使用「输入文本」在搜索框中输入企业名称
- 使用「点击元素」点击搜索按钮
- 等待搜索结果列表加载
第3步:进入企业详情页
搜索结果出来后,需要点击企业名称进入详情页。这里注意:公示系统有时会弹出验证码,需要做验证码分支处理。
第4步:提取关键字段
在详情页中,使用「获取元素文本」逐一提取以下字段:
- 统一社会信用代码
- 企业名称
- 法定代表人
- 注册资本
- 成立日期
- 经营范围
- 登记状态
- 登记机关
第5步:数据比对与判定
将提取的数据与Excel中供应商提供的数据逐项比对,设定审核规则:
- 通过条件:登记状态为"存续"、注册资本达标、经营范围覆盖采购品类
- 不通过条件:登记状态为"吊销"或"注销"、注册资本不达标
- 人工复核条件:信息不一致但差异较小、无法获取完整信息
第6步:生成审核报告
将审核结果写入Excel,生成报告包含:
- 审核时间
- 供应商名称
- 审核结果
- 差异项明细
- 建议处理方式
三、代码实现
3.1 企业信息查询子流程
子流程名称:企业信息查询 参数:企业名称(文本) 返回值:企业信息(字典) 步骤: 1. 【打开网页】网址:"https://www.gsxt.gov.cn/index.html" 2. 【等待元素加载】等待搜索框出现 XPath://input[@id="keyword"] 说明:公示系统首页的搜索输入框,id为keyword是经过多次页面改版后验证稳定的定位方式 3. 【输入文本】 目标元素://input[@id="keyword"] 输入内容:{企业名称} 4. 【点击元素】 目标元素://button[@id="btn_query"] 说明:搜索按钮,点击后触发查询 5. 【等待元素加载】(等待搜索结果) XPath://div[contains(@class,"search_result")]//a 超时时间:10秒 说明:搜索结果以链接列表形式展示,等待第一个链接加载完成 6. 【条件判断】是否出现验证码 判断条件:检测页面是否包含验证码弹窗 XPath://div[contains(@class,"verify")] ── 如果存在验证码 → 执行"验证码处理"子流程 ── 如果不存在 → 继续下一步 7. 【点击元素】点击第一个搜索结果进入详情 XPath:(//div[contains(@class,"search_result")]//a)[1] 说明:取搜索结果列表中的第一个链接(通常就是目标企业) 8. 【等待元素加载】等待详情页加载 XPath://div[contains(@class,"detail")] 超时时间:15秒 9. 【获取元素文本】提取各字段 统一社会信用代码 XPath://td[contains(text(),"统一社会信用代码")]/following-sibling::td[1] 法定代表人 XPath://td[contains(text(),"法定代表人")]/following-sibling::td[1] 注册资本 XPath://td[contains(text(),"注册资本")]/following-sibling::td[1] 成立日期 XPath://td[contains(text(),"成立日期")]/following-sibling::td[1] 经营范围 XPath://td[contains(text(),"经营范围")]/following-sibling::td[1] 登记状态 XPath://td[contains(text(),"登记状态")]/following-sibling::td[1] 10. 【返回】返回企业信息字典3.2 核心比对逻辑(Python代码块)
# 供应商资质审核核心比对逻辑# 输入:从公示系统提取的企业信息字典,供应商提交的资质信息字典# 输出:审核结果("通过"/"不通过"/"人工复核")+ 差异明细defaudit_supplier_qualification(gsxt_data,supplier_data):""" 供应商资质审核函数 gsxt_data: 从国家企业信用信息公示系统提取的数据 supplier_data: 供应商自行提交的数据 """differences=[]# 记录差异项risk_score=0# 风险评分,超过阈值触发人工复核# 1. 检查经营状态 - 这是最关键的ifgsxt_data["登记状态"]!="存续":differences.append({"字段":"登记状态","公示系统":gsxt_data["登记状态"],"期望值":"存续","严重程度":"致命"})return"不通过",differences# 状态异常直接不通过# 2. 验证统一社会信用代码(精确匹配)ifgsxt_data["统一社会信用代码"]!=supplier_data["提供统一社会信用代码"]:differences.append({"字段":"统一社会信用代码","公示系统":gsxt_data["统一社会信用代码"],"供应商提供":supplier_data["提供统一社会信用代码"],"严重程度":"严重"})return"不通过",differences# 信用代码不一致直接不通过# 3. 检查注册资本# 将注册资本字符串转换为数值进行比较gsxt_capital=parse_capital(gsxt_data["注册资本"])# 转为万元数值required_capital=supplier_data["要求注册资本"]# 万元ifgsxt_capital<required_capital:differences.append({"字段":"注册资本","公示系统":f"{gsxt_capital}万元","要求":f"{required_capital}万元","严重程度":"严重"})risk_score+=30# 注册资本不达标加30分# 4. 检查经营范围覆盖# 判断经营范围内是否包含采购品类关键词required_keywords=supplier_data["采购品类关键词"]# 如:["食品","预包装"]business_scope=gsxt_data["经营范围"]missing_keywords=[]forkwinrequired_keywords:ifkwnotinbusiness_scope:missing_keywords.append(kw)ifmissing_keywords:differences.append({"字段":"经营范围","公示系统":business_scope[:50]+"...",# 经营范围可能很长"缺失关键词":", ".join(missing_keywords),"严重程度":"一般"})risk_score+=20# 经营范围缺失加20分# 5. 检查成立日期(判断经营年限)fromdatetimeimportdatetime establish_date=datetime.strptime(gsxt_data["成立日期"],"%Y-%m-%d")years_established=(datetime.now()-establish_date).days/365ifyears_established<1:differences.append({"字段":"成立日期","公示系统":gsxt_data["成立日期"],"说明":f"成立不足1年(仅{years_established:.1f}年),需关注","严重程度":"提示"})risk_score+=10# 综合判定ifrisk_score>=50:return"不通过",differenceselifrisk_score>=20:return"人工复核",differenceselse:return"通过",differencesdefparse_capital(capital_str):""" 解析注册资本字符串为万元数值 例:"1000万人民币" → 1000 "5000万元" → 5000 "100万(美元)" → 100(外币需人工复核时标记) """importre# 提取数字部分match=re.search(r'(\d+(?:\.\d+)?)\s*万',capital_str)ifmatch:returnfloat(match.group(1))# 如果单位是"亿"match=re.search(r'(\d+(?:\.\d+)?)\s*亿',capital_str)ifmatch:returnfloat(match.group(1))*10000return03.3 验证码处理子流程
子流程名称:验证码处理 步骤: 1. 【截图】截取验证码图片区域 XPath://img[contains(@src,"captcha") or contains(@id,"captcha")] 2. 【影刀OCR识别】对验证码图片进行OCR识别 注意:公示系统的验证码通常包含中文和数字混合,影刀自带OCR对数字+英文验证码效果较好, 中文验证码可能需要接入第三方打码平台 3. 【条件判断】OCR识别是否成功 ── 成功:输入识别结果,点击确定 ── 失败:点击"换一张"刷新验证码,返回步骤1(最多重试3次) ── 超过3次:记录日志"验证码识别失败:{企业名称}",跳过该企业,继续下一个 4. 【等待元素消失】等待验证码弹窗关闭 XPath://div[contains(@class,"verify-modal")]四、踩坑经验
坑1:公示系统频繁弹验证码
现象:查了不到20家企业就开始疯狂弹验证码,甚至滑块验证。
原因:公示系统的反爬机制检测到高频访问同一IP,触发风控。
解决:
- 每次查询间隔3-5秒,模拟人类操作速度
- 在影刀流程中加入「随机等待」指令,等待时间2-5秒随机
- 如果机器人运行在服务器上,确保服务器IP不被公示系统封禁
- 极端情况下,准备多个出口IP轮换
坑2:搜索结果不唯一
现象:搜索"XX科技有限公司",返回了10个结果,机器人点了第一个但那是错的。
原因:很多企业名称相似度极高,特别是一些同名不同地区的企业。
解决:
在搜索时使用精确的全称,不要只输入简称
搜索结果出来后,先用「获取元素文本」获取所有结果的企业名称列表
做一次精准匹配:
if 搜索关键词 == 列表项文本,再点击如果精确匹配也返回多个结果,根据"法定代表人"或"注册资本"做二次确认
坑3:详情页信息不全
现象:有些企业的详情页部分字段没有显示,比如"注册资本"那一行是空白的,导致提取失败。
原因:可能是该企业最新的工商信息还未完全同步到公示系统,或者该企业处于异常状态。
解决:
- 在提取每个字段后做「非空判断」
- 如果关键字段为空,标记为"信息不完整,需人工核实"
- 不要直接报错中断流程,用try-catch包裹提取操作
坑4:经营范围字段过长
现象:经营范围从影刀变量中读取时被截断,只拿到了一半内容。
原因:影刀早期版本的字符串变量有长度限制(约2000字符),而有些企业的经营范围超过5000字。
解决:
- 使用「获取元素outerHTML」再通过正则提取文本内容
- 或者将经营范围分段读取后拼接
- 如果经营范围过长影响后续判断,只取前1000字做关键词匹配即可
坑5:公示系统页面结构变更
现象:某天突然所有查询都失败了,流程全部报错。
原因:公示系统进行了改版,HTML结构和class名称都变了。
解决:
- 不要过于依赖具体的class名称定位元素,优先使用文本内容定位(如
//td[contains(text(),"统一社会信用代码")]) - 建立XPath配置表,将XPath集中管理在Excel中而非硬编码在流程里
- 每周运行一次监控任务,用一条测试数据验证流程是否正常
坑6:OCR识别营业执照的精度不足
现象:下载的营业执照图片用影刀OCR识别后,统一社会信用代码里的"0"被识别成"O",“2"被识别成"Z”。
原因:营业执照扫描件清晰度不够,OCR对相似字符的区分能力有限。
解决:
- 统一社会信用代码只有数字(0-9)和大写字母,不包含字母"O/Z/I",所以做后处理替换:
O→0, Z→2, I→1, S→5 - 信用代码有校验算法(ISO 7064),可以在识别后做校验码验证
- 如果OCR精度要求高,建议购买商用的营业执照OCR接口(如百度OCR、腾讯OCR)
五、常见问题速查
| # | 现象 | 原因 | 解决方式 |
|---|---|---|---|
| 1 | 打开公示系统后页面一直转圈圈不加载 | 网站加载了较多JS脚本,网络环境较差 | 增加「等待元素出现」的超时时间到30秒;检查网络代理设置;在流程开始时添加「等待页面加载完成」 |
| 2 | 搜索结果返回0条记录 | 企业名称输入有误或该企业未在工商系统登记 | 先在企业名称前后去空格;检查是否用了繁体字;用企业名称的前几个字做模糊搜索确认 |
| 3 | 提取的字段内容和看到的文字不一致 | HTML中存在隐藏文本或换行符干扰 | 使用normalize-space()函数去除多余空格和换行:`//td[contains(text(),"注册资 |
| 本")]/following-sibling::td[1]/normalize-space(.)` | |||
| 4 | 影刀流程运行到一半卡住了 | 公示系统弹出"系统繁忙"提示但没有被捕获 | 在关键步骤后添加"等待元素出现或消失"的兜底检查,并设置合理的超时时间 |
| 5 | 多线程并行查询时报错 | 公示系统同一时间只允许一个有效会话 | 不要用多线程同时查询同一个公示系统;如果业务量大,采用队列模式串行处理 |
| 6 | 审核报告中的中文乱码 | CSV/Excel文件的编码不是UTF-8 | 在「写入Excel」指令中指定编码格式为UTF-8;或者先写入CSV再用Excel打开导入 |
六、推荐资源
- 国家企业信用信息公示系统:https://www.gsxt.gov.cn/ — 官方数据源,数据最权威
- 统一社会信用代码校验算法:GB 32100-2015标准,可在GitHub搜索相关Python实现
- 影刀官方社区:搜索"工商查询"可找到官方提供的参考流程模板
- 企查查/天眼查API:如果预算允许,商业API查询效率更高、数据更全
七、内容标签
影刀RPA企业资质审核营业执照验证OCR识别工商查询合规审计供应商管理自动化审核企业内控数据比对
注意:本文涉及企业工商信息查询,建议在获得企业授权的前提下使用自动化工具采集数据。批量查询请控制频率,避免对公示系统造成压力。涉及金融数据审核的内容,请确保在加密环境中运行RPA流程。