恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

基于Python爬虫和数据清洗的产业分类标准化对照表构建

  • 首页
  • 资讯中心
  • /
  • 基于Python爬虫和数据清洗的产业分类标准化对照表构建

相关资讯

React性能优化实战:从Profiler定位到虚拟列表与代码分割的完整指南 2026/10/17 9:44:53
A-Star算法在迷宫游戏中的实时优化与工程落地 2026/10/17 9:44:53
未来制造业与工业人工智能PPT:从车间痛点到投资回报的汇报骨架 2026/10/17 9:44:53

最新资讯

如何快速搭起一个AI代理服务:agent-service-toolkit从LangGraph到上线的实践指南
ResNet+SVM乳腺癌检测实战:特征提取、SVM调参及避坑指南
双串锂电池主动均衡设计:MP2642GR-Z与STM32协同实战
ChatAI+NBAPI 实战:用 TaoToken 统一 Key 把 API 聚合接入自建 ChatGPT
superpowers:为Codex CLI赋予技能层的AI编程助手实践指南
冷热数据分离存储实战:从成本困境到分层体系落地

今日推荐

Qwen3.5-122B-A10B-singprobe幻觉检测实战:AUC 0.7806,如何实时揪出大模型一本正经的胡话?
NetSpot 实战:用信道分析与频宽优化解决 Wi-Fi 卡顿
C++ split() 字符串分割的五种实现与性能实测

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

基于Python爬虫和数据清洗的产业分类标准化对照表构建

发布时间:2026/10/17 9:44:53
基于Python爬虫和数据清洗的产业分类标准化对照表构建 如果你做过数据治理、BI看板或者指标体系搭建大概率会遇到一个让人头大的问题同一张业务表里客户所属行业写的是“计算机、通信和其他电子设备制造业”另一份外部报告里同一个行业叫“电子制造业”到了供应商系统里又变成“ICT设备制造”。如果不先把这些乱七八糟的叫法统一起来后续的统计分析全是坑。我这次就用Python爬虫加自动化脚本把多个来源的产业分类名称抓下来清洗后映射到一套标准编码上最终生成了一张可复用的“产业分类标准化对照表”。这篇就完整记录我当时怎么做的包括爬虫设计、数据清洗、匹配逻辑、定时更新和踩坑实录适合正在做数据标准化、行业分析或爬虫项目的同学参考。1. 项目背景与目标拆解1.1 为什么需要产业分类标准化对照表先说一个真实场景。某天我接到一个数据治理需求要把几个业务系统里的“行业”字段统一起来。第一套系统里的字段是用户在注册时自己填写的比如“软件服务”“互联网科技”“软件开发”第二套系统是销售团队录入的写的是“软件和信息技术服务业”“信息技术服务”第三套系统来自外部商机数据直接用的是一串四位数编码但编码体系跟前面完全不兼容。这三套数据的口径只要放在一起饼图能做但每个扇区的含义都不一样汇总出来的数字根本没法解释。要做区域分布分析、行业渗透率分析更是无从下手。所以当时的核心任务就变成能不能做一张表把“来源行业名称”和“标准行业名称”对应起来并且要给每个匹配结果一个置信度让业务侧知道这个映射是来自精确匹配、模糊匹配还是人工确认。这种表就是产业分类标准化对照表。它不是一个一次性交付的Excel而是一个需要持续维护的数据资产。因为业务系统会继续录入新的叫法外部数据源也会更新分类口径如果全靠手工维护每周抽一个下午复制粘贴效率极低而且容易出错。于是很自然就想到用爬虫去抓公开的分类数据源再通过脚本自动清洗、匹配、生成对照表。1.2 整体方案与技术选型整个项目分成了四个环节数据采集、数据清洗、映射生成、自动化调度。数据采集用Python的requests加BeautifulSoup因为目标数据源大多是公开的静态表格页面结构相对固定用这两个库足够。数据清洗用pandas处理空值、去重、去空格、截取括号内容这类操作pandas的表达力很强。映射匹配用到了fuzzy字符串匹配库先做精确匹配再对没有命中的名称做相似度匹配最后把置信度低于阈值的结果拎出来让人工审核。自动化调度用的是APScheduler设定每天凌晨执行一次增量更新把新增的来源名称纳入对照表。之所以选Python而不用Java或者Node是因为这个任务的难点不在并发和性能而在快速试错。爬取、解析、匹配、输出Excel整个链路用Python写起来非常顺而且后续如果换了数据源改解析函数比改一整套工程要快得多。说实话这个项目的数据量不算大也就是几万个名称级别的规模Python的性能完全够用。2. 数据源分析与爬虫设计2.1 数据源选择与页面结构勘探爬虫的第一步不是急着写代码而是先弄清楚目标页面长什么样。我当时确认了两类数据源一类是某个公开统计网站的行业分类目录页按层级展示大类、中类、小类每页有一张表格包含编码和名称另一类是企业信息查询平台上的行业标签字段这些标签是用户或者商家提交的叫法非常随意正好用来当作“待标准化来源名称”。先看目录页。打开浏览器开发者工具按F12查看页面结构直接搜索表格所在的HTML节点确认是不是渲染在服务端的表格。如果表格数据是服务端渲染出来的requests就能直接拿到如果是前端异步加载的得另找接口。我实际碰到的目录页是服务端渲染的表格里每一行有四个字段编码、名称、说明、级别。这已经很理想了。再确定分页规则。目录页的分页参数通常藏在URL的query里比如page1、page2。我习惯先手动点几页观察URL变化规律同时看总页数在页面哪里暴露。如果总页数写在某个元素里比如“共120页”那爬虫就按这个数字循环请求。如果没写就循环请求一直发直到某一页返回空表格为止但这样多一次无效请求不是最优。2.2 请求与解析一套能直接跑的模板我写爬虫有个习惯先把通用请求函数做出来再针对每个页面写解析函数。请求函数至少要包含三部分自定义请求头、超时、重试机制。下面是当时用的模板实测下来在大部分静态页面上都能稳定跑。import time import random import requests from bs4 import BeautifulSoup HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, } def safe_get(url, retries3, timeout10): for attempt in range(retries): try: resp requests.get(url, headersHEADERS, timeouttimeout) if resp.status_code 200: return resp print(fHTTP {resp.status_code}: {url}) except requests.RequestException as e: print(f请求异常({attempt 1}): {e}) time.sleep(1.5 * (attempt 1)) return None解析函数用BeautifulSoup的select定位表格行。假设每一行是table classcatalog-table下的tr字段在td里。def parse_catalog_page(html): soup BeautifulSoup(html, html.parser) rows soup.select(table.catalog-table tr) data [] for row in rows[1:]: cells row.find_all(td) if len(cells) 3: continue code cells[0].get_text(stripTrue) name cells[1].get_text(stripTrue) desc cells[2].get_text(stripTrue) data.append({code: code, name: name, desc: desc}) return data这里有个小细节get_text(stripTrue)会把标签内所有文本拼在一起如果单元格里只有纯文本效果很好。但如果单元格里嵌套了span、a标签文本会连在一起比如“计算机、通信和其他电子设备制造业”中间可能出现多个空格strip属性只能去掉首尾空白中间的空格还是保留。所以清洗环节还需要再处理一次。拿到每一页的数据后直接append到一个list里最后统一转成DataFrame导出CSV。分页循环的工作量不大把URL模板化range遍历页码即可。为了避免给目标站点造成压力我一般在每页请求之间加0.5到1秒的随机延迟而不是死循环快速抓。2.3 反爬应对策略与请求头伪装很多人问为什么我模拟了请求头还是被拒绝访问。最常见的原因是请求头不完整只放了User-Agent缺少Accept、Accept-Language这些常见头。服务器会校验请求是否来自真实浏览器请求头里只有User-Agent反而更像机器人。我的做法是尽量让请求头看起来像一个正常浏览器的组合。比如Accept要包含text/html因为这是页面响应类型Accept-Language要写中文环境。如果页面需要登录还要处理Cookie这个项目里因为是公开目录页不需要登录所以简单很多。第二个容易被忽略的问题是访问频率。即使每页随机延迟0.5秒如果一次性把200页全部抓完还是可能触发频率限制。我当时的策略是每爬20页就暂停5秒钟如果发现连续三个请求都返回非200状态码就停止爬取等5分钟再继续。这种“熔断式”设计可以在不改代码的情况下保护目标站点也保护自己的IP不被封。第三如果目标页面已经过了服务端渲染阶段而是用了异步加载那么直接解析HTML是拿不到数据的。这时候要用开发者工具的Network面板找到实际的JSON接口再去请求那个接口。接口返回的数据往往比HTML表格更干净解析起来反而容易。后面做增量更新的时候也可以直接对比接口返回的版本号判断数据有没有变化。3. 数据清洗与映射逻辑构建3.1 清洗规则别小看空格和括号原始数据拿到手之后第一件事绝对不是匹配而是清洗。我当时清洗和标准化的时候发现来源名称里的脏数据主要有这么几类第一类是空白字符问题。有些名称里带着全角空格、换行符、制表符比如“软件 开发”中间有个全角空格strip()处理不掉要用replace把所有空白字符替换成空或者用正则\s统一压缩成单个空格。第二类是括号问题。部分来源名称带英文括号或者中文括号比如“计算机及外围设备制造含耗材”。这种带括号的信息有时是附加说明有时却是分类的关键区别。我的处理方式是先把括号内的内容单独提取出来看它是否会影响映射判断。如果某个标准名称本身也带同样的括号内容就保留后再匹配否则把括号内容摘掉用主体名称去匹配。第三类是前后缀问题。有些数据源会在名称前面加编号比如“C39 计算机、通信和其他电子设备制造业”这里“C39”是编码但名称里也带着匹配时如果不先剥离编码就会全部失灵。我当时的清洗函数大致是这样import re def clean_name(raw): if not isinstance(raw, str): return s raw.strip() s re.sub(r\s, , s) s re.sub(r\[.*?\], , s) s re.sub(r.*?, , s) s re.sub(r\(.*?\), , s) s re.sub(r^\d{1,4}\s*, , s) s re.sub(r^[A-Z]{1,2}\d{0,4}\s*, , s) return s注意这里去括号的逻辑比较粗暴会丢掉括号里的限定词。比如“软件开发偏金融方向”如果直接去掉括号就变成“软件开发”可能跟标准分类里的“软件开发”匹配上但业务含义已经有偏差。所以更稳妥的做法是保留一个“原始名称”字段清洗后的名称仅用于匹配最终对照表里同时展示干净名称和来源原始名称。3.2 名称标准化与相似度匹配清洗完了接下来就是把每一个来源名称映射到标准编码上。最理想的情况是精确匹配也就是来源名称跟标准名称完全一样或者去掉噪声后完全一样。但现实里大量名称是“既像又不完全像”这时候就要靠模糊匹配。模糊匹配我用的库是thefuzz它底层是基于Levenshtein距离做相似度评分。用法很简单from thefuzz import fuzz def match_name(source_clean, std_names): best_score 0 best_idx -1 for i, std_name in enumerate(std_names): score fuzz.WRatio(source_clean, std_name) if score best_score: best_score score best_idx i return best_idx, best_score但这里有个坑WRatio对短文本的匹配很不友好。比如“银行业”和“软件业”两者长度都很短可能因为都有“业”字拿到70分以上的相似度但实际完全不是一回事。所以我的做法是先加一道规则过滤如果两个字符串的公共前缀长度为零或者公共子串长度小于2直接跳过该候选哪怕分数再高也不认。另外模糊匹配不能只看最高分。我设置了一个三段阈值相似度≥85自动映射标记为“高置信自动匹配”相似度在60到84之间生成候选映射但不自动写入正式对照表需要人工审核相似度60认为是新名称放入“未匹配清单”留待后续处理。这个阈值不是拍脑袋定的。我拿一批手工标注过的样本先跑了交叉验证发现85以上的错误率低于1%60到84区间的错误率在8%左右。如果你换了数据源最好也先抽100条记录人工标注跑一遍不同阈值下的准确率再决定用多少不要直接抄网上的参数。3.3 对照表字段设计与人工审核闭环一张能用的对照表绝不只是“来源名称”和“标准名称”两列。我当时设计的字段结构是字段名说明source_name来源系统里的原始行业名称clean_name清洗后的名称用于匹配source_system这个名称来自哪个数据源或子系统std_code匹配上的标准编码std_name标准编码对应的标准名称match_method精确匹配、模糊匹配、人工确认confidence置信度0到100reviewed是否已经人工审核review_note审核备注updated_at最近更新时间这样设计有几个好处。第一任何一条映射都能回溯看到它来自哪个系统、用的什么匹配方法。第二置信度字段方便后续做数据质量监控。第三reviewed字段可以直接配合一个简单审核页面让业务同学把低置信度的记录批量处理掉。人工审核闭环是这样的脚本每天跑完生成两份文件一份是“自动确认映射表”一份是“待人工审核映射表”。审核表里只保留置信度在60到84之间的记录按来源系统分组一个人审核几十条就够。审核结果直接更新到数据库对应的reviewed字段第二天脚本不会再去动这些已经被人工确认的记录。这样既能自动化又不至于完全黑盒领导问起来也有据可查。4. 自动化调度与增量更新4.1 为什么手动跑一次不够最初版本其实只是一个单次运行的脚本输入爬虫结果输出对照表。但我用了大概两周就发现问题了业务系统的行业字段不是死的每个月都有新的录入外部数据源也会调整分类名称比如原来叫“电子商务”的类目后来改成了“互联网零售及相关服务”。如果对照表不更新新的名称就会掉进“未匹配清单”匹配率每月降几个点然后又得手工补一批。所以这个项目必须做成自动化。我选APScheduler而不是直接用操作系统的cron主要原因是脚本会跑多步任务爬取目录页、爬取标签页、清洗、匹配、生成报告。如果中途某一步挂了需要重试和报警APScheduler能把这些逻辑写在同一个Python进程里比写shell脚本调cron更灵活。当然如果你只跑一台Linux服务器用cron也不是不行只是多步编排和异常处理会更麻烦。4.2 APScheduler定时任务的落地写法APScheduler的使用核心是创建一个调度器然后注册一个任务。我当时的写法是这样from apscheduler.schedulers.blocking import BlockingScheduler from apscheduler.triggers.cron import CronTrigger def daily_update(): print(开始每日产业分类对照表更新) try: crawl_and_clean() build_mapping() export_reports() print(更新完成) except Exception as e: send_alert(f对照表更新失败: {e}) scheduler BlockingScheduler() scheduler.add_job( daily_update, triggerCronTrigger(hour2, minute30), iddaily_industry_mapping, replace_existingTrue, ) scheduler.start()凌晨两点半跑是因为这个时间段目标站点的访问压力最小而且不影响白天业务使用查询。如果你用的是云服务器注意时区问题APScheduler默认使用本地时区部署前要确认服务器时区跟你预期一致。定时任务里每一步最好都写日志。我当时的日志文件按天滚动每次执行会记录爬了多少页、新增多少来源名称、精确匹配率是多少、模糊匹配率是多少。有了这些日志数据质量下滑的时候能第一时间定位是哪个环节出了问题。4.3 增量更新与历史归档增量更新的核心是识别“新增了哪些来源名称”。我实现的方式很简单每次爬到的数据先全量清洗再跟数据库里已有的source_name source_system做对比如果组合不存在就作为新增记录插入如果已存在但clean_name变了就作为变更记录更新如果没有任何变化就跳过。这里有个容易忽略的问题发布字段。对照表下游可能有BI报表在引用如果直接删掉某个旧的编码映射报表会突然出现大量空值。所以我保留了一张历史映射表每次更新前把当前有效映射快照写入历史表并打上valid_to时间戳。这样即使某条映射后来被废弃也能追溯当时报表是用哪个口径统计的。增量更新不一定需要每次都全量重爬。如果目标数据源提供“最近更新列表”接口可以直接抓增量。但如果接口版本经常变动反而增加维护成本。我当时是折中方案目录页每周拉一次全量因为标准分类不会经常变标签页每天拉增量因为企业标签每天都在新增。两种频率分开管理效果比统一每天全量好很多。5. 踩坑实录与排查技巧5.1 常见问题速查表整理一下这个项目里最常遇到的几个问题以及对应的排查思路方便你直接对照现象可能原因排查与解决方式请求返回200但解析结果为空页面数据是异步加载或者表格class选择器不匹配打开开发者工具查看实际DOM结构确认数据是否在接口里部分记录匹配到错误的行业清洗规则去掉了关键限定词或模糊匹配阈值过低抽查错误样本检查清洗函数是否误删支架内容调整阈值每次运行结果不一样数据源更新或者分页总数统计逻辑不稳定记录上次运行的数据量对比本次差异检查分页判断逻辑定时任务运行没输出调度器被阻塞或进程被服务器杀掉了检查进程是否存活用supervisor或systemd守护进程中文乱码页面编码不是UTF-8在requests的response中检查apparent_encoding手动设定编码5.2 我印象最深的三个错误第一个错误是没处理全角括号。当时代码里用的去括号正则只覆盖了英文括号\(\)碰到的来源名称里大量出现中文括号消费者金融。结果就是一百多条记录全部匹配失败全部进了未匹配清单。我花了两个小时才发现是这个问题。后来我养成了一个习惯任何清洗操作都同时跑两遍一遍英文括号一遍中文括号。第二个错误是模糊匹配没有做“公共子串”过滤。用thefuzz做全量匹配跑出来一条很有趣的错误来源名称“网络借贷服务”匹配到了标准名称“互联网广告服务”因为两个字符串都有“联网”“服务”这些片段相似度被拉高到了78。如果没有公共子串过滤这种错误映射很容易混进人工审核名单。后来我加了前缀和公共子串校验错误率明显下降。第三个错误是数据库去重逻辑不完整。我最初判断“新增记录”只看source_name忽略source_system结果两个子系统里都有“信息技术服务”这个名称第二条被当成重复条直接跳过。但这两个子系统后续对“信息技术服务”的范围定义不一样需要分别维护。改成用source_name source_system作为唯一键之后问题解决。5.3 结果校验与数据质量验收自动化跑完不能只看“跑了没”还要看“跑得对不对”。我定义了一个数据质量报告每天输出四个指标精确匹配率、模糊匹配率、未匹配率、人工审核完成率。精确匹配率 精确匹配的记录数 / 总记录数。理想情况应该在70%以上如果低于这个值通常说明清洗规则还没有把噪声去掉。模糊匹配率 模糊匹配并自动高置信确认的记录数 / 总记录数。未匹配率是最需要关注的指标如果它突然升高就可能是有新的命名体系出现需要去新增标准分类或者扩充同义词库。我还会随机抽查10条自动匹配的结果人工确认对应关系是否正确。抽查的原则是高置信度记录每50条抽1条低置信度记录每5条抽1条。抽查结果如果发现错误就回退对应的自动映射把该批记录标记为待审核然后调整打分规则。验收通过后对照表发布到内部数据平台。发布前会做一次全量对比确认这次的映射结果与上次相比没有大规模不合理的变更。如果某个标准编码的映射数量波动超过10%系统会在报告里单独标红提示防止因为清洗规则变更导致全表口径漂移。这个项目做完以后我再处理其他字段的标准化问题就顺手很多。其实产业分类标准化只是一个典型场景当你面对的是“来源系统里有一堆叫法不完全一致的文本型字段”这套爬虫加清洗加映射加定时更新的思路完全可以直接复用。我个人在实践中最大的体会是不要一上来就追求全自动、全高置信先把稳定的精确匹配跑通再逐步引入模糊匹配和人工审核闭环每一步都能控住质量最后的结果才真正敢让下游业务用。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号