中国天气网反爬严格,需用curl设置user-agent、referer等请求头并处理编码;优先调用其稳定json接口(如/data/sk/),响应为gb2312需转utf-8后再json_decode。

file_get_contents 和 curl 都能用,但中国天气网已默认启用反爬机制,直接请求大概率返回空页或 403 —— 这不是你代码写错了,是网站加了 User-Agent 检查、Referer 校验,甚至部分接口还依赖 Cookie 或 JS 渲染。
用 curl 抓取前必须设置基础请求头
中国天气网(如 <a href="https://www.php.cn/link/7fe059987fe6e9d0cb6a7c2e98874d4c">https://www.php.cn/link/7fe059987fe6e9d0cb6a7c2e98874d4c</a>)对无头请求非常敏感。不设 User-Agent 和 Referer,curl_exec 很可能返回空白字符串或重定向到首页。
实操建议:
- 必须设置
CURLOPT_USERAGENT,例如"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" - 推荐加上
CURLOPT_REFERER,值设为同域名首页:"http://www.weather.com.cn/" - 关闭 SSL 验证(仅开发测试时):
CURLOPT_SSL_VERIFYPEER => false - 开启
CURLOPT_FOLLOWLOCATION,避免因 302 跳转导致内容丢失
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'); curl_setopt($ch, CURLOPT_REFERER, 'http://www.weather.com.cn/'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $content = curl_exec($ch); curl_close($ch);
DOMDocument 解析失败?先检查编码和 HTML 结构完整性
DOMDocument::loadHTML() 对 malformed HTML 极其脆弱。中国天气网页面常含未闭合标签、中文注释、乱码字符(如 天气),直接 load 可能静默失败或报 Warning,导致 $xpath->query() 返回空结果。
立即学习“PHP免费学习笔记(深入)”;
常见错误现象:
-
$days = $xpath->query('//div[@id="7d"]//li')返回 0 个节点,但浏览器里明明有 -
DOMDocument报Entity 'nbsp' not found类警告
解决办法:
- 用
mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8')统一转码 - 用正则预清理注释:
$content = preg_replace('/<!--[\s\S]*?-->/', '', $content) - 加载前补全 doctype(可选):
$content = '' . $content . ''
别硬啃网页源码,优先用官方 JSON 接口
中国天气网实际提供多个未公开但长期稳定的 JSON 接口,比解析 HTML 更可靠、更轻量:
三个可用地址(城市编码需查表,如北京 101010100):
- 实时数据:
http://www.weather.com.cn/data/sk/101010100.html - 当日详情:
http://www.weather.com.cn/data/cityinfo/101010100.html - 7天预报:
http://m.weather.com.cn/data/101010100.html
这些接口返回标准 JSON,无需 XPath 或正则,json_decode(file_get_contents($url), true) 即可拿到数组。注意:
- 响应是 GB2312 编码,需用
iconv('GB2312', 'UTF-8', $json_str)转换后再 decode -
http://m.weather.com.cn/data/...返回的是嵌套结构,主数据在$data['weatherinfo']下 - 部分接口已弃用(如旧版
/data/地址),若返回 404,换用/data/sk/或迁移到和风天气等正规 API
城市编码怎么找?别手动扒网页
中国天气网没有公开的城市 ID 映射表,但可通过以下方式快速获取:
- 访问
http://www.weather.com.cn/forecast/,打开开发者工具 → Network → 切换城市,观察 XHR 请求里的cityid参数 - 用现成的离线映射文件(如 GitHub 上搜
china-weather-city-code),多数含 CSV/JSON 格式 - 调用淘宝 IP 定位接口粗略判断(仅作参考):
http://ip.taobao.com/service/getIpInfo.php?ip=your_ip→ 提取data.city后再匹配
最稳妥的做法:把常用城市(北上广深杭等)的编码写死在配置数组里,避免每次请求都去查。
真正卡住人的从来不是“怎么写循环”,而是 curl 拿不到内容、DOMDocument 解析无声失败、或者今天还能用的接口明天就 404 —— 所以务必加日志:记录 curl_getinfo($ch, CURLINFO_HTTP_CODE) 和原始 $content 前 200 字符,否则排查起来全是黑盒。











