如何在PHP中运行Node.js并导入Puppeteer爬取结果?
解决PHP调用Node.js Puppeteer脚本并获取爬取数据的问题
一、原代码的核心问题
- PHP的
exec是独立进程,cd js不会改变后续exec的工作目录,导致Node.js找不到index.js。 - 未捕获Node.js的输出,无法将爬取数据传递给PHP。
- Node.js脚本存在未定义变量
weather_report_chin_html,且多次输出JSON会导致PHP解析失败。
二、修复步骤
1. 调整PHP代码:正确调用Node.js并捕获输出
将目录切换与Node执行命令合并,同时捕获输出和执行状态:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>contacts.php</title> </head> <body text="blue"> <?php // 初始化输出和状态变量 $output = []; $returnStatus = 0; // 合并切换目录与执行脚本的命令,确保Node能找到index.js exec('cd ' . __DIR__ . '/js && node index.js', $output, $returnStatus); // 处理执行结果 if ($returnStatus === 0) { // 将输出数组拼接成完整字符串,解析为JSON $rawResult = implode("\n", $output); $crawledData = json_decode($rawResult, true); if ($crawledData) { // 这里可以直接使用爬取到的数据,比如打印或存入数据库 echo '<h3>爬取结果:</h3>'; echo '<pre>' . print_r($crawledData, true) . '</pre>'; } else { echo '解析爬取数据失败,请检查Node.js脚本输出格式'; } } else { echo 'Node.js脚本执行失败,错误码:' . $returnStatus . '<br>'; echo '错误信息:<pre>' . implode("\n", $output) . '</pre>'; } ?> </body> </html>
2. 修改Node.js脚本:输出标准JSON并修复错误
补充目标URL,收集所有数据后一次性输出标准JSON,确保PHP能正确解析:
const puppeteer = require('puppeteer'); // 替换为你的目标爬取URL const targetUrl = 'https://example.com/weather-report'; (async () => { let browser; try { // 服务器环境建议使用无头模式 browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); await page.goto(targetUrl, { waitUntil: 'domcontentloaded' }); // 等待页面加载完成 // 一次性获取所有.NEW元素的数据 const crawledData = await page.$$eval('.NEW', elements => elements.map(el => ({ text: el.textContent.trim(), href: el.href })) ); // 输出标准JSON字符串,无多余内容 console.log(JSON.stringify(crawledData)); } catch (error) { // 将错误以JSON格式输出到标准错误流 console.error(JSON.stringify({ error: error.message })); // 返回非0状态码告知PHP执行失败 process.exit(1); } finally { // 确保浏览器关闭 if (browser) await browser.close(); } })();
三、额外注意事项
- 依赖安装:在
js目录下执行npm install puppeteer,确保所需依赖已安装。 - 服务器权限:确保PHP进程拥有执行Node.js的权限,以及读取
js目录的权限。 - 无头环境依赖:如果在Linux服务器运行,需安装Puppeteer所需的系统依赖(如
libnss3-dev、libgbm-dev等)。 - 超时设置:若爬虫耗时较长,需在PHP开头添加
set_time_limit(0)关闭超时限制。
内容的提问来源于stack exchange,提问作者Lo Dennis
相关产品推荐
相关产品推荐

