PHP无法直接获取JS渲染内容,因其HTTP客户端无渲染引擎;需用Headless Chrome(Puppeteer)、Selenium或抓取API/SSR来解决。

PHP 本身不能直接执行 JavaScript,所以用 file_get_contents() 或 cURL 拿到的只是初始 HTML,那些由 JS 渲染出来的内容(比如 React/Vue 加载的数据、滚动加载的列表、点击展开的详情)默认是空的。
为什么 PHP 直接请求拿不到动态内容
浏览器加载页面时会下载并执行 JS,再修改 DOM;而 PHP 的 HTTP 客户端只是“下载器”,不带渲染引擎。你看到的“空白”或“loading…”占位符,就是原始 HTML 里没被 JS 处理前的样子。
- 常见错误现象:
file_get_contents('https://example.com')返回的内容里包含,但实际页面中这个区域已被 Vue 填充了数据 - 真实场景:电商商品页的 SKU 列表、新闻站的无限滚动评论、后台管理界面的权限菜单
- 关键区别:静态页面返回即完整;动态页面返回的是“壳”,JS 才是“填充工”
用 Headless Chrome 配合 PHP 调用 Puppeteer(推荐方案)
本质是让 PHP 启动一个无界面 Chrome 实例,等 JS 执行完再取最终 DOM。比服务端渲染更通用,兼容绝大多数前端框架。
- 需要 Node.js 环境和
puppeteer包,PHP 只负责调用命令行或 API - 示例调用方式:
exec('node scrape.js https://example.com', $output);,其中scrape.js用page.waitForSelector('.item-list')等待目标元素出现 - 注意超时设置:动态页面加载慢,
page.goto(url, { waitUntil: 'networkidle0' })比'domcontentloaded'更稳妥 - 性能影响:每次启动浏览器开销大,不适合高频小请求;建议用长连接或池化管理(如 Chrome DevTools Protocol +
chrome-remote-interface)
检查目标站点是否提供 API 或 SSR 支持
很多所谓“动态页面”背后其实有隐藏 API,比硬啃 JS 更高效可靠。
立即学习“PHP免费学习笔记(深入)”;
- 打开浏览器开发者工具 → Network 标签 → 刷新页面 → 筛选
XHR或Fetch,找返回 JSON 的请求(比如/api/v1/products?category=12) - 有些站点启用了服务端渲染(SSR),比如 Next.js/Nuxt 默认输出首屏 HTML,此时
cURL就能拿到完整内容 - 验证方法:禁用浏览器 JS 后刷新,如果关键内容仍可见,说明是 SSR 或静态 API;如果只剩骨架,则必须走浏览器自动化
- 绕过反爬:API 请求往往带
X-Requested-With: XMLHttpRequest,PHP 中用curl_setopt($ch, CURLOPT_HTTPHEADER, [...])补全即可
用 Selenium + WebDriver(适合复杂交互)
当页面需要登录、滑动验证、鼠标悬停触发菜单等操作时,Puppeteer 可能不够灵活,Selenium 提供更贴近真实用户行为的控制能力。
- PHP 需安装
facebook/webdriverComposer 包,并运行chromedriver服务 - 关键代码片段:
$driver->wait(10)->until(WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector('.price'))) - 容易踩的坑:ChromeDriver 版本必须与本地 Chrome 版本严格匹配,否则报
session not created - 兼容性提示:Selenium 启动的浏览器默认带图形界面,服务器部署时要加
--headless --no-sandbox --disable-dev-shm-usage
真正卡住的往往不是“能不能”,而是没分清哪些内容是 JS 渲染的、哪些只是前端懒加载但实际藏在 HTML 注释或内联 JSON 里。先看 Network 和 Disable JavaScript,再决定要不要上浏览器自动化——多数时候,少写几行 JS 调用,比多起一个 Chrome 进程更省事。










