首页 > 解决方案 > 循环时无法单击元素

问题描述

我正在尝试遍历所有元素,单击它们并等待一段时间让它加载,然后再收集一些信息。但是由于某种原因,它只点击所有迭代的第一个元素。

const result = await page.evaluate(async () => {
    const data = [];
    const elements = document.querySelectorAll('.calendar-available');
    for (const element of elements) {
        data_sub = [];
        element.click();  
        await new Promise((resolve) => setTimeout(resolve, 2000));
        let columns = document.querySelectorAll('.col-md-6');
        for(i = 2; i < columns.length; i++){
            let info = columns[i].innerText;
            data_sub.push(info);
        }         
        data.push(data_sub);
    }    
    return data;
}); 

标签: web-scrapingpuppeteer

解决方案


好吧,您的代码似乎是有效的,但是在每次单击之后,DOM 树都会以某种方式重新分配,并且循环中的下一个元素引用相同的第一个元素。我们可以这样处理这个问题(更改的行用注释标记):

'use strict';

const puppeteer = require('puppeteer');

(async function main() {
  try {
    const browser = await puppeteer.launch({ headless: false });
    const [page] = await browser.pages();

    await page.goto('https://reslife.ucla.edu/reserve');

    const result = await page.evaluate(async () => {
        document.querySelector('.reserve-grid .col-md-4 input').click();
        await new Promise((resolve) => setTimeout(resolve, 2000));
        document.querySelector('.reserve-grid .col-md-6 input').click();
        await new Promise((resolve) => setTimeout(resolve, 2000));

        const data = [];
        const length = document.querySelectorAll('.calendar-available').length; // <-
        for (let n = 0; n < length; n++) { // <-
            const element = document.querySelectorAll('.calendar-available').item(n); // <-
            data_sub = [];
            element.click();
            await new Promise((resolve) => setTimeout(resolve, 2000));
            let columns = document.querySelectorAll('.col-md-6');
            for(i = 2; i < columns.length; i++){
                let info = columns[i].innerText;
                data_sub.push(info);
            }
            data.push(data_sub);
        }
        return data;
    });

    console.log(result);

    await browser.close();
  } catch (err) {
    console.error(err);
  }
})();

或者,我们可以使用这些行而不是标记的行

        const labels = [...document.querySelectorAll('.calendar-available')].map(el => el.getAttribute('aria-label')); // <-
        for (const label of labels) { // <-
            const element = document.querySelector(`.calendar-available[aria-label="${label}"]`); // <-

推荐阅读