使用Node.js+Phantom.js抓取页面非HTML内容的技术咨询
如何用Node.js + Phantom.js抓取非HTML内容?
嘿,我看你已经在折腾用Node.js搭配Phantom.js抓取WHO流感数据库的非HTML内容了,结合你贴的代码,给你梳理下具体怎么实现:
核心思路
首先得明确:你说的“非HTML内容”大概率是页面通过AJAX动态加载的CSV、JSON这类数据。Phantom.js作为无头浏览器,能监听页面的所有网络请求和响应,这就是我们抓取这类资源的关键。
1. 监听网络请求,精准筛选目标资源
你的代码已经加了onResourceRequested事件,但可以进一步筛选你需要的非HTML资源(比如后缀是.csv的,或者URL里包含ReportData这类关键词的)。调整后的代码片段:
await page.on('onResourceRequested', function(requestData, networkRequest) { // 筛选WHO流感数据库的CSV数据请求 if (requestData.url.includes('.csv') || requestData.url.includes('ReportData')) { console.info('发现目标资源请求:', requestData.url); // 这里可以记录URL,后续单独请求或者直接捕获响应 } });
2. 捕获资源响应,提取非HTML内容
用onResourceReceived事件可以拿到完整的响应内容,这是获取数据的核心步骤:
await page.on('onResourceReceived', function(response) { // 只处理加载完成的响应,且是我们需要的资源类型(比如CSV) if (response.stage === 'end' && response.contentType.includes('text/csv')) { // 获取响应的纯文本内容(CSV就是纯文本格式) page.property('plainText').then(csvContent => { console.log('成功抓取到CSV数据!'); // 用Node.js的fs模块保存到本地文件 const fs = require('fs'); fs.writeFileSync('who_flumart_data.csv', csvContent); }); } });
3. 确保页面完全加载(避免遗漏动态资源)
目标页面是动态渲染的,简单的page.open可能还没等数据加载完就结束了,所以要加等待逻辑:
// 打开页面后,等待6秒确保动态数据加载完成(也可以用更精准的waitForSelector) await page.open(url); await page.waitFor(6000);
完整调整后的代码示例
把这些整合到你的现有代码里,最终版本大概是这样:
var phantom = require('phantom'); var loadInProgress = false; var url = 'http://apps.who.int/flumart/Default?ReportNo=12'; const fs = require('fs'); (async function() { const instance = await phantom.create(); const page = await instance.createPage(); // 设置User-Agent,避免被反爬拦截 await page.setting('userAgent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'); // 监听请求,筛选目标资源 await page.on('onResourceRequested', function(requestData, networkRequest) { if (requestData.url.includes('.csv') || requestData.url.includes('ReportData')) { console.info('请求目标资源:', requestData.url); } }); // 监听响应,捕获CSV内容 await page.on('onResourceReceived', function(response) { if (response.stage === 'end' && response.contentType.includes('text/csv')) { page.property('plainText').then(csvContent => { console.log('成功获取CSV数据,已保存到本地'); fs.writeFileSync('who_flumart_data.csv', csvContent); }); } }); // 监听页面控制台信息,方便调试 await page.on('onConsoleMessage', function(msg) { console.info('页面控制台输出:', msg); }); // 打开页面并等待加载完成 await page.open(url); await page.waitFor(6000); // 退出Phantom.js实例 await instance.exit(); })();
额外提示
- Phantom.js已经停止维护了,如果后续遇到兼容性问题,建议换成Puppeteer(Chrome官方的无头浏览器),API更友好,社区支持也更好。
- 如果直接捕获响应有问题,可以尝试在页面上下文里用
fetch直接请求目标资源,比如:
const csvData = await page.evaluate(() => { // 这里替换成你之前捕获到的目标资源URL return fetch('https://example.com/target.csv').then(res => res.text()); });
内容的提问来源于stack exchange,提问作者user7558372
相关产品推荐
相关产品推荐

