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

Puppeteer性能对比:$eval与innerHTML爬虫方案选型咨询

问题:Puppeteer爬虫两种字段提取方式的性能对比

我目前正在使用Puppeteer开发一款网页爬虫,用于抓取单篇文章的详情(类似亚马逊商品信息)。
此前我通过获取所有文章元素的Element Handles,再使用$eval结构化提取所需内容,抓取400个元素耗时12-15秒。
我尝试改用$$eval获取400个元素的innerHTML,仅耗时5秒,考虑配合HTML解析器处理。
我的问题是:针对每个元素需提取5个字段的场景,使用$eval逐个处理Element Handles是否比HTML解析更优?

原方案代码(耗时12-15秒)

//getting element handles for articles
let articleHandles = await page.$$('.SearchResult_searchResultItemWrapper__VVVnZ')

//looping through handles to get info and push to array
for (handle of articleHandles) {
    const articleLink = await handle.$eval('a', e => e.getAttribute('href'));
    const articleImg = await handle.$eval('a>div>span>img', e => e.getAttribute('src'));
    const articleDesc = await handle.$eval('div>div', e => e.innerText);
    const dealerHandle = await handle.$('div.SearchResult_companyWrapper__W5gTQ', e => e.innerText);

    const dealer = dealerHandle ? await dealerHandle.evaluate(e => e.innerText) : "Not found";

    let detailsOne = (cleanupArticleDescription(articleDesc));

    let detailsTwo = {
        link: articleLink,
        img: "https://www.****" + articleImg,
        dealer: dealer.substring(dealer.indexOf(' ') + 1)
    }

    const article = { ...detailsOne, ...detailsTwo }

    articlesAll.push(article);
}

innerHTML方案代码(耗时5秒)

let articleHandles = await page.$$eval('.SearchResult_searchResultItemWrapper__VVVnZ', e => { return e.map(a => a.innerHTML) })
for (handle of articleHandles) {
    console.log(handle)
}

补充信息

  • 目标页面采用无限滚动,我滚动10次加载400个元素
  • 我也可通过URL参数切换页面,但因使用Bright Data的爬虫浏览器需支付流量费用,为避免额外开销,当前每抓取400个元素后跳过10页(从第1页跳转至第11页)。页面本身对无限滚动加载的元素数量有限制,我发现每10页通过URL参数加载新页面是兼顾性能与开销的最优方式。

回答

从你给出的耗时数据来看,$$eval批量处理后配合HTML解析(或直接在浏览器端提取结构化数据)的方案,性能远优于逐个$eval处理Element Handles的方式,尤其针对百万级的抓取需求,这种性能差距会被持续放大,是更优选择。

原方案慢的核心原因

原方案的瓶颈在于频繁的跨进程通信:每次$eval和evaluate都是Node.js环境与浏览器页面环境之间的异步交互,400个元素每个要触发4-5次这类交互,累计上千次的异步调用延迟,直接导致了12-15秒的耗时。

最优优化方向

  1. 直接在浏览器端完成所有字段提取:
    完全可以把所有提取逻辑整合到$$eval的回调中,一次性返回结构化数据,只需要一次跨进程通信,耗时会和你获取innerHTML的5秒持平,还省去了本地解析HTML的步骤:

    const articlesAll = await page.$$eval('.SearchResult_searchResultItemWrapper__VVVnZ', items => {
        // 把cleanupArticleDescription的逻辑移到这里,避免数据来回传输
        const cleanupArticleDescription = (desc) => {
            // 原函数的处理逻辑
            return /* 处理后的结果 */;
        };
    
        return items.map(item => {
            const articleLink = item.querySelector('a')?.getAttribute('href') || '';
            const articleImg = item.querySelector('a>div>span>img')?.getAttribute('src') || '';
            const articleDesc = item.querySelector('div>div')?.innerText || '';
            const dealerEl = item.querySelector('div.SearchResult_companyWrapper__W5gTQ');
            const dealer = dealerEl ? dealerEl.innerText.substring(dealerEl.innerText.indexOf(' ') + 1) : "Not found";
    
            const detailsOne = cleanupArticleDescription(articleDesc);
    
            return {
                ...detailsOne,
                link: articleLink,
                img: "https://www.****" + articleImg,
                dealer: dealer
            };
        });
    });
    
  2. 若需使用HTML解析器:
    推荐用cheerio这类轻量库解析innerHTML,解析速度快,整体耗时仍远低于原方案,但相比直接在浏览器端提取,会多一步本地解析的开销,属于次优选择。

额外性能建议

  • 保持当前每10页跳转一次的策略,减少Bright Data的流量开销和页面跳转耗时
  • 无限滚动时,用page.waitForSelector配合滚动逻辑,确保元素完全加载后再抓取,避免数据遗漏
  • 百万级数据抓取建议分批次写入数据库,避免内存溢出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 02:32:38