映射数组传递值到异步Puppeteer函数有时会返回不正确的值

时间:2018-10-19 22:35:36

标签: javascript node.js asynchronous async-await puppeteer

我有一个数组,一个数组将在网站上返回无效的搜索结果,另一个数组将返回有效的搜索。

["sakdjlkasjda", "Assassin's Creed Origins"]

然后我在数组上映射并将值传递给异步函数

const cex = games.map((game) => cexSearch(game));

return Promise.all(cex)
  .then(function(g) {
    console.log(g);
    res.send(g);
  });

在异步功能中,我创建一个Puppeteer实例,导航到URL。该网站有一个元素(没有类或ID),仅在没有结果的地方显示。对于有效结果,noRecordsDisplay应该等于none,在没有有效结果的情况下,noRecordsDisplay应该等于""。但是,有几次我注意到对于应该无效的搜索,noRecordsDisplay等于none,因此不确定在哪里出错的情况在大多数情况下都是可行的,但并非全部时间?任何帮助将不胜感激。

async function cexSearch(game) {
  const url = 'https://uk.webuy.com/search?stext=' + game;
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36');
  await page.goto(url, {
    timeout: 3000000
  });
  const content = '.content-area';
  await page.waitForSelector(content);
  await page.waitForSelector('.content-area > div:not(.searchRcrd)');
  const noRecordsDisplay = await page.evaluate(() => document.querySelector('.content-area > div:not(.searchRcrd)').style.display);
  console.log("display = " + noRecordsDisplay);
  if (noRecordsDisplay === "") {
    return "No Search Results";
  } else {
    //When there is an invalid search it sometimes reaches here and .searchRcrd does not exist so it timesout
    const selector = '.searchRcrd';
    await page.waitForSelector(selector);

    // DO logic

    await browser.close();

    return records;
  }
} 

1 个答案:

答案 0 :(得分:1)

有多种方法可以解决您的问题并更精确地获得结果。

要查看是否有结果,

!!document.querySelector('.searchRcrd') // => Returns true if results are available

用法:

const noRecordsDisplay = await page.evaluate(() => !!document.querySelector('.searchRcrd'));

另一种方法是使用waitForResponse而不是waitForSelector

例如

  • 搜索中使用的ajax请求包含此部分/v3/boxes?q=
  • 结果为response.data,则返回数据,否则返回null。

用法:

const finalResponse = await page.waitForResponse(response => response.url().includes('/v3/boxes?q=') && response.status() === 200);
const data = (await finalResponse.json()).data;

编辑:

您的代码不会等到页面完全加载。要等待页面完全加载,应使用waitUntil选项。

这里是完整的工作代码。

const puppeteer = require("puppeteer");

const games = ["Does not Exist", "Assassin's Creed Origins"];
const cex = games.map(game => cexSearch(game));

Promise.all(cex).then(function(g) {
  console.log(g);
});

async function cexSearch(game) {
  const url = "https://uk.webuy.com/search?stext=" + game;
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: "networkidle0" }); // <-- wait for page to load properly

  await page.waitForSelector(".content-area > div:not(.searchRcrd)");
  const noRecordsDisplay = await page.evaluate(
    () => !!document.querySelector(".searchRcrd")
  );
  if (!noRecordsDisplay) {
    console.log(game, ">> No Search Results");
    await browser.close();
    return false;
  }
  console.log(game, ">> Result Exists");
  await browser.close();
  return true;
}

结果:

➜ node app.js
No Search Results
Result Exists
[ false, true ]

编辑2:

如果您在该数组中传递了 6个元素,则该应用将尝试一次打开6个实例/ chrome窗口(!!),并且很可能由于以下原因而挂断资源。

虽然在:D上使用16GB内存的机器对我来说100%很好。您一次打开6页,这是一个完全不同的问题。有关并发性的答案,请参见here

更多测试:

Quantam Break >> No Search Results
FIFA 19 >> Result Exists
asdhsuah >> No Search Results
asucinuasu >> No Search Results
No Man's Sky >> Result Exists
Overcooked 2 >> Result Exists
[ false, true, true, false, true, false ]

查看最终结果与控制台日志的顺序不同。这是由于异步特性。

您必须查看整体图片。如果您传递6个元素,它将打开6个窗口,它必须等待页面完全加载,如果服务器/计算机质量不好,或者Internet状况不佳,则会出现导航问题。

对于以后的尝试,如果要构建经过100个链接并返回结果的内容,则需要学习Async Await和Queue。如果您传递100个元素,它将立即冻结,因为它将尝试立即打开100个chrome窗口。请记住这一点。