You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Puppeteer提取多层div嵌套h4文本失败,程序异常终止求助

问题:Puppeteer爬取星球状态时元素数量不稳定

问题详情

我用Puppeteer爬取https://play.projectnebula.com/planet/[ID]系列页面,目标是提取嵌套在7层div下的h4文本(内容为"Claimed"),以此筛选未认领的星球(所有状态均通过h4标签展示)。但运行代码时,前1-2个URL能获取到全部13个h4元素,后续URL仅能拿到11个,导致无法定位到对应"Claimed"的h4,程序提前终止。

原代码

const puppeteer = require('puppeteer')
async function run() {

    const browser = await puppeteer.launch({
        headless: false,
        ignoreHTTPSErrors: true,
    })

    var x = 1101;
    while (x !== 0) {
        const page = await browser.newPage();
        await page.setRequestInterception(true);

        page.on('request', (req) => {
            if (req.resourceType() == 'image' || req.resourceType() == 'font') {
                req.abort();
            }
            else {
                req.continue();
            }
        });
        page.setDefaultTimeout(0);
        await page.goto(`https://play.projectnebula.com/planet/${x}`);
        await page.waitForSelector('h4');
        const elements = await page.$$("h4");

        let text = await (await elements[elements.length - 2].getProperty("innerText")).jsonValue()
        text = text.toLowerCase().trim();
        if (text == 'claimed' || text == 'on sale') {
            console.log(text, x)
            x += 1;
            await page.close();
        }
        else {
            console.log(x, text)
            x = 0
        }
    }
}
run();

问题原因分析

  1. 等待时机过早:仅等待第一个h4出现就开始获取元素,页面后续的h4可能还未渲染完成,导致元素数量不足
  2. 页面复用问题:每次循环新建页面,可能存在浏览器资源分配不稳定、页面加载状态不一致的情况
  3. 元素定位脆弱:依赖elements.length -2的索引定位状态h4,完全依赖页面h4的数量排序,一旦页面结构微调就会失效
  4. 请求拦截的潜在影响:虽然拦截了图片和字体,但可能某些关键请求的加载状态未被正确等待

修复方案

核心改进点

  • 用精准选择器直接定位目标状态h4(基于7层div的层级),避免依赖索引
  • 等待页面完全加载完成,确保所有h4都渲染完毕
  • 复用同一个页面,减少资源开销和加载波动

修复后的代码

const puppeteer = require('puppeteer')

async function run() {
    const browser = await puppeteer.launch({
        headless: false,
        ignoreHTTPSErrors: true,
    })

    // 复用同一个页面,减少资源消耗
    const page = await browser.newPage();
    await page.setRequestInterception(true);

    page.on('request', (req) => {
        if (req.resourceType() === 'image' || req.resourceType() === 'font') {
            req.abort();
        } else {
            req.continue();
        }
    });
    page.setDefaultTimeout(0);

    let x = 1101;
    while (x !== 0) {
        try {
            // 等待页面完全加载(networkidle2表示仅剩下2个以下的网络请求)
            await page.goto(`https://play.projectnebula.com/planet/${x}`, {
                waitUntil: 'networkidle2'
            });

            // 用精准层级选择器定位7层div下的h4,若有父级类名可替换为更精准的选择器
            await page.waitForSelector('div > div > div > div > div > div > div h4', { timeout: 10000 });
            
            // 直接获取目标h4文本,避免依赖索引
            const statusText = await page.$eval('div > div > div > div > div > div > div h4', el => el.innerText.toLowerCase().trim());

            if (statusText === 'claimed' || statusText === 'on sale') {
                console.log(statusText, x);
                x += 1;
            } else {
                console.log(x, statusText);
                x = 0;
            }
        } catch (err) {
            // 处理超时或元素未找到的情况,避免程序崩溃
            console.error(`处理星球${x}时出错:`, err.message);
            x += 1;
        }
    }

    await page.close();
    await browser.close();
}
run();

额外优化建议

  • 如果知道目标h4所在父级div的类名,把层级选择器替换成带类名的版本(比如.planet-status-container h4),稳定性会更高
  • 若页面存在懒加载,可增加页面滚动操作确保所有元素渲染完成
  • 加入随机延迟,降低被网站反爬机制拦截的风险

内容的提问来源于stack exchange,提问作者Hafeez Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:35:23