首页 > 解决方案 > 无法让 querySelectorAll 与 puppeteer 一起工作(返回未定义)

问题描述

我正在尝试使用超市的价格进行一些网络抓取。它与 node.js 和 puppeteer 一起使用。从接受 cookie 并单击“加载更多按钮”开始,我可以浏览网站。但是当我尝试使用 querySelectorAll 读取包含产品的 div 时,我被卡住了。即使我等待特定的 div 出现,它也会返回 undefined 。我错过了什么?

问题出在代码块的末尾。

const { product } = require("puppeteer");

const scraperObjectAll = {
    url: 'https://www.bilkatogo.dk/s/?query=',
    async scraper(browser) {
        let page = await browser.newPage();
        console.log(`Navigating to ${this.url}`);
        await page.goto(this.url);

        // accept cookies
        await page.evaluate(_ => {
            CookieInformation.submitAllCategories();
        });

        var productsRead = 0;
        var productsTotal = Number.MAX_VALUE;

        while (productsRead < 100) {
            // Wait for the required DOM to be rendered
            await page.waitForSelector('button.btn.btn-dark.border-radius.my-3');
            // Click button to read more products
            await page.evaluate(_ => {
                document.querySelector("button.btn.btn-dark.border-radius.my-3").click()
            });
            // Wait for it to load the new products
            await page.waitForSelector('div.col-10.col-sm-4.col-lg-2.text-center.mt-4.text-secondary');
            // Get number of products read and total
            const loadProducts = await page.evaluate(_ => {
                let p = document.querySelector("div.col-10.col-sm-4.col-lg-2").innerText.replace("INDLÆS FLERE", "").replace("Du har set ","").replace(" ", "").replace(/(\r\n|\n|\r)/gm,"").split("af ");
                return p;
            });

            console.log("Products (read/total): " + loadProducts);
            productsRead = loadProducts[0];
            productsTotal = loadProducts[1];

            // Now waiting for a div element
            await page.waitForSelector('div[data-productid]');

            const getProducts = await page.evaluate(_ => {
                return document.querySelectorAll('div');
            });

            // PROBLEM HERE!
            // Cannot convert undefined or null to object
            console.log("LENGTH: " + Array.from(getProducts).length);
        }

标签: javascriptpuppeteerqueryselector

解决方案


传递给的回调page.evaluate模拟页面上下文中运行,而不是在节点脚本的标准范围内。如果没有仔细考虑,就无法在页面和 Node 脚本之间传递表达式:最重要的是,如果某些内容不可序列化(转换为纯 JSON),则无法传输。

querySelectorAll返回一个NodeList,NodeLists只存在于前端,不存在后端。同样,NodeLists 包含 HTMLElements,它们也只存在于前端。

将所有需要使用仅存在于前端的数据的逻辑放在.evaluate回调中,例如:

const numberOfDivs = await page.evaluate(_ => {
  return document.querySelectorAll('div').length;
});

或者

const firstDivText = await page.evaluate(_ => {
  return document.querySelector('div').textContent;
});

推荐阅读