You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Puppeteer爬取多页面数据并写入单个JSON文件

Puppeteer多页爬取数据合并写入JSON实现方案

问题原因

变量未定义报错来自两个核心问题:

  • vmz01、vmz02、mb01、mb02都是异步爬取函数内部的局部作用域变量,函数外部无法直接访问
  • 爬取函数是异步执行的,没有等待执行完成就读取变量的话,变量还没完成声明赋值,自然触发报错

修改步骤

  1. 改造两个爬取函数,将爬取到的价格数据作为返回值对外暴露,同时给browser.close()加上await避免浏览器资源泄漏
  2. 新增主执行逻辑,通过Promise.all并行等待两个爬取任务全部执行完成,拿到所有爬取结果
  3. 按照指定结构组装最终数据对象,调用Node.js内置的文件系统模块,将完整数据写入单个JSON文件

完整修改后代码

const puppeteer = require('puppeteer');
// 引入Node.js内置的promise版文件系统模块,无需额外安装
const fs = require('fs/promises');

async function scrapeVMZ(url) {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url, { waitUntil: 'domcontentloaded' });

    const [vmzel1] = await page.$x('//*[@id="__layout"]/div/div[1]/section/div/div/div[2]/div[2]/div[1]/div/div/div[2]/div/div[1]/span[2]');
    const vmztxt1 = await vmzel1.getProperty('textContent');
    const vmzRawTxt1 = await vmztxt1.jsonValue();

    const [vmzel2] = await page.$x('//*[@id="__layout"]/div/div[1]/section/div/div/div[2]/div[2]/div[1]/div/div/div[2]/div/div[1]/span[4]/b');
    const vmztxt2 = await vmzel2.getProperty('textContent');
    const vmzRawTxt2 = await vmztxt2.jsonValue();

    const vmz01 = JSON.stringify(vmzRawTxt1.trim());
    const vmz02 = JSON.stringify(vmzRawTxt2.trim());
    
    await browser.close();
    // 对外返回爬取到的两个价格数据
    return { vmz01, vmz02 };
}

async function scrapeMB(url) {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url, { waitUntil: 'domcontentloaded' });

    const [mbel1] = await page.$x('/html/body/section[3]/div/div/div[2]/div[1]/div/div[2]/a[1]/span[2]/span/div/div[2]/span');
    const mbtxt1 = await mbel1.getProperty('textContent');
    const mbRawTxt1 = await mbtxt1.jsonValue();

    const [mbel2] = await page.$x('/html/body/section[3]/div/div/div[2]/div[1]/div/div[2]/a[1]/span[2]/span/div/div[4]/span');
    const mbtxt2 = await mbel2.getProperty('textContent');
    const mbRawTxt2 = await mbtxt2.jsonValue();

    const mb01 = JSON.stringify(mbRawTxt1.trim());
    const mb02 = JSON.stringify(mbRawTxt2.trim());
   
    await browser.close();
    // 对外返回爬取到的两个价格数据
    return { mb01, mb02 };
}

// 主执行逻辑
async function main() {
    // 并行执行两个爬取任务,等待全部完成后拿结果
    const [vmzRes, mbRes] = await Promise.all([
        scrapeVMZ('https://www.vmzviagens.com.br/ingressos/orlando/walt-disney-orlando'),
        scrapeMB('https://www.ingressosmagicblue.com.br/produtos/?mpage=2')
    ]);

    // 按照指定结构组装数据
    const abc = {        
        "MB": {
            preco: mbRes.mb01,
            preco2: mbRes.mb02
        },
        "VMZ": {
            preco: vmzRes.vmz01,
            preco2: vmzRes.vmz02
        }
    };

    // 写入JSON文件,null和2参数是为了格式化输出JSON,方便阅读
    await fs.writeFile('./price_data.json', JSON.stringify(abc, null, 2), 'utf-8');
    console.log('数据已成功写入price_data.json文件');
}

// 启动主逻辑
main().catch(err => console.error('执行出错:', err));

补充说明

  • 代码里给page.goto加了waitUntil: 'domcontentloaded'参数,减少页面等待时间,避免因静态资源加载慢导致爬取超时
  • 对爬取到的原始文本加了trim(),自动去掉文本前后多余的换行、空格
  • 写入文件时JSON.stringify传入了格式化参数,生成的JSON文件会自动缩进,不会挤成一行
  • 所有异步操作都加了await,不会出现浏览器提前关闭、文件写入失败的问题

内容的提问来源于stack exchange,提问作者Fadrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:54:25