首页/新闻资讯/正文详情

Python采集中国天气网天气数据:JSON接口与城市ID实战

发布时间:2026/9/25 7:35:42 来源:云帆数科 栏目:资讯中心
Python采集中国天气网天气数据:JSON接口与城市ID实战
简介资源包内含一套基于Visual Studio 2008的C# Windows Forms完整工程面向需要接入中国天气网公开API的初级开发者解决从构造HTTP请求、解析JSON/XML到界面展示的关键流程。压缩包共34个文件主要包括9个.cs源码文件、3个.dll库文件、3个.exe可执行程序以及配置文件、资源文件和项目工程文件整体仅259KB结构精简便于运行调试。已有2308人学习下载。工程演示了通过HttpWebRequest发送请求并接收响应使用JavaScriptSerializer解析JSON或用XDocument处理XML同时说明API密钥注册与管理要点。代码封装了天气数据获取方法能够提取温度、湿度、风向等信息并配有Windows窗体界面示例可快速迁移到其他项目。对刚接触网络编程或想基于VS2008实现天气功能的读者这是一份可运行、可参考的实战模板。1. 中国天气网获取天气数据不靠解析 HTML靠的是它藏在 JS 里的 JSON 接口“中国天气网获取天气数据”这件事最容易被新手带偏的地方是一上来就对着www.weather.com.cn的 HTML 页面写正则。实际做过一轮就会明白页面结构半年能改三次而藏在页面背后的 JSON 接口和内嵌 JS 变量反而稳定得多。这篇文章要讲的是一条我自己跑通过的路线——先用城市 ID 锁定目标再分别拿实时数据、今日概况和七天预报最后把采集做成带重试、校验和存储的小任务。适合谁要做天气展示页面、气象数据分析、本地小仪表盘又不想接付费天气 API 的开发者。后面所有代码基于 Python 3.8依赖只有requests和beautifulsoup4。2. 先搞懂中国天气网的数据源城市 ID 和三个关键接口2.1 城市 ID 从哪来页面、JS 文件与 city3jdata 三级接口中国天气网所有天气数据的入口都不是城市名而是一个 9 位数字城市 ID比如北京是101010100上海是101020100。网页端搜索框输入“海淀”跳转到的 URL 里就是101010200之类的 ID。9 位 ID 的常见规则是前三位101固定接着两位省代码、两位市代码、两位区县代码。但这条规则只适合做校验不适合直接拼——直辖市、省直辖县级市、新设立的区经常不按连号走手拼出来的 ID 有一半是查不到数据的。安全的做法是用网站自身的分级接口去查。城市数据分三级省份、地级市、区县对应三个接口import requests headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36 } # 第一级省份列表返回 {01: 北京, 02: 上海, ...} province_resp requests.get( http://www.weather.com.cn/data/city3jdata/province.html, headersheaders, timeout10 ) provinces province_resp.json() print(provinces[01]) # 北京 # 第二级某省份下的城市返回 {0101: 北京, ...} city_resp requests.get( fhttp://www.weather.com.cn/data/city3jdata/stat/{01}.html, headersheaders, timeout10 ) cities city_resp.json() print(cities[0101]) # 北京 # 第三级某城市下的区县返回 {0101: 海淀, ...} station_resp requests.get( fhttp://www.weather.com.cn/data/city3jdata/station/{0101}.html, headersheaders, timeout10 ) stations station_resp.json() print(stations[0101]) # 海淀这段代码的逻辑是逐级往下查每一级返回的都是{代码: 名称}的 JSON 对象。省代码是两位市代码是省代码加城市两位区县代码是市代码加区县两位。最终拼成城市 ID 时规则是101 省代码 市代码 区县代码。用上面的例子101010101对应海淀101010101但海淀在网页端的实际 ID 是101010200说明第三级 station 返回的区县代码和实际数据服务 ID 并不总是一一对应。所以这个接口真正可靠的用法是拿前两级确认省和市区县一级只作参考最终 ID 以页面 URL 里的为准。2.2 三个核心接口实时天气、今日概况与七天预报拿到城市 ID 之后数据接口分三类覆盖不同需求接口 path返回内容适合用途注意点/data/sk/{city_id}.html实时温度、风向、风力、湿度、气压仪表盘实时显示老接口字段名是 WD/WS 这种缩写/data/cityinfo/{city_id}.html今日最高/最低温、天气现象、发布时间今日概览卡片temp1 是最低温temp2 是最高温容易写反/weather/{city_id}.shtml七天预报完整页面七天趋势数据在页面内嵌 JS 变量里需要正则提取实时接口和概况接口返回的是标准 JSON七天预报的.shtml是一个完整 HTML 页面数据不在 HTML 标签里而是嵌在script标签的 JS 变量中。这个差异决定了后面解析方式完全不同前两个用resp.json()一步到位七天预报需要用正则先取出 JS 变量再json.loads。这三个接口都不需要登录、不需要 token、不需要签名参数唯一的硬性要求是请求头里带一个正常的User-Agent。不带 UA 的请求偶尔会返回 200 但内容为空这是网站反爬最轻的一层骗过它不需要什么技巧。2.3 为什么选 JSON 接口而不是直接解析 HTML很多人第一次做这个需求下意识就去抓http://www.weather.com.cn/weather/101010100.shtml然后在 BeautifulSoup 里找.tem、.win这些 class。这个方案的致命问题不是写不出来而是维护不住页面改版一次class 名换一批你的解析代码就要重写。JSON 接口的字段虽然也变但变动频率低得多而且老接口即便字段冗余也不会随意删。另一个维度是请求体积。一个.shtml页面加图片、广告占位、统计脚本动辄几十 KB而/data/sk/接口返回的 JSON 只有几百字节。如果你要监控几十个城市JSON 接口在带宽和解析耗时上的优势是量级的。后面所有的实现都基于这个选型能拿 JSON 就不碰 HTML页面只用来提取七天预报里那段 JS 变量。3. 用 Python 跑通最小采集脚本从城市 ID 到天气 JSON 落盘3.1 先写一个查城市 ID 的工具函数实际项目中我不会每次运行都去查三级接口城市的 ID 变化不频繁查一次存成本地配置文件更合理。但第一次写脚本时这个工具函数能帮忙确认手头 ID 是否有效。把上一步的三级查询包成一个函数import requests HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36 } def query_city_id(province_code: str, city_code: str) - str: 根据省市代码拼出9位城市ID并验证该ID是否有实时数据。 base f101{province_code}{city_code}00 # 用实时接口做验证404或报错说明ID不可用 check_url fhttp://www.weather.com.cn/data/sk/{base}.html resp requests.get(check_url, headersHEADERS, timeout10) if resp.status_code ! 200: return None data resp.json() if data.get(weatherinfo, {}).get(cityid) ! base: return None return base print(query_city_id(01, 01)) # 北京 101010100函数参数是两位省代码和两位市代码内部直接拼101 省 市 00然后用实时接口验证。这里有一个容易被忽略的细节北京这种直辖市的区一级代码是00数据挂在它下面普通地级市的市区也是00结尾。校验时拿返回的cityid字段和拼接结果比对能过滤掉一部分“接口返回了 JSON 但实际是错误页”的情况。这个函数返回值如果是None就说明省市代码配错了需要回到 city3jdata 接口去查。3.2 实时天气与今日概况两个最稳的 JSON 接口城市 ID 确定之后采集主体代码只有十几行。下面这版把实时数据和今日概况一起抓下来并打印关键字段import requests import json from datetime import datetime CITY_ID 101010100 # 北京 HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36 } def fetch_weather(city_id: str) - dict: sk_url fhttp://www.weather.com.cn/data/sk/{city_id}.html info_url fhttp://www.weather.com.cn/data/cityinfo/{city_id}.html sk_resp requests.get(sk_url, headersHEADERS, timeout10) sk_resp.encoding utf-8 sk_data sk_resp.json()[weatherinfo] info_resp requests.get(info_url, headersHEADERS, timeout10) info_resp.encoding utf-8 info_data info_resp.json()[weatherinfo] record { city: sk_data[city], cityid: city_id, temp_now: float(sk_data[temp]), # 当前温度 wind_dir: sk_data[WD], # 风向 wind_level: sk_data[WS], # 风力 humidity: sk_data[SD], # 相对湿度 temp_low: info_data[temp1], # 今日最低温 temp_high: info_data[temp2], # 今日最高温 weather: info_data[weather], # 天气现象 fetch_time: datetime.now().isoformat() # 本地采集时间 } return record if __name__ __main__: print(json.dumps(fetch_weather(CITY_ID), ensure_asciiFalse, indent2))这段代码的逻辑分三步请求实时接口、请求概况接口、合并字段。sk_data[temp]返回的是字符串比如23或-8所以转成float方便后续计算。temp1和temp2同样是字符串里面带了单位℃我没有在这里转换因为后面清洗章节会统一处理。这里要解释两个参数timeout10是必须的中国天气网的接口在极端天气时偶尔会慢不设超时会让采集任务挂死resp.encoding utf-8是主动声明编码避免 requests 对部分接口返回的 GBK 内容误判成 Latin-1 导致乱码。如果你在 Windows 终端打印中文乱码通常是终端编码问题不是接口问题把输出重定向到文件检查即可。3.3 七天预报从页面内嵌 JS 变量里提取七天预报没有公开的纯 JSON 接口常规做法是抓.shtml页面然后从页面里的hour3dataJS 变量中提取。这个变量存放未来 48 小时和 7 天趋势的数据结构是城市 ID 作为键里面带weatherList之类的数组。用正则把它抠出来再解析import requests import re import json def fetch_forecast_7d(city_id: str) - list: url fhttp://www.weather.com.cn/weather/{city_id}.shtml resp requests.get(url, headersHEADERS, timeout15) resp.encoding utf-8 html resp.text # 页面内嵌的JS变量包含7天数据 match re.search(rvar hour3data(\{.*?\});, html, re.S) if not match: return [] raw json.loads(match.group(1)) city_key str(city_id) if city_key not in raw: return [] # 从数据里取出7天趋势列表 weather_list raw[city_key].get(weatherList, []) result [] for item in weather_list: result.append({ date: item.get(date, ), temp_low: item.get(low, ), temp_high: item.get(high, ), weather: item.get(wth, ), wind: item.get(wd, ), }) return result if __name__ __main__: for day in fetch_forecast_7d(101010100): print(day)re.search(rvar hour3data(\{.*?\});, html, re.S)这段正则是整个函数最核心的部分\{.*?\}是非贪婪匹配re.S让.能匹配换行符保证 JS 变量跨行也能取全。取出来的字符串是一个 JSON 对象键是城市 ID值里嵌套了weatherList数组。这个提取结果有个坑weatherList里包含的不只是 7 天有些城市会带 6 小时间隔的多组数据打印出来可能超过 7 条。实际使用时要按date字段去重只保留每天最后一条或第一条。另外low和high是纯数字字符串weather是中文描述wd是风向字段名和实时接口完全不一样别套用同一套解析逻辑。4. 把采集脚本升级成数据任务轮询频率、存储与失败重试4.1 轮询频率怎么定气象数据的时效边界能抓到数据之后第一个要决定的是多久跑一次。气象数据有天然的时效边界实时温度每 510 分钟更新一次今日概况每天只在几个固定时间点刷新七天预报每小时全量重算。没必要用同一套频率去刷三个接口我一般按下面的表格配置数据推荐轮询间隔依据实时温度/风力5 分钟数据源本身约 5 分钟刷新一次今日最高/最低温30 分钟一天内只变几次30 分钟足够覆盖七天预报1 小时上游预报每天更新数次小时级足够具体调度我用一个简单的whilesleep循环加时间戳判断不用引入 Celery 这类重框架。如果你要跑在服务器上更稳妥的办法是系统 crontab 或systemd timer这样采集进程崩溃了会被系统拉起而不是靠脚本内部自愈。4.2 存储方案SQLite 一张表 vs CSV 按天分文件数据量小的时候CSV 按天分文件是最直观的方案文件名带日期每天一个文件排查问题方便。但 CSV 有两个问题并发写入会丢数据按日期查询要跨文件。采集任务通常单线程跑并发问题不大可如果你后面要分析历史趋势SQLite 一张表省事得多。我推荐最小化方案SQLite 单表时间戳做主键索引。import sqlite3 from datetime import datetime DB_PATH weather.db def init_db(): conn sqlite3.connect(DB_PATH) conn.execute( CREATE TABLE IF NOT EXISTS weather_hourly ( fetch_time TEXT NOT NULL, city_id TEXT NOT NULL, temp_now REAL, temp_low REAL, temp_high REAL, humidity REAL, wind_dir TEXT, weather TEXT, PRIMARY KEY (fetch_time, city_id) ) ) conn.commit() conn.close() def save_record(record: dict): conn sqlite3.connect(DB_PATH) conn.execute( INSERT OR REPLACE INTO weather_hourly (fetch_time, city_id, temp_now, temp_low, temp_high, humidity, wind_dir, weather) VALUES (?, ?, ?, ?, ?, ?, ?, ?) , ( record[fetch_time], record[cityid], record[temp_now], record[temp_low], record[temp_high], record[humidity], record[wind_dir], record[weather], )) conn.commit() conn.close()INSERT OR REPLACE的语义是如果fetch_time和city_id组合已存在就覆盖整行。这让重跑采集脚本变得安全——重复执行不会产生脏数据只会更新同一条记录。init_db()要在采集启动前调用一次建表语句里的PRIMARY KEY (fetch_time, city_id)同时充当去重约束和查询索引后面查某个城市某天的数据会很快。存储字段的类型值得注意temp_now是 REAL而temp_low、temp_high在 JSON 里带℃后缀存入前必须先清洗成float否则 SQLite 虽然能存但后续AVG、MAX这类聚合函数算出来全是 0。4.3 失败重试与数据校验不能把脏数据写进库网络请求一定会失败这是采集任务里唯一可以提前确定的事。超时、连接重置、对方返回 500都需要重试。但重试不能无脑循环否则对方服务器把你 IP 封了都不知道。我一般用指数退避最多重试三次import time import requests def fetch_with_retry(url: str, headers: dict, max_retries: int 3) - requests.Response: for attempt in range(max_retries): try: resp requests.get(url, headersheaders, timeout10) if resp.status_code 200: return resp except requests.RequestException: pass time.sleep(2 ** attempt) # 第1次等2秒第2次等4秒第3次等8秒 raise RuntimeError(f请求失败: {url})重试逻辑的关键参数是time.sleep(2 ** attempt)第一次失败等 2 秒第二次等 4 秒第三次等 8 秒。这个退避速度对天气数据足够了不会因为间隔太短触发反爬也不会因为间隔太长拖慢任务。如果三次都失败直接抛异常让上层任务记录日志而不是吞掉错误继续往下走。数据校验在入库前做比入库后清洗省事得多。至少校验两点温度值是否在合理区间夏天不可能出现-30冬天不可能出现45以及返回的cityid是否和请求的 ID 一致。校验不通过就丢弃这轮数据等下一个周期自然更新而不是把异常值写进库里以后再花半天排查是从哪来的。5. 天气数据采集避坑5 个让脚本翻车的真实细节5.1 城市 ID 变了接口返回 404还以为是网站改版现象某一天开始/data/sk/{city_id}.html返回 404但城市在网页端能找到天气信息。原因不是网站改版而是部分城市 ID 在实时数据服务里根本不存在。特别是行政区划调整后新设立的区县 ID 在网页端能用但老数据接口还没来得及同步。另一个高频场景是自己按101 省 市 区拼接的 ID拼出来看着合理实际服务端没有对应数据。解决城市 ID 以city3jdata接口逐级查出的为准区县一级不要自己拼用页面 URL 里的实际 ID。启动采集任务前跑一遍探测脚本把失效的 ID 从配置里移除并告警。5.2 返回 200 但内容乱码或空 body现象resp.text打印出来全是或者resp.json()抛出JSONDecodeError但浏览器里打开同 URL 完全正常。原因部分接口在特定网络环境下返回 GBK 编码requests 默认会从响应头猜编码猜错的概率不低。另外一个场景是响应被 gzip 压缩虽然 requests 会自动解压但如果通过代理访问压缩头可能被剥离导致 body 成了二进制乱码。解决显式设置编码优先按响应头里的charset判断没有就退回gbk重试一把。压缩问题先打印resp.headers.get(Content-Encoding)确认再排查代理配置。不要依赖resp.apparent_encoding它对短文本的猜测经常不准。5.3 温度是负值int() 硬转没问题但缺字段会 KeyError现象冬天跑得好好的脚本某天变成KeyError: temp日志里一堆 Traceback。原因天气接口是“有则返回、无则不返回”的规则字段不保证齐全。尤其雷雨、大风等极端天气场景实时接口偶尔会缺失temp或WD字段。用resp.json()[weatherinfo][temp]这种链式访问字段一缺就崩。解决所有字段取值改用.get()并给默认值入库前再做一次字段存在性校验。宁可记录NULL也不要让采集任务死在半路更不要把异常值硬塞进数据库。5.4 d1 接口直接抓返回 403Referer 和时间戳的坑现象用d1.weather.com.cn开头的 JSONP 接口抓数据requests.get()直接 403加 UA、换 IP 都没用。原因d1域名下的接口校验Referer必须来自www.weather.com.cn同时习惯要求带_回调参数。这是专门给网页端 JS 用的接口直接裸请求会被当成非法调用拒绝。解决请求头加Referer: http://www.weather.com.cn/URL 末尾补?_加毫秒时间戳。如果只是做常规天气展示直接用/data/sk/老接口更省事没必要跟d1接口较劲。5.5 凌晨抓到的“今日”还是昨天的数据现象每天 0 点到 6 点之间采集的temp_low、temp_high、weather都是前一天的对比网页端看到的数据也对不上。原因今日概况接口的刷新时间不是自然日零点而是按气象业务节奏走一般在清晨完成当日数据上线。ptime字段数据发布时间能明确看出数据的实际时间戳。解决入库前检查返回的ptime在“今日”字段刷新前不要把采集结果当当日数据写入。两个选择要么采集任务避开 06 点要么把ptime也存进库里让下游自行判断数据新鲜度。我选了后者保留原始时间戳的价值远比省一条记录大。6. 从 JSON 到干净气象表字段清洗与数据校验的最后一公里前面所有代码拿到的都还是“能用但不够规范”的数据温度带单位、字段名不统一、部分值可能是空字符串。如果只做展示直接打印没问题如果要入库做分析必须先清洗成统一格式。我常用的做法是把三个接口的数据合并成一个扁平字典再统一做类型转换。清洗规则有几条temp1和temp2去掉℃后转float同时记住temp1是最低、temp2是最高temp_now直接转float但要做空值判断因为实时接口在极端天气下可能缺这个字段湿度SD去掉%后转float风向WD、风力WS、天气现象weather保持字符串原样但要去掉首尾空格。验证采集数据对不对我有一个土办法把清洗后的温度和time字段打印出来和手机自带天气 App 同城市对比。温差在 12℃ 内是正常的因为气象站位置和温度计不同如果相差 5℃ 以上优先怀疑城市 ID 串了——别笑多城市采集时配置写错城市 ID 是最高频的事故。另一个验证点是交叉验证用/data/sk/的temp和.shtml页面里hour3data的当前温度做比对两个独立数据源一致基本可以确认链路没有解析 bug。我自己踩过的最大一个坑是把temp1和temp2写反导致一整周的“最高温”都是负数。后来在脚本里加了一条断言temp_high temp_low不满足直接告警。这种自校验逻辑比写十行注释都管用。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

Python入门实战:猜数字游戏完整开发教程
Python入门实战:猜数字游戏完整开发教程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 7:35:42

空气感叠穿春季种草趋势拆解:从穿搭逻辑到小红书运营实操
空气感叠穿春季种草趋势拆解:从穿搭逻辑到小红书运营实操

如果让我用一个词概括今年春天的穿搭关键词,空气感叠穿一定是绕不开的那个。打开小红书数据平台,搜索热词和穿搭垂类笔记里,这类内容正以肉眼可见的速度冒出来:薄衬衫叠针织背心、轻风衣内搭长裙、纱裙外罩镂空开衫,随… · 2026/9/25 7:35:23

PaddleSpeech Wav2Vec2ASR 在 LibriSpeech 上的微调实践与结果解读(asr3 示例)
PaddleSpeech Wav2Vec2ASR 在 LibriSpeech 上的微调实践与结果解读(asr3 示例)

人工智能语音音频NLP媒体生成 【免费下载链接】PaddleSpeech Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation … · 2026/9/25 7:35:23

Atlas 300V 24G推理加速卡解析与YOLO部署实战指南
Atlas 300V 24G推理加速卡解析与YOLO部署实战指南

前阵子有网友在后台连续问了我两个问题:Atlas 300V 24G是运算加速卡吗?能不能拿来部署YOLO?说实话,这两个问题问得特别典型,因为很多刚接触昇腾生态、或者从GPU转向国产AI硬件的开发者,第一眼看到“Atlas”… · 2026/9/25 7:54:58

全国省市区三级联动表:MySQL导入与查询实战指南
全国省市区三级联动表:MySQL导入与查询实战指南

简介:这份资源是2024年最新整理的MySQL全国省市区三级联动数据表,面向后端开发、数据库设计人员以及需要地址级联选择功能的前端工程师,可解决地理信息查询与行政区域联动维护的问题。压缩包共2个文件,以sql数据脚本和zip归档为主… · 2026/9/25 7:54:52

可复用回归预测系统骨架:6类模型统一接口实践
可复用回归预测系统骨架:6类模型统一接口实践

简介:本资源是一套面向机器学习初学者与进阶实践者的预测建模综合代码包,覆盖贝叶斯网络、马尔科夫模型、线性回归、岭回归、多项式回归、决策树回归及深度神经网络七大主流预测方法,适用于时间序列预测、房价估算、用户行为建模等典型场景。… · 2026/9/25 7:54:34

Atlas 300V部署YOLOv5/YOLOv8:从ONNX到OM全流程
Atlas 300V部署YOLOv5/YOLOv8:从ONNX到OM全流程

先交代一下背景。不少人在搜“atlas部署yolo”和“atlas 300v 24g 是运算加速卡吗”这类词,说实话,这两个问题指向的是同一件事:你想在昇腾Atlas平台上面把YOLO检测模型跑起来,但不确定这块卡到底能不能干这个活、干起来麻不麻烦。… · 2026/9/25 7:54:28

OpenCodex Windows 服务控制台窗口问题全解析:从根因调查到“无窗口后台服务“的完整修复路径
OpenCodex Windows 服务控制台窗口问题全解析:从根因调查到“无窗口后台服务“的完整修复路径

【免费下载链接】opencodex Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code 项目地址: https://gitcode.com/gh_mirrors/ope/opencodex 点击… · 2026/9/25 7:54:28

Atlas 300V 24G部署YOLO全流程:从环境搭建到推理调优
Atlas 300V 24G部署YOLO全流程:从环境搭建到推理调优

如果你最近在搞AI推理,肯定绕不开"Atlas"这个名字。特别是Atlas 300V 24G这张卡,网上问得最多的一句就是:它到底是不是运算加速卡?答案是肯定的——这是一张标准的专用AI推理加速卡,24GB显存,专为… · 2026/9/25 7:54:28

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码