我正在try 使用Puppeter从多个页面中获取价格.我遇到的问题是,编写一个包含所有刮取数据的JSON文件.问题是,如果我试图用async function中的变量编写文件,我会得到一个错误,说明该变量尚未声明.

async function scrapeVMZ(url) {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);

    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();

    console.log({vmzRawTxt1, vmzRawTxt2});
    const vmz01 = JSON.stringify(vmzRawTxt1);
    const vmz02 = JSON.stringify(vmzRawTxt2);
    console.log(vmz01, vmz02);
    browser.close();
}
scrapeVMZ('https://www.vmzviagens.com.br/ingressos/orlando/walt-disney-orlando');


async function scrapeMB(url) {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);

    
    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();

    console.log({mbRawTxt1, mbRawTxt2});
    const mb01 = JSON.stringify(mbRawTxt1);
    const mb02 = JSON.stringify(mbRawTxt2);
    console.log(mb01, mb02);
   
    browser.close();
}
scrapeMB('https://www.ingressosmagicblue.com.br/produtos/?mpage=2');

如何使用上面的代码编写一个文件,将变量vmz01, vmz02mb01, mb02存储在JSON文件中,如下面的示例所示?

let abc = {        
        "MB": {
            preco: mb01,
            preco2: mb02
        },
        "VMZ": {
            preco: vmz01,
            preco2: vmz02
        }
    };

推荐答案

console.log出现在函数中而不是返回结果时,这是一条死胡同.如果要稍后使用,请返回结果.既然你在回复promise ,你可以在打电话的人中回复await个,或者serially or in parallel个.

函数中也有大量重复代码,您可能不需要2个浏览器.这里有一个在单个浏览器中并行运行的快速重构(preco个键有点尴尬——我建议这里可能有一个数组).

const fs = require("fs").promises;
const puppeteer = require("puppeteer"); // ^14.3.0

const vmzPaths = [
  '//*[@id="__layout"]/div/div[1]/section/div/div/div[2]/div[2]/div[1]/div/div/div[2]/div/div[1]/span[2]',
  '//*[@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 mbPaths = [
  "/html/body/section[3]/div/div/div[2]/div[1]/div/div[2]/a[1]/span[2]/span/div/div[2]/span",
  "/html/body/section[3]/div/div/div[2]/div[1]/div/div[2]/a[1]/span[2]/span/div/div[4]/span",
];

const scrape = async (browser, url, paths) => {
  const page = await browser.newPage();
  await page.goto(url);
  return Promise.all(paths.map(async p =>
    (await page.waitForXPath(p)).evaluate(e => e.textContent)
  ));
};

let browser;
(async () => {
  browser = await puppeteer.launch({headless: true});
  const text = await Promise.all([
    scrape(browser, "https://www.ingressosmagicblue.com.br/produtos/?mpage=2", mbPaths),
    scrape(browser, "https://www.vmzviagens.com.br/ingressos/orlando/walt-disney-orlando", vmzPaths),
  ]);
  const names = ["MB", "VMZ"];
  const collected = Object.fromEntries(text.map((e, i) => [
    names[i], Object.fromEntries(e.map((e, i) =>
      [`preco${i === 0 ? "" : (i + 1)}`, e]
    ))
  ]));
  await fs.writeFile("out.json", JSON.stringify(collected, null, 2));
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close())
;

顺便说一句,I'm not a big fan of hyper-precise, browser generated paths and selectors.这些往往是超脆的,几乎总是有更好的方法来 Select Select 器.但我并没有为了关注promise 问题而阅读这一页,所以我将把它作为读者的练习.

Javascript相关问答推荐

类型脚本中只有字符串或数字键而不是符号键的对象

使用下表中所示的值初始化一个二维数组

Promise Chain中的第二个useState不更新

MathJax可以导入本地HTML文档使用的JS文件吗?

如何将react—flanet map添加到remixjs应用程序

我可以使用使用node.js创建的本地主机来存储我网站上提交的所有数据吗?没有SQL或任何数据库.只有HTML语言

400 bad request error posting through node-fetch

Next.js中的服务器端组件列表筛选

Docent.cloneNode(TRUE)不克隆用户输入

对具有相似属性的对象数组进行分组,并使用串连的值获得结果

Node.js API-queryAll()中的MarkLogic数据移动

如何通过Axios在GraphQL查询中发送数组

用Reaction-RT-Chart创建实时条形图

使用Java脚本替换字符串中的小文本格式hashtag

Rails 7:在不使用导入映射的情况下导入Java脚本

如何按区域进行过滤并将其从结果数组中删除?

如何在Java脚本中添加一个可以在另一个面板中垂直调整大小的面板?

是否在图表中计算线上的点坐标?

JAVASCRIPT|导入模块中断FOR循环

在脚本设置中使用Vue3 v-html,无需额外的换行标记