营业执照(统一信用代码)的真伪识别程序设想(三)

admin 2026-09-07 04:18:10 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文档提出营业执照真伪识别程序设想,通过本地库交叉校验OCR识别结果,实现统一社会信用代码、名称、住所、法定代表人等字段比对,并设计Web服务可视化展示异常数据,支持图片预览与人工核对,提升执照审核效率与准确性。 综合评分: 72 文章分类: 安全工具,安全开发,数据安全


营业执照(统一信用代码)的真伪识别程序设想(三)

老皮的碎碎念念

2026年9月6日 16:06 安徽

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

对营业执照进行本地库校验:

将本地营业执照主体库导出为 REG_MARPRIPINFO.csv (字段名根据总局标准定义)

根据REG_MARPRIPINFO.csv校验ocr_result.csv,具体如下,将ocr_result.csv的数据逐个依次校验:首先统一社会信用代码是否包含在UNISCID中,如是,继续校验entname对名称,dom对住所,lerep对法定代表人,是否一致,输出不一致的,(如果统一社会信用代码是15位那么在reg_no中搜索,兼容老个体执照)

# -*- coding: utf-8 -*-"""交叉校验: ocr_result.csv vs REG_MARPRIPINFO.csv
逐条读取 ocr_result.csv 的统一社会信用代码, 在 REG_MARPRIPINFO.csv 中查找:  1. 优先匹配 UNISCID 字段  2. 未命中且为 15 位纯数字时, 回退匹配 REGNO 字段(老版执照注册号)命中后逐项比对: ENTNAME↔名称, DOM↔住所, LEREP↔法定代表人输出: 不一致明细 CSV + 控制台摘要"""import csvimport osimport sys

def norm(s):    """归一化: 去首尾空白、去尾部 \t、合并连续空白"""    if not s:        return ""    return " ".join(s.replace("\t", "").strip().split())

def main():    base = r"C:\Users\Administrator\AppData\Roaming\TRAE SOLO CN\ModularData\ai-agent\work-mode-projects\6a956215a09016f81bdfcb06"    reg_csv = os.path.join(base, "REG_MARPRIPINFO.csv")    ocr_csv = os.path.join(base, "ocr_result.csv")    out_dir = base
    # 1) 加载 REG_MARPRIPINFO.csv, 构建 UNISCID 索引 + REGNO 索引    uscc_map = {}   # UNISCID(大写) -> (ENTNAME, DOM, LEREP)    regno_map = {}  # REGNO       -> (ENTNAME, DOM, LEREP)
    with open(reg_csv, "r", encoding="utf-8-sig", newline="") as f:        rd = csv.reader((ln.replace("\x00", "") for ln in f))        header = next(rd)        idx = {name: i for i, name in enumerate(header)}        i_ent = idx["ENTNAME"]        i_dom = idx["DOM"]        i_lerep = idx["LEREP"]        i_regno = idx["REGNO"]        i_uniscid = idx["UNISCID"]
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;row&nbsp;in&nbsp;rd:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;len(row) <=&nbsp;max(i_ent, i_dom, i_lerep, i_regno, i_uniscid):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;continue&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rec = (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; norm(row[i_ent]),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; norm(row[i_dom]),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; norm(row[i_lerep]),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uscc = norm(row[i_uniscid]).upper()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;uscc:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uscc_map[uscc] = rec&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; regno = norm(row[i_regno])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;regno:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; regno_map[regno] = rec
&nbsp; &nbsp;&nbsp;print("REG_MARPRIPINFO.csv 加载完成: UNISCID 索引 %d 条, REGNO 索引 %d 条"&nbsp;% (len(uscc_map),&nbsp;len(regno_map)))
&nbsp; &nbsp;&nbsp;# 2) 逐条校验 ocr_result.csv&nbsp; &nbsp; results = [] &nbsp;# (图片, 信用代码, 匹配方式, 名称_ocr, 名称_reg, 名称_一致?, 住所_ocr, 住所_reg, 住所_一致?, 法定代表人_ocr, 法定代表人_reg, 法定代表人_一致?)&nbsp; &nbsp; matched =&nbsp;0&nbsp; &nbsp; not_found =&nbsp;0&nbsp; &nbsp; mismatch_cnt =&nbsp;0
&nbsp; &nbsp;&nbsp;with&nbsp;open(ocr_csv,&nbsp;"r", encoding="utf-8-sig", newline="")&nbsp;as&nbsp;f:&nbsp; &nbsp; &nbsp; &nbsp; rd = csv.DictReader(f)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;row&nbsp;in&nbsp;rd:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; img = row.get("图片文件",&nbsp;"")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; code_raw = row.get("统一社会信用代码",&nbsp;"").strip()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; code_up = code_raw.upper()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ocr_name = norm(row.get("名称",&nbsp;""))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ocr_addr = norm(row.get("住所",&nbsp;""))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ocr_lerep = norm(row.get("法定代表人",&nbsp;""))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 查找: 先 UNISCID, 再 REGNO&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rec =&nbsp;None&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; match_by =&nbsp;""&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;code_up&nbsp;in&nbsp;uscc_map:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rec = uscc_map[code_up]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; match_by =&nbsp;"UNISCID"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;elif&nbsp;code_raw&nbsp;in&nbsp;regno_map:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rec = regno_map[code_raw]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; match_by =&nbsp;"REGNO"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;rec&nbsp;is&nbsp;None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; not_found +=&nbsp;1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; results.append((img, code_raw,&nbsp;"未找到", ocr_name,&nbsp;"",&nbsp;"", ocr_addr,&nbsp;"",&nbsp;"", ocr_lerep,&nbsp;"",&nbsp;""))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;continue
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; matched +=&nbsp;1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reg_name, reg_dom, reg_lerep = rec
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name_ok = (ocr_name == reg_name)&nbsp;if&nbsp;ocr_name&nbsp;and&nbsp;reg_name&nbsp;else&nbsp;None&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dom_ok = (ocr_addr == reg_dom)&nbsp;if&nbsp;ocr_addr&nbsp;and&nbsp;reg_dom&nbsp;else&nbsp;None&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lerep_ok = (ocr_lerep == reg_lerep)&nbsp;if&nbsp;ocr_lerep&nbsp;and&nbsp;reg_lerep&nbsp;else&nbsp;None
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; has_mismatch =&nbsp;False&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;ok&nbsp;in&nbsp;(name_ok, dom_ok, lerep_ok):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;ok&nbsp;is&nbsp;False:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; has_mismatch =&nbsp;True&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;has_mismatch:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mismatch_cnt +=&nbsp;1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;def&nbsp;status_str(ok):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;ok&nbsp;is&nbsp;True:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;"一致"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;ok&nbsp;is&nbsp;False:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;"不一致"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;"OCR为空"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; results.append((&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; img, code_raw, match_by,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ocr_name, reg_name, status_str(name_ok),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ocr_addr, reg_dom, status_str(dom_ok),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ocr_lerep, reg_lerep, status_str(lerep_ok),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ))
&nbsp; &nbsp;&nbsp;# 3) 输出不一致明细&nbsp; &nbsp; report = os.path.join(out_dir,&nbsp;"ocr_cross_check_report.csv")&nbsp; &nbsp;&nbsp;with&nbsp;open(report,&nbsp;"w", encoding="utf-8-sig", newline="")&nbsp;as&nbsp;f:&nbsp; &nbsp; &nbsp; &nbsp; w = csv.writer(f)&nbsp; &nbsp; &nbsp; &nbsp; w.writerow([&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"图片文件",&nbsp;"信用代码",&nbsp;"匹配方式",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"名称(OCR)",&nbsp;"名称(库)",&nbsp;"名称比对",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"住所(OCR)",&nbsp;"住所(库)",&nbsp;"住所比对",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"法定代表人(OCR)",&nbsp;"法定代表人(库)",&nbsp;"法定代表人比对",&nbsp; &nbsp; &nbsp; &nbsp; ])&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 只输出未找到 + 不一致的记录&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;r&nbsp;in&nbsp;results:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;r[2] ==&nbsp;"未找到"&nbsp;or&nbsp;"不一致"&nbsp;in&nbsp;r[5]&nbsp;or&nbsp;"不一致"&nbsp;in&nbsp;r[8]&nbsp;or&nbsp;"不一致"&nbsp;in&nbsp;r[11]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w.writerow(r)
&nbsp; &nbsp;&nbsp;# 4) 全量明细(含一致的)&nbsp; &nbsp; full_report = os.path.join(out_dir,&nbsp;"ocr_cross_check_full.csv")&nbsp; &nbsp;&nbsp;with&nbsp;open(full_report,&nbsp;"w", encoding="utf-8-sig", newline="")&nbsp;as&nbsp;f:&nbsp; &nbsp; &nbsp; &nbsp; w = csv.writer(f)&nbsp; &nbsp; &nbsp; &nbsp; w.writerow([&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"图片文件",&nbsp;"信用代码",&nbsp;"匹配方式",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"名称(OCR)",&nbsp;"名称(库)",&nbsp;"名称比对",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"住所(OCR)",&nbsp;"住所(库)",&nbsp;"住所比对",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"法定代表人(OCR)",&nbsp;"法定代表人(库)",&nbsp;"法定代表人比对",&nbsp; &nbsp; &nbsp; &nbsp; ])&nbsp; &nbsp; &nbsp; &nbsp; w.writerows(results)
&nbsp; &nbsp;&nbsp;# 5) 控制台摘要&nbsp; &nbsp; sys.stdout.reconfigure(encoding="utf-8", errors="replace")&nbsp; &nbsp;&nbsp;print()&nbsp; &nbsp;&nbsp;print("=== 交叉校验报告 ===")&nbsp; &nbsp;&nbsp;print("ocr_result.csv 总条数 : %d"&nbsp;%&nbsp;len(results))&nbsp; &nbsp;&nbsp;print("成功匹配库中记录 &nbsp; &nbsp; : %d"&nbsp;% matched)&nbsp; &nbsp;&nbsp;print("未找到 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: %d"&nbsp;% not_found)&nbsp; &nbsp;&nbsp;print("存在不一致 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: %d"&nbsp;% mismatch_cnt)&nbsp; &nbsp;&nbsp;print()&nbsp; &nbsp;&nbsp;print("--- 逐条明细 ---")&nbsp; &nbsp;&nbsp;for&nbsp;img, code, mby, n_ocr, n_reg, n_st, d_ocr, d_reg, d_st, l_ocr, l_reg, l_st&nbsp;in&nbsp;results:&nbsp; &nbsp; &nbsp; &nbsp; flag =&nbsp;"✗"&nbsp;if&nbsp;(mby ==&nbsp;"未找到"&nbsp;or&nbsp;"不一致"&nbsp;in&nbsp;n_st&nbsp;or&nbsp;"不一致"&nbsp;in&nbsp;d_st&nbsp;or&nbsp;"不一致"&nbsp;in&nbsp;l_st)&nbsp;else&nbsp;"✓"&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(" &nbsp;%s %s"&nbsp;% (flag, img))&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;mby ==&nbsp;"未找到":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp; &nbsp;信用代码 %s 未在库中找到"&nbsp;% code)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;continue&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp; &nbsp;匹配方式: %s &nbsp;信用代码: %s"&nbsp;% (mby, code))&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp; &nbsp;名称 &nbsp; &nbsp;: [%s] vs [%s] &nbsp;→ %s"&nbsp;% (n_ocr, n_reg, n_st))&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp; &nbsp;住所 &nbsp; &nbsp;: [%s] vs [%s] &nbsp;→ %s"&nbsp;% (d_ocr, d_reg, d_st))&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp; &nbsp;法定代表: [%s] vs [%s] &nbsp;→ %s"&nbsp;% (l_ocr, l_reg, l_st))&nbsp; &nbsp;&nbsp;print()&nbsp; &nbsp;&nbsp;print("不一致明细: %s"&nbsp;% report)&nbsp; &nbsp;&nbsp;print("全量明细 &nbsp;: %s"&nbsp;% full_report)

if&nbsp;__name__ ==&nbsp;"__main__":&nbsp; &nbsp; main()

写一个python服务,网页访问展示校验输出的错误数据,点击图片文件名称可以显示照片,便于人工核对未校验通过的执照

页面功能

  • 汇总卡片

    :总记录数 / 有异常 / 正常

  • 筛选按钮

    :全部 / 仅异常 / 仅正常

  • 数据表格

    :每行展示图片文件名、信用代码、USCC 校验结果(GB 32100-2015)、名称/住所/法定代表人(含交叉比对详情)、匹配方式、备注

  • 图片预览

    :点击图片文件名,弹出原图浮窗,按 Esc 或点击空白处关闭

  • 异常记录自动排在最前面

判定逻辑

以下情况标记为异常:

  • USCC 校验:校验码不符 / 长度异常 / 非法字符
  • 交叉校验:未找到 / 字段不一致
# -*- coding: utf-8 -*-"""OCR 执照识别结果校验可视化服务
启动后访问 http://127.0.0.1:5000展示 ocr_result.csv + USCC 校验 + 交叉校验的合并结果点击图片文件名可弹出原图预览"""import csvimport osimport sys
from flask import Flask, abort, send_file, render_template_string
BASE = os.path.dirname(os.path.abspath(__file__))IMG_DIR = r"D:\Personal\Desktop\新建文件夹 (2)"
app = Flask(__name__)

def norm(s):&nbsp; &nbsp; return (s or "").replace("\t", "").strip()

def load_ocr_result():&nbsp; &nbsp; path = os.path.join(BASE, "ocr_result.csv")&nbsp; &nbsp; data = {}&nbsp; &nbsp; if not os.path.exists(path):&nbsp; &nbsp; &nbsp; &nbsp; return data&nbsp; &nbsp; with open(path, "r", encoding="utf-8-sig", newline="") as f:&nbsp; &nbsp; &nbsp; &nbsp; for row in csv.DictReader(f):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; img = norm(row.get("图片文件", ""))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if img:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data[img] = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "code": norm(row.get("统一社会信用代码", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name": norm(row.get("名称", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "address": norm(row.get("住所", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "legal_rep": norm(row.get("法定代表人", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "note": norm(row.get("备注", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; return data

def load_uscc_check():&nbsp; &nbsp; path = os.path.join(BASE, "ocr_uscc_check_report.csv")&nbsp; &nbsp; data = {}&nbsp; &nbsp; if not os.path.exists(path):&nbsp; &nbsp; &nbsp; &nbsp; return data&nbsp; &nbsp; with open(path, "r", encoding="utf-8-sig", newline="") as f:&nbsp; &nbsp; &nbsp; &nbsp; for row in csv.DictReader(f):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; img = norm(row.get("图片文件", ""))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if img:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data[img] = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "uscc_status": norm(row.get("校验结果", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "uscc_reason": norm(row.get("说明", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; return data

def load_cross_check():&nbsp; &nbsp; path = os.path.join(BASE, "ocr_cross_check_full.csv")&nbsp; &nbsp; data = {}&nbsp; &nbsp; if not os.path.exists(path):&nbsp; &nbsp; &nbsp; &nbsp; return data&nbsp; &nbsp; with open(path, "r", encoding="utf-8-sig", newline="") as f:&nbsp; &nbsp; &nbsp; &nbsp; for row in csv.DictReader(f):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; img = norm(row.get("图片文件", ""))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if img:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data[img] = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "match_by": norm(row.get("匹配方式", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name_ocr": norm(row.get("名称(OCR)", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name_reg": norm(row.get("名称(库)", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name_cmp": norm(row.get("名称比对", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "addr_ocr": norm(row.get("住所(OCR)", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "addr_reg": norm(row.get("住所(库)", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "addr_cmp": norm(row.get("住所比对", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "lerep_ocr": norm(row.get("法定代表人(OCR)", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "lerep_reg": norm(row.get("法定代表人(库)", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "lerep_cmp": norm(row.get("法定代表人比对", "")),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; return data

def merge_data():&nbsp; &nbsp; ocr = load_ocr_result()&nbsp; &nbsp; uscc = load_uscc_check()&nbsp; &nbsp; cross = load_cross_check()&nbsp; &nbsp; rows = []&nbsp; &nbsp; for img, o in ocr.items():&nbsp; &nbsp; &nbsp; &nbsp; u = uscc.get(img, {})&nbsp; &nbsp; &nbsp; &nbsp; c = cross.get(img, {})&nbsp; &nbsp; &nbsp; &nbsp; # 判断是否有错误&nbsp; &nbsp; &nbsp; &nbsp; has_error = False&nbsp; &nbsp; &nbsp; &nbsp; if u.get("uscc_status") in ("校验码不符", "长度异常", "非法字符", "首位异常"):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; has_error = True&nbsp; &nbsp; &nbsp; &nbsp; if c.get("match_by") == "未找到":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; has_error = True&nbsp; &nbsp; &nbsp; &nbsp; if "不一致" in c.get("name_cmp", "") or "不一致" in c.get("addr_cmp", "") or "不一致" in c.get("lerep_cmp", ""):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; has_error = True
&nbsp; &nbsp; &nbsp; &nbsp; rows.append({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "img": img,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "code": o.get("code", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name": o.get("name", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "address": o.get("address", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "legal_rep": o.get("legal_rep", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "note": o.get("note", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "uscc_status": u.get("uscc_status", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "uscc_reason": u.get("uscc_reason", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "match_by": c.get("match_by", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name_ocr": c.get("name_ocr", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name_reg": c.get("name_reg", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "name_cmp": c.get("name_cmp", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "addr_ocr": c.get("addr_ocr", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "addr_reg": c.get("addr_reg", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "addr_cmp": c.get("addr_cmp", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "lerep_ocr": c.get("lerep_ocr", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "lerep_reg": c.get("lerep_reg", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "lerep_cmp": c.get("lerep_cmp", ""),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "has_error": has_error,&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; rows.sort(key=lambda r: (not r["has_error"], r["img"]))&nbsp; &nbsp; return rows

HTML = r"""<!DOCTYPE&nbsp;html><html&nbsp;lang="zh-CN"><head><meta&nbsp;charset="utf-8"><meta&nbsp;name="viewport"&nbsp;content="width=device-width, initial-scale=1"><title>OCR 执照校验结果</title><style>:root&nbsp;{&nbsp;&nbsp;--bg:&nbsp;#0f1117;&nbsp;&nbsp;--card:&nbsp;#1a1d27;&nbsp;&nbsp;--border:&nbsp;#2a2d3a;&nbsp;&nbsp;--text:&nbsp;#e0e0e0;&nbsp;&nbsp;--text-dim:&nbsp;#888;&nbsp;&nbsp;--accent:&nbsp;#4a9eff;&nbsp;&nbsp;--green:&nbsp;#4caf50;&nbsp;&nbsp;--red:&nbsp;#f44336;&nbsp;&nbsp;--orange:&nbsp;#ff9800;&nbsp;&nbsp;--yellow:&nbsp;#ffd54f;}* {&nbsp;box-sizing: border-box;&nbsp;margin:&nbsp;0;&nbsp;padding:&nbsp;0; }body&nbsp;{&nbsp;&nbsp;background:&nbsp;var(--bg);&nbsp;&nbsp;color:&nbsp;var(--text);&nbsp;&nbsp;font-family:&nbsp;'Microsoft YaHei',&nbsp;'Segoe UI', sans-serif;&nbsp;&nbsp;padding:&nbsp;24px;&nbsp;&nbsp;font-size:&nbsp;16px;}h1&nbsp;{&nbsp;font-size:&nbsp;28px;&nbsp;margin-bottom:&nbsp;4px; }.subtitle&nbsp;{&nbsp;color:&nbsp;var(--text-dim);&nbsp;font-size:&nbsp;16px;&nbsp;margin-bottom:&nbsp;20px; }.summary&nbsp;{&nbsp;&nbsp;display: flex;&nbsp;&nbsp;gap:&nbsp;16px;&nbsp;&nbsp;margin-bottom:&nbsp;24px;&nbsp;&nbsp;flex-wrap: wrap;}.summary&nbsp;.card&nbsp;{&nbsp;&nbsp;background:&nbsp;var(--card);&nbsp;&nbsp;border:&nbsp;1px&nbsp;solid&nbsp;var(--border);&nbsp;&nbsp;border-radius:&nbsp;8px;&nbsp;&nbsp;padding:&nbsp;16px&nbsp;24px;&nbsp;&nbsp;min-width:&nbsp;120px;&nbsp;&nbsp;text-align: center;}.summary&nbsp;.num&nbsp;{&nbsp;font-size:&nbsp;36px;&nbsp;font-weight:&nbsp;700; }.summary&nbsp;.label&nbsp;{&nbsp;font-size:&nbsp;15px;&nbsp;color:&nbsp;var(--text-dim);&nbsp;margin-top:&nbsp;4px; }
table&nbsp;{&nbsp;&nbsp;width:&nbsp;100%;&nbsp;&nbsp;border-collapse: collapse;&nbsp;&nbsp;background:&nbsp;var(--card);&nbsp;&nbsp;border-radius:&nbsp;8px;&nbsp;&nbsp;overflow: hidden;}th,&nbsp;td&nbsp;{&nbsp;&nbsp;padding:&nbsp;14px&nbsp;16px;&nbsp;&nbsp;text-align: left;&nbsp;&nbsp;border-bottom:&nbsp;1px&nbsp;solid&nbsp;var(--border);&nbsp;&nbsp;font-size:&nbsp;16px;&nbsp;&nbsp;vertical-align: top;}th&nbsp;{&nbsp;&nbsp;background:&nbsp;#212530;&nbsp;&nbsp;color:&nbsp;var(--text-dim);&nbsp;&nbsp;font-weight:&nbsp;600;&nbsp;&nbsp;white-space: nowrap;&nbsp;&nbsp;position: sticky;&nbsp;&nbsp;top:&nbsp;0;&nbsp;&nbsp;z-index:&nbsp;1;}tr:hover&nbsp;td&nbsp;{&nbsp;background:&nbsp;#1e2230; }.img-link&nbsp;{&nbsp;&nbsp;color:&nbsp;var(--accent);&nbsp;&nbsp;cursor: pointer;&nbsp;&nbsp;text-decoration: underline;&nbsp;&nbsp;text-underline-offset:&nbsp;2px;}.img-link:hover&nbsp;{&nbsp;text-decoration: none;&nbsp;opacity: .8; }.badge&nbsp;{&nbsp;&nbsp;display: inline-block;&nbsp;&nbsp;padding:&nbsp;4px&nbsp;12px;&nbsp;&nbsp;border-radius:&nbsp;4px;&nbsp;&nbsp;font-size:&nbsp;14px;&nbsp;&nbsp;font-weight:&nbsp;600;&nbsp;&nbsp;white-space: nowrap;}.badge-ok&nbsp;{&nbsp;background:&nbsp;rgba(76,175,80,.15);&nbsp;color:&nbsp;var(--green); }.badge-err&nbsp;{&nbsp;background:&nbsp;rgba(244,67,54,.15);&nbsp;color:&nbsp;var(--red); }.badge-warn&nbsp;{&nbsp;background:&nbsp;rgba(255,152,0,.15);&nbsp;color:&nbsp;var(--orange); }.badge-info&nbsp;{&nbsp;background:&nbsp;rgba(74,158,255,.15);&nbsp;color:&nbsp;var(--accent); }.cmp-ok&nbsp;{&nbsp;color:&nbsp;var(--green); }.cmp-bad&nbsp;{&nbsp;color:&nbsp;var(--red);&nbsp;font-weight:&nbsp;600; }.cmp-empty&nbsp;{&nbsp;color:&nbsp;var(--text-dim); }
#overlay&nbsp;{&nbsp;&nbsp;display: none;&nbsp;&nbsp;position: fixed;&nbsp;&nbsp;inset:&nbsp;0;&nbsp;&nbsp;background:&nbsp;rgba(0,0,0,.85);&nbsp;&nbsp;z-index:&nbsp;999;&nbsp;&nbsp;justify-content: center;&nbsp;&nbsp;align-items: center;}#overlay.show&nbsp;{&nbsp;display: flex; }#overlay&nbsp;img&nbsp;{&nbsp;&nbsp;max-width:&nbsp;90vw;&nbsp;&nbsp;max-height:&nbsp;90vh;&nbsp;&nbsp;border-radius:&nbsp;8px;&nbsp;&nbsp;box-shadow:&nbsp;0&nbsp;8px&nbsp;32px&nbsp;rgba(0,0,0,.5);}#overlay&nbsp;.close&nbsp;{&nbsp;&nbsp;position: fixed;&nbsp;&nbsp;top:&nbsp;16px;&nbsp;&nbsp;right:&nbsp;24px;&nbsp;&nbsp;color:&nbsp;#fff;&nbsp;&nbsp;font-size:&nbsp;32px;&nbsp;&nbsp;cursor: pointer;&nbsp;&nbsp;user-select: none;}.filter-bar&nbsp;{&nbsp;&nbsp;margin-bottom:&nbsp;16px;&nbsp;&nbsp;display: flex;&nbsp;&nbsp;gap:&nbsp;8px;&nbsp;&nbsp;flex-wrap: wrap;}.filter-btn&nbsp;{&nbsp;&nbsp;background:&nbsp;var(--card);&nbsp;&nbsp;border:&nbsp;1px&nbsp;solid&nbsp;var(--border);&nbsp;&nbsp;color:&nbsp;var(--text-dim);&nbsp;&nbsp;padding:&nbsp;8px&nbsp;20px;&nbsp;&nbsp;border-radius:&nbsp;6px;&nbsp;&nbsp;cursor: pointer;&nbsp;&nbsp;font-size:&nbsp;16px;&nbsp;&nbsp;transition: all .2s;}.filter-btn:hover&nbsp;{&nbsp;border-color:&nbsp;var(--accent);&nbsp;color:&nbsp;var(--text); }.filter-btn.active&nbsp;{&nbsp;background:&nbsp;var(--accent);&nbsp;color:&nbsp;#fff;&nbsp;border-color:&nbsp;var(--accent); }</style></head><body><h1>OCR 执照识别校验结果</h1><p&nbsp;class="subtitle">USCC 校验(GB 32100-2015) + REG_MARPRIPINFO 交叉比对 · 点击图片文件名预览原图</p>
<div&nbsp;class="summary">&nbsp;&nbsp;<div&nbsp;class="card"><div&nbsp;class="num"&nbsp;id="s-total">0</div><div&nbsp;class="label">总记录</div></div>&nbsp;&nbsp;<div&nbsp;class="card"><div&nbsp;class="num"&nbsp;id="s-err"&nbsp;style="color:var(--red)">0</div><div&nbsp;class="label">有异常</div></div>&nbsp;&nbsp;<div&nbsp;class="card"><div&nbsp;class="num"&nbsp;id="s-ok"&nbsp;style="color:var(--green)">0</div><div&nbsp;class="label">正常</div></div></div>
<div&nbsp;class="filter-bar">&nbsp;&nbsp;<button&nbsp;class="filter-btn active"&nbsp;data-filter="all">全部</button>&nbsp;&nbsp;<button&nbsp;class="filter-btn"&nbsp;data-filter="err">仅异常</button>&nbsp;&nbsp;<button&nbsp;class="filter-btn"&nbsp;data-filter="ok">仅正常</button></div>
<table&nbsp;id="tbl"><thead><tr>&nbsp;&nbsp;<th>图片文件</th>&nbsp;&nbsp;<th>统一社会信用代码</th>&nbsp;&nbsp;<th>USCC 校验</th>&nbsp;&nbsp;<th>名称</th>&nbsp;&nbsp;<th>住所</th>&nbsp;&nbsp;<th>法定代表人</th>&nbsp;&nbsp;<th>交叉校验</th>&nbsp;&nbsp;<th>备注</th></tr></thead><tbody&nbsp;id="tbody"></tbody></table>
<div&nbsp;id="overlay">&nbsp;&nbsp;<span&nbsp;class="close"&nbsp;onclick="closeOverlay()">&times;</span>&nbsp;&nbsp;<img&nbsp;id="overlay-img"&nbsp;src=""&nbsp;alt=""></div>
<script>const&nbsp;DATA&nbsp;= __DATA__;const&nbsp;IMG_PREFIX&nbsp;=&nbsp;"/img/";
function&nbsp;badge(text, type) {&nbsp;&nbsp;return&nbsp;`<span class="badge badge-${type}">${esc(text)}</span>`;}
function&nbsp;esc(s) {&nbsp;&nbsp;if&nbsp;(!s)&nbsp;return&nbsp;'';&nbsp;&nbsp;return&nbsp;s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}
function&nbsp;cmpCell(ocr, reg, cmp) {&nbsp;&nbsp;if&nbsp;(!cmp)&nbsp;return&nbsp;'<span class="cmp-empty">—</span>';&nbsp;&nbsp;if&nbsp;(cmp ===&nbsp;'一致')&nbsp;return&nbsp;`<span class="cmp-ok">一致</span>`;&nbsp;&nbsp;if&nbsp;(cmp ===&nbsp;'OCR为空')&nbsp;return&nbsp;'<span class="cmp-empty">OCR为空</span>';&nbsp;&nbsp;// 不一致&nbsp;&nbsp;let&nbsp;html =&nbsp;'<span class="cmp-bad">不一致</span><br>';&nbsp;&nbsp;if&nbsp;(ocr) html +=&nbsp;`<span style="font-size:14px;color:var(--text-dim)">OCR:&nbsp;${esc(ocr)}</span><br>`;&nbsp;&nbsp;if&nbsp;(reg) html +=&nbsp;`<span style="font-size:14px;color:var(--text-dim)">库:&nbsp;${esc(reg)}</span>`;&nbsp;&nbsp;return&nbsp;html;}
function&nbsp;renderRows(filter) {&nbsp;&nbsp;const&nbsp;tbody =&nbsp;document.getElementById('tbody');&nbsp; tbody.innerHTML&nbsp;=&nbsp;'';&nbsp;&nbsp;let&nbsp;errCount =&nbsp;0, okCount =&nbsp;0;&nbsp;&nbsp;DATA.forEach((r, i) =>&nbsp;{&nbsp; &nbsp;&nbsp;if&nbsp;(r.has_error) errCount++;&nbsp;else&nbsp;okCount++;&nbsp; &nbsp;&nbsp;if&nbsp;(filter ===&nbsp;'err'&nbsp;&& !r.has_error)&nbsp;return;&nbsp; &nbsp;&nbsp;if&nbsp;(filter ===&nbsp;'ok'&nbsp;&& r.has_error)&nbsp;return;
&nbsp; &nbsp;&nbsp;// USCC badge&nbsp; &nbsp;&nbsp;let&nbsp;usccBadge =&nbsp;'';&nbsp; &nbsp;&nbsp;const&nbsp;st = r.uscc_status;&nbsp; &nbsp;&nbsp;if&nbsp;(st ===&nbsp;'有效') usccBadge =&nbsp;badge('有效',&nbsp;'ok');&nbsp; &nbsp;&nbsp;else&nbsp;if&nbsp;(st ===&nbsp;'校验码不符') usccBadge =&nbsp;badge('校验码不符',&nbsp;'err');&nbsp; &nbsp;&nbsp;else&nbsp;if&nbsp;(st ===&nbsp;'注册号(15位)') usccBadge =&nbsp;badge('注册号',&nbsp;'info');&nbsp; &nbsp;&nbsp;else&nbsp;if&nbsp;(st) usccBadge =&nbsp;badge(st,&nbsp;'warn');
&nbsp; &nbsp;&nbsp;// 交叉校验&nbsp; &nbsp;&nbsp;let&nbsp;crossBadge =&nbsp;'';&nbsp; &nbsp;&nbsp;if&nbsp;(r.match_by&nbsp;===&nbsp;'未找到'&nbsp;|| !r.match_by) {&nbsp; &nbsp; &nbsp; crossBadge =&nbsp;badge('未找到',&nbsp;'warn');&nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; crossBadge =&nbsp;badge(r.match_by,&nbsp;'info');&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;const&nbsp;tr =&nbsp;document.createElement('tr');&nbsp; &nbsp; tr.innerHTML&nbsp;=&nbsp;`&nbsp; &nbsp; &nbsp; <td><span class="img-link" onclick="showImg('${esc(r.img)}')">${esc(r.img)}</span></td>&nbsp; &nbsp; &nbsp; <td><code style="font-size:15px">${esc(r.code)}</code></td>&nbsp; &nbsp; &nbsp; <td>${usccBadge}${r.uscc_reason ?&nbsp;'<br><span style="font-size:14px;color:var(--text-dim)">'+esc(r.uscc_reason)+'</span>':''}</td>&nbsp; &nbsp; &nbsp; <td>${esc(r.name)}${r.name_cmp ?&nbsp;'<hr style="border:none;border-top:1px solid var(--border);margin:4px 0">'+cmpCell(r.name_ocr, r.name_reg, r.name_cmp):''}</td>&nbsp; &nbsp; &nbsp; <td>${esc(r.address)}${r.addr_cmp ?&nbsp;'<hr style="border:none;border-top:1px solid var(--border);margin:4px 0">'+cmpCell(r.addr_ocr, r.addr_reg, r.addr_cmp):''}</td>&nbsp; &nbsp; &nbsp; <td>${esc(r.legal_rep)}${r.lerep_cmp ?&nbsp;'<hr style="border:none;border-top:1px solid var(--border);margin:4px 0">'+cmpCell(r.lerep_ocr, r.lerep_reg, r.lerep_cmp):''}</td>&nbsp; &nbsp; &nbsp; <td>${crossBadge}</td>&nbsp; &nbsp; &nbsp; <td style="font-size:15px;color:var(--text-dim)">${esc(r.note)}</td>&nbsp; &nbsp; `;&nbsp; &nbsp; tbody.appendChild(tr);&nbsp; });&nbsp;&nbsp;document.getElementById('s-total').textContent&nbsp;=&nbsp;DATA.length;&nbsp;&nbsp;document.getElementById('s-err').textContent&nbsp;= errCount;&nbsp;&nbsp;document.getElementById('s-ok').textContent&nbsp;= okCount;}
function&nbsp;showImg(filename) {&nbsp;&nbsp;fetch(IMG_PREFIX&nbsp;+&nbsp;encodeURIComponent(filename))&nbsp; &nbsp; .then(resp&nbsp;=>&nbsp;{&nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!resp.ok)&nbsp;throw&nbsp;new&nbsp;Error('not found');&nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;resp.blob();&nbsp; &nbsp; })&nbsp; &nbsp; .then(blob&nbsp;=>&nbsp;{&nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;url =&nbsp;URL.createObjectURL(blob);&nbsp; &nbsp; &nbsp;&nbsp;document.getElementById('overlay-img').src&nbsp;= url;&nbsp; &nbsp; &nbsp;&nbsp;document.getElementById('overlay').classList.add('show');&nbsp; &nbsp; })&nbsp; &nbsp; .catch(() =>&nbsp;{&nbsp; &nbsp; &nbsp;&nbsp;alert('图片未找到: '&nbsp;+ filename +&nbsp;'\n请确认图片目录: '&nbsp;+&nbsp;IMG_DIR);&nbsp; &nbsp; });}
function&nbsp;closeOverlay() {&nbsp;&nbsp;document.getElementById('overlay').classList.remove('show');&nbsp;&nbsp;document.getElementById('overlay-img').src&nbsp;=&nbsp;'';}
document.getElementById('overlay').addEventListener('click',&nbsp;function(e) {&nbsp;&nbsp;if&nbsp;(e.target&nbsp;===&nbsp;this)&nbsp;closeOverlay();});
document.addEventListener('keydown',&nbsp;function(e) {&nbsp;&nbsp;if&nbsp;(e.key&nbsp;===&nbsp;'Escape')&nbsp;closeOverlay();});
document.querySelectorAll('.filter-btn').forEach(btn&nbsp;=>&nbsp;{&nbsp; btn.addEventListener('click',&nbsp;function() {&nbsp; &nbsp;&nbsp;document.querySelectorAll('.filter-btn').forEach(b&nbsp;=>&nbsp;b.classList.remove('active'));&nbsp; &nbsp;&nbsp;this.classList.add('active');&nbsp; &nbsp;&nbsp;renderRows(this.dataset.filter);&nbsp; });});
renderRows('all');</script></body></html>"""

@app.route("/")def index():&nbsp; &nbsp; rows = merge_data()&nbsp; &nbsp; import json&nbsp; &nbsp; html = HTML.replace("__DATA__", json.dumps(rows, ensure_ascii=False))&nbsp; &nbsp; return html

@app.route("/img/<path:filename>")def serve_img(filename):&nbsp; &nbsp; from urllib.parse import unquote&nbsp; &nbsp; filename = unquote(filename)&nbsp; &nbsp; # 优先在 IMG_DIR 找&nbsp; &nbsp; if IMG_DIR and os.path.exists(os.path.join(IMG_DIR, filename)):&nbsp; &nbsp; &nbsp; &nbsp; return send_file(os.path.join(IMG_DIR, filename))&nbsp; &nbsp; # 回退到附件目录&nbsp; &nbsp; attach = r"c:\Users\Administrator\.trae-cn\attachments\6a956215a09016f81bdfcb09"&nbsp; &nbsp; if os.path.exists(os.path.join(attach, filename)):&nbsp; &nbsp; &nbsp; &nbsp; return send_file(os.path.join(attach, filename))&nbsp; &nbsp; abort(404)

if __name__ == "__main__":&nbsp; &nbsp; print("=" * 50)&nbsp; &nbsp; print(" &nbsp;OCR 执照校验结果可视化服务")&nbsp; &nbsp; print(" &nbsp;访问 http://127.0.0.1:5000")&nbsp; &nbsp; print(" &nbsp;图片目录: %s" % IMG_DIR)&nbsp; &nbsp; print(" &nbsp;按 Ctrl+C 停止")&nbsp; &nbsp; print("=" * 50)&nbsp; &nbsp; app.run(host="127.0.0.1", port=5000, debug=False)

至此程序的基本框架和功能验证已经完成

注:本文中的营业执照图片数据来源于百度搜索,为不盈利引用,仅作为试验学习使用,不证明其合法性、真伪性,未进行商业性利用。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:老皮的碎碎念念 《营业执照(统一信用代码)的真伪识别程序设想(三)》

评论:0   参与:  0