0

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

["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应该相等""。但是,有几次我注意到对于应该无效的搜索,noRecordsDisplayequals 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;
  }
} 
4

1 回答 1

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 windows(!!),并且很可能由于资源问题而挂起。

不过,在一台 16GB 内存的机器上,它对我来说 100% 没问题:D。您一次打开 6 页,这是一个完全不同的问题。有关并发的答案,请参见此处。

更多测试:

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 个窗口,它必须等待页面完全加载,如果服务器/计算机不好,或者网络不好,有些会出现导航问题。

对于您未来的尝试,您需要学习 Async Await 和 Queue,如果您想构建类似的东西,它可以通过 100 个链接并返回结果。如果传递 100 个元素,它会立即冻结,因为它会尝试一次打开 100 个 chrome 窗口。记在脑子里。

于 2018-10-20T03:20:46.233 回答