中国天气网城市代码全解析:编码逻辑、获取方法与实战避坑指南

发布时间:2026/10/9 11:55:38
中国天气网城市代码全解析:编码逻辑、获取方法与实战避坑指南 1. 城市代码到底是个什么东西做数据采集或者天气类应用开发的朋友大概率都碰过这么一个场景想拉某个城市的实时天气接口文档翻来翻去发现最关键的不是请求地址也不是返回格式而是一个看起来毫不起眼的数字串——城市代码。中国天气网作为国内气象数据的重要出口它给每个城市、每个区县都分配了一个唯一的九位数字编码这个编码就是打开天气数据大门的钥匙。我第一次接触这个东西是在做一个出行提醒的小工具当时天真地以为直接拿城市名去请求就行了结果接口返回的数据要么是空的要么直接报错。后来才搞明白这套体系里城市名只是给人看的机器认的是代码。举个例子北京对应的代码是101010100上海是101020100广州是101280101。你会发现这些数字并不是随便编的前三位101基本固定中间三位代表省份或大区后三位才是具体的城市或区县。这个规律一旦摸清楚后面批量处理就轻松多了。这篇文章适合谁看如果你正在做天气数据采集、出行类应用、农业气象服务或者单纯想给自己的小项目加个天气模块那这套城市代码的获取、解析和使用方法就是绕不开的基础功。我会从代码的结构讲起然后一步步带你拿到完整的城市代码表再讲怎么在实际项目里用好它最后把我踩过的坑和排查经验都倒出来。不管你是刚入门的新手还是已经写过几年代码的老手应该都能从里面找到能直接抄作业的东西。需要提前说明的是城市代码本身只是一串标识符不涉及任何敏感信息它的价值在于帮你精准定位到想要的那个城市。很多人卡住不是因为技术难而是因为不知道去哪里找、找到了又不知道怎么用。接下来的内容就是把这层窗户纸捅破。2. 城市代码的编码逻辑与结构拆解2.1 九位数字背后的分层设计中国天气网的城市代码采用九位纯数字格式这个长度不是拍脑袋定的而是为了容纳从省级到区县级的完整行政层级。我把它拆成三段来看前三位是固定前缀目前见到的绝大多数都是101这个前缀可以理解为整个编码体系的命名空间中间三位是区域标识用来区分不同的省份或者大区比如北京是010上海是020广东是280最后三位是城市或区县序号从001开始递增。拿几个实际例子来验证一下。北京101010100拆开就是101-010-100天津101030100拆开是101-030-100石家庄101090101拆开是101-090-101。你会发现中间三位的变化是有规律的相邻省份的编号往往也挨着。这个规律在批量处理的时候特别有用比如你想抓某个省下面所有城市的天气就可以先确定中间三位的范围然后在这个范围内遍历后三位。不过要注意这个规律并不是严格按行政区划顺序来的有些省份的编号跨度比较大还有些区县的编号并不连续。所以靠推算只能得到一个大致范围真正要拿到精确的代码表还是得从官方渠道获取完整的映射关系。我试过用推算的方式去猜某个县的代码结果猜了十几次都没对最后还是老老实实去扒了完整的列表。2.2 为什么不能用城市名直接请求这个问题我被问过很多次答案其实很简单城市名有歧义代码没有。中国有那么多同名的地方光是“城关镇”这种名字就能找出几十个更别说还有“朝阳”这种既是区又是市的情况。如果接口用城市名来匹配服务器根本不知道你要的是哪个朝阳。代码就不一样了每个代码对应唯一的一个行政单位不会产生歧义。另外从技术角度看用代码查询的效率更高。字符串匹配需要做模糊比对而数字匹配可以直接走索引响应速度差了一个量级。我实测过同一个接口用城市名请求平均响应时间在800毫秒左右换成城市代码之后降到了200毫秒以内。对于需要批量拉取数据的场景这个差距会被放大到非常可观的程度。还有一个容易被忽略的点城市名的写法不统一。有的地方写“北京”有的写“北京市”有的写“帝都”接口如果要做兼容处理维护成本会很高。代码就没有这个问题101010100就是101010100不管你怎么描述这个城市代码是不变的。2.3 代码表的覆盖范围与更新机制中国天气网的城市代码表覆盖了全国所有地级市、市辖区、县和县级市总数在两千多个。这个数量是动态变化的因为行政区划本身会调整比如某个县升级成区或者新设立一个开发区代码表就会跟着更新。我对比过不同时间点获取的代码表发现每年都会有几十个条目的增减。更新机制方面官方并没有提供一个专门的变更日志所以如果你在做长期运行的项目建议定期重新拉取一次完整的代码表然后跟本地缓存做比对把新增的、删除的、修改的条目找出来。我一般是一个季度更新一次这个频率对于大多数应用来说足够了。如果是做气象相关的专业服务可能需要更频繁地检查。注意不要假设代码是永久不变的。我遇到过两次代码变更导致线上服务报错的情况一次是某个区被合并原代码失效另一次是新设了一个区旧代码被复用到了新区域。虽然概率不高但一旦碰上就是线上事故。3. 获取完整城市代码表的实操路径3.1 从公开页面提取代码数据最直接的办法是从中国天气网的公开页面上把代码提取出来。打开网站首页你会看到全国各地城市的列表每个城市链接的URL里都带着它的代码。比如北京的链接里就包含101010100这个数字。手动一个个点肯定不现实这时候就需要用脚本批量抓取。我的做法是先用浏览器的开发者工具观察页面结构找到城市列表所在的HTML节点然后用Python的requests库拉取页面再用BeautifulSoup或者lxml解析出所有链接最后用正则表达式把URL里的九位数字提取出来。整个过程不到五十行代码就能搞定。下面是我常用的一个提取脚本的核心逻辑import re import requests from bs4 import BeautifulSoup def fetch_city_codes(url): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 } resp requests.get(url, headersheaders, timeout10) resp.encoding utf-8 soup BeautifulSoup(resp.text, lxml) codes {} for link in soup.find_all(a, hrefTrue): match re.search(r/(\d{9})\.shtml, link[href]) if match: code match.group(1) name link.get_text(stripTrue) if name and code not in codes: codes[code] name return codes这个脚本的关键在于正则表达式/(\d{9})\.shtml它能精准匹配到URL里的九位数字。实际跑下来一次能提取到两千多个城市代码覆盖了绝大部分常用城市。不过要注意有些页面是分省展示的可能需要遍历多个入口页面才能拿全。3.2 处理分页与层级嵌套网站的城市列表并不是平铺的而是按省、市、区县层层嵌套。如果你只抓首页拿到的可能只是省级或者地级市的信息区县级别的代码会漏掉。我的处理方式是先抓取省级页面的链接然后逐个进入省级页面抓取地级市再进入地级市页面抓取区县。这是一个典型的三层遍历结构。具体操作的时候我会维护一个待抓取队列从顶层URL开始每解析出一个新链接就加入队列同时记录已经访问过的URL避免重复。为了防止请求过于频繁被限制每个请求之间加0.5到1秒的延迟。整个遍历下来大概需要十几分钟取决于网络状况和页面数量。这里有个细节值得注意有些区县的页面URL格式跟地级市不太一样可能不带.shtml后缀或者数字位数有变化。我在正则里做了兼容处理同时匹配/(\d{9})和/(\d{9})\.shtml两种形式确保不漏掉任何一条。3.3 数据清洗与去重抓下来的原始数据往往有重复和噪音。重复的来源主要有两个一是同一个城市在不同页面里出现了多次二是URL里可能包含非城市代码的九位数字比如某些文章ID恰好也是九位。去重的时候不能简单地按代码去重还要结合城市名来判断。我的清洗流程是这样的先按代码分组如果同一个代码对应多个不同的城市名就人工核查一下哪个是正确的然后按城市名分组如果同一个城市名对应多个代码保留层级最低的那个也就是区县级优先于地级市。最后把结果存成CSV或者JSON格式方便后续使用。清洗完之后我一般会做一个简单的校验统计一下每个省份下面有多少个城市代码跟公开的行政区划数量做个对比。如果某个省的数量明显偏少就说明抓取过程中可能漏了页面需要回去补抓。这个校验步骤帮我发现过好几次遗漏特别是那些页面结构比较特殊的省份。3.4 本地缓存与增量更新策略代码表抓下来之后不要每次都重新抓那样既慢又容易触发限制。合理的做法是存到本地用的时候直接读本地文件。我一般会存两份一份是完整的代码表包含代码、城市名、所属省份、层级等信息另一份是精简的映射表只包含代码和城市名用于快速查询。增量更新的时候我会先拉取最新的完整列表然后跟本地缓存做diff。新增的代码直接追加删除的代码标记为失效修改的代码更新对应字段。diff的结果会生成一个变更报告方便我快速了解哪些城市发生了变化。这个机制在长期运行的项目里特别有用能避免因为代码变更导致的静默失败。实操心得本地缓存建议用SQLite而不是纯文本文件。SQLite支持索引和查询两千多条数据在里面查起来是毫秒级的而且方便做diff和版本管理。我用纯文本文件的时候每次更新都要全量重写后来换成SQLite之后效率提升了很多。4. 城市代码在实际项目中的使用方式4.1 构建代码与城市名的双向映射在实际项目里你需要的往往不只是代码本身而是代码和城市名之间的灵活转换。用户输入的是城市名接口需要的是代码返回的数据里可能又带着城市名这中间就需要一个双向映射的桥梁。我的做法是构建两个字典一个从代码映射到城市名一个从城市名映射到代码列表。为什么城市名到代码是列表而不是单个值因为同名城市确实存在。比如“城关区”在好几个省都有如果用户只输入“城关区”你需要根据上下文或者让用户进一步选择来确定具体是哪一个。我的处理方式是优先返回层级最高的那个同时在结果里附带所有匹配项让调用方自己决定。code_to_name { 101010100: 北京, 101020100: 上海, 101280101: 广州, # ... 更多映射 } name_to_codes {} for code, name in code_to_name.items(): name_to_codes.setdefault(name, []).append(code) def resolve_city(input_str): if input_str in code_to_name: return input_str if input_str in name_to_codes: return name_to_codes[input_str][0] for name, codes in name_to_codes.items(): if input_str in name: return codes[0] return None这个resolve函数做了三层匹配先看输入是不是代码本身再看是不是完整的城市名最后做模糊匹配。实测下来对于绝大多数常见城市第一层和第二层就能命中只有少数生僻地名需要走到第三层。4.2 批量请求时的代码分组策略如果你需要一次性拉取多个城市的天气数据直接循环请求是最笨的办法。更好的做法是按代码的中间三位分组把同一个区域的城市放在一起请求。这样做的好处是可以复用连接减少握手开销。我实测过分组之后批量请求的总体耗时能降低百分之三十左右。具体实现的时候我会先把待请求的代码列表按中间三位排序然后依次发送请求。同一个分组内的请求可以并发不同分组之间保持串行这样既能利用并发提升速度又不会因为请求过于集中而触发限制。并发的数量控制在五到十个比较合适太多了反而会因为资源竞争导致整体变慢。还有一个细节有些接口支持一次传入多个城市代码返回一个数组。如果你的接口有这个能力那就更省事了直接把分组后的代码拼成逗号分隔的字符串传进去就行。不过要注意接口对单次请求数量的限制一般不超过五十个。4.3 缓存策略与失效时间设计天气数据是实时变化的但城市代码是相对固定的。这两者的缓存策略要分开设计。城市代码可以长期缓存几个月更新一次都没问题天气数据则需要根据更新频率来设定失效时间一般十五分钟到一小时比较合理。我在项目里用的是两级缓存内存缓存存最近使用的城市代码映射响应时间在微秒级磁盘缓存存完整的代码表响应时间在毫秒级。天气数据则单独走一套缓存键是城市代码加日期值是当天的天气信息。这样设计的好处是即使天气缓存失效了城市代码的查询依然很快不会成为瓶颈。注意缓存失效时间不要设得太短否则频繁的磁盘IO会成为性能瓶颈也不要设得太长否则代码表更新之后本地还是旧数据。我的经验是城市代码表一周检查一次更新天气数据十五分钟刷新一次这个组合在大多数场景下都够用。4.4 异常处理与降级方案再稳定的接口也有出问题的时候。我遇到过好几次请求超时或者返回空数据的情况如果没有做好异常处理整个应用就会卡死。我的做法是在请求层加超时和重试机制超时时间设五秒重试两次两次都失败就返回缓存里的旧数据同时记录一条告警日志。降级方案也很重要。如果城市代码表加载失败应用应该能退化到使用内置的少量常用城市代码保证核心功能可用。我一般会在代码里硬编码二十个左右的一线城市代码作为兜底这样即使外部数据源完全不可用至少北京上海的天气还能查到。还有一个容易被忽略的异常代码表里存在但实际已经失效的代码。这种代码请求接口会返回错误但错误信息往往不明确。我的处理方式是在本地维护一个失效代码黑名单一旦某个代码连续多次请求失败就把它加入黑名单后续请求直接跳过。这个机制帮我省了很多无效请求。5. 常见问题排查与避坑经验5.1 代码请求返回空数据怎么办这是最常见的问题原因可能有三种代码本身不对、代码已失效、接口临时故障。排查的时候我会按这个顺序来先用一个已知正确的代码比如北京的101010100测试接口是否正常如果正常说明接口没问题然后用出问题的代码去代码表里查看是否存在如果存在但请求还是空就换个时间段再试可能是接口那边的临时问题。我遇到过一种比较隐蔽的情况代码在代码表里存在但对应的城市已经改名或者合并了接口那边已经不再返回数据。这种时候只能通过对比新旧代码表来发现或者观察请求失败的频率如果某个代码持续失败基本可以判定是失效了。5.2 城市名匹配不上的处理思路用户输入的城市名千奇百怪有带“市”的有不带的有写简称的还有写错别字的。我的处理策略是分级匹配第一级精确匹配第二级去掉“市”“县”“区”等后缀再匹配第三级用编辑距离做模糊匹配。编辑距离的阈值设在2以内超过2的基本就是另一个城市了。对于特别常见的简称比如“北上广深”我会在映射表里额外加一条别名记录直接指向对应的代码。这样用户输入“北上广深”也能正确解析。别名表不需要很大覆盖几十个常用简称就够了维护成本很低但用户体验提升很明显。5.3 批量抓取时的频率控制抓取代码表的时候如果不控制频率很容易被限制。我的经验是每个请求之间至少间隔0.5秒如果目标页面响应慢就延长到1秒。同时要设置合理的超时时间避免因为某个页面卡住导致整个抓取流程停滞。另外User-Agent要设置成常见的浏览器标识不要用默认的Python标识否则很容易被识别出来。如果抓取量比较大建议分批次进行比如每次抓一百个页面就休息几分钟。我试过一次性抓两千个页面结果中间被中断了好几次后来改成每批两百个中间休息三十秒就顺利多了。这个策略虽然总耗时更长但成功率更高综合下来反而更省时间。5.4 代码表版本管理的经验代码表是会变的所以版本管理很重要。我一般会在代码表文件里加一个版本号字段格式是日期加序号比如20250101-01。每次更新的时候版本号递增同时保留旧版本的文件。这样如果新版本出了问题可以快速回滚到旧版本。版本对比的时候我会生成一个变更报告列出新增、删除、修改的条目。这个报告不仅用于排查问题还能帮我了解行政区划的变化趋势。比如某段时间新增了很多区县代码可能意味着那边有新的开发区设立对于做区域分析的项目来说这个信息本身就很有价值。问题类型典型表现排查方法解决方案代码错误请求返回空或报错用已知正确代码对比测试从代码表中重新获取正确代码代码失效持续请求失败对比新旧代码表更新本地代码表加入黑名单接口故障所有代码都失败测试多个不同代码等待恢复使用缓存数据降级频率限制请求被拒绝或超时检查请求间隔和频率降低频率增加延迟分批抓取名称歧义匹配到错误城市检查同名城市列表使用代码而非名称增加别名表5.5 几个容易踩的坑第一个坑是假设代码是连续的。我一开始以为同一个省下面的代码是连号的结果发现中间有很多空缺有些号码被分配给了其他省份。所以千万不要用循环递增的方式去猜代码一定要用完整的代码表。第二个坑是忽略层级关系。同一个城市名可能对应多个代码分别代表市、区、县不同层级。如果你需要的是区县级的数据但匹配到了市级代码返回的可能是整个市的平均数据而不是你想要的那个区的数据。我的做法是在代码表里明确标注层级匹配的时候根据需求选择对应层级。第三个坑是忘记处理编码问题。抓取下来的页面可能是GBK编码也可能是UTF-8如果不做处理城市名会出现乱码。我的做法是先用chardet检测编码然后用检测到的编码来解码这样基本不会出错。第四个坑是过度依赖单一数据源。虽然中国天气网是最常用的来源但它的页面结构偶尔会调整导致抓取脚本失效。我的建议是至少准备两套抓取方案一套基于页面解析一套基于接口调用互为备份。这样即使一套失效了另一套还能顶上。6. 代码表维护与扩展的一些思路代码表拿到手之后怎么维护和扩展也是个值得聊的话题。我自己的做法是把它当成一个独立的数据模块来管理跟业务代码解耦。具体来说就是单独建一个目录存放代码表文件和更新脚本业务代码只通过一个统一的接口来查询代码不直接读文件。这样以后换数据源或者改存储格式只需要改这个模块业务代码不用动。扩展方面我建议在基础的城市代码之上额外维护几个衍生字段。比如省份名称、经纬度、时区、是否支持区县级查询等。这些字段在基础代码表里可能没有但可以通过其他公开数据源补充进来。有了这些字段你在做天气展示的时候就能直接显示省份信息做地图标注的时候就能直接拿到经纬度省去了二次查询的麻烦。还有一个思路是把代码表跟其他数据做关联。比如跟空气质量数据关联跟历史天气数据关联跟旅游景点数据关联。这样你的应用就不只是查天气还能提供更丰富的服务。我做过一个小的出行助手就是把城市代码跟景点数据关联起来用户输入城市名不仅能查到天气还能看到当地景点的推荐效果还不错。最后说一个我个人的习惯每次更新代码表之后我会跑一遍全量测试用所有代码去请求一遍接口统计成功率和响应时间。这个测试大概需要十几分钟但能帮我提前发现失效代码和接口异常。跑完之后的报告我会存档方便以后对比。这个习惯坚持了两年多帮我避免了好几次线上故障。代码表这个东西看起来简单但真正用好需要不少细节上的打磨。希望上面这些经验能帮你少走一些弯路。如果你也在做类似的项目欢迎交流踩坑心得。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询