curl_exec() 返回空字符串但 http 状态码是 200,通常是因目标网站反爬(如校验 user-agent 或返回 js 渲染内容),应设置真实请求头、启用跳转、检查 ssl 及错误信息。

curl_exec() 返回空字符串但 HTTP 状态码是 200
这通常不是代码写错了,而是目标网站做了基础反爬:比如检查 User-Agent、拒绝非浏览器请求、或返回了 JavaScript 渲染后的内容(而 curl 只拿原始 HTML)。
解决办法不是硬刚,而是先模拟真实请求头:
- 务必设置
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36') - 加上
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)处理跳转 - 用
curl_getinfo($ch, CURLINFO_HTTP_CODE)确认状态码,再检查curl_error($ch)是否为空——很多“空响应”其实是 SSL 握手失败,得加curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false)(仅测试用)
file_get_contents() 抓到的 HTML 里有乱码或缺失内容
PHP 默认不处理字符编码转换,file_get_contents() 拿到的是原始字节流。如果网页声明是 UTF-8 但实际含 GBK 字符,或者用了 BOM 或压缩传输(gzip),就会显示异常。
- 优先改用
curl,它能自动处理 gzip 和重定向;file_get_contents()对压缩响应完全无感 - 若坚持用
file_get_contents(),必须配stream_context_create()设置http选项:'user_agent'、'timeout'、'header' => ["Accept-Encoding: gzip"](但解压仍需手动) - 拿到内容后别急着
DOMDocument::loadHTML(),先用mb_convert_encoding($html, 'UTF-8', 'auto')做一次编码归一
DOMDocument::loadHTML() 解析失败,报 Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name
这是 HTML 不规范导致的,比如出现了未闭合的 、孤立的 ©、或 JS 里的 && 被当成了实体引用。DOMDocument 默认严格解析,不会自动容错。
- 加载前先用
libxml_use_internal_errors(true)屏蔽警告,否则直接中断脚本 - 用
preg_replace('/&(?![a-zA-Z#]{1,8};)/', '&', $html)修复孤立&符号(常见于内联 JS/CSS) - 不要用
loadHTMLFile()直接读远程 URL——它不走 curl 设置,也不支持 header,容易出错;统一先curl_exec()拿内容,再loadHTML()
用 XPath 提取元素时总是返回空数组
XPath 表达式本身没问题,但 DOM 结构和你预期的不一样:比如目标内容在 <script></script> 里动态渲染、被注释掉、或包裹在 iframe 中。DOMDocument 解析的是静态 HTML,不执行 JS。
立即学习“PHP免费学习笔记(深入)”;
- 先用
$dom->saveHTML()输出解析后的 HTML 片段,确认目标节点是否真的存在 - XPath 查询前确保调用
$xpath->registerNamespace('x', 'http://www.w3.org/1999/xhtml')(如果文档有命名空间) - 用
$xpath->query('//div[@class="content"]//p[1]')这类带层级的路径比单纯//p更稳;避免用text()直接取值,先取节点再调$node->textContent - 注意:XPath 索引从 1 开始,
[1]是第一个,不是[0]
真正卡住的地方往往不在语法,而在你拿到的 HTML 根本不是浏览器看到的那个版本——没处理跳转、没过反爬头、没解 gzip、没清 JS 注释、没容错实体符号。每一步都得验证中间结果,而不是堆完代码才看最终输出。










