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

如何用Puppeteer提取同class嵌套标签的全部innerText

问题:Puppeteer仅提取首个新闻实例内容,无法获取后续条目

我正在学习JavaScript和Puppeteer,以《卫报》首页作为练习场景(其HTML标签与类嵌套结构复杂)。我编写了一段脚本,尝试提取指定4个类名(fc-item__kicker、js-headline-text、a标签href、fc-item__standfirst)的内容,但目前仅能提取首个实例的内容,无法获取后续同选择器实例的内容。

HTML片段

<!DOCTYPE html>
<html>
<body>
    <div class="l-side-margins">
        <div class="facia-page">
            <section id="headlines" class="fc-container fc-container--has-toggle">
                <div class="fc-container__inner">
                    <div class="fc-container--rolled-up-hide fc-container__body" id="container-10f21d96-18f6-426f-821b-19df55dfb831">
                        <div class="fc-slice-wrapper">
                            <ul class="u-unstyled l-row l-row--cols-4 fc-slice fc-slice--qqq-q">
                                <li class="fc-slice__item l-row__item l-row__item--span-3 u-faux-block-link">
                                    <div class="fc-item__container">
                                        <div class="fc-item__content">
                                            <div class="fc-item__header">
                                                <h3 class="fc-item__title"><a class="fc-item__link" href="https://www.example.com"><span class="fc-item__kicker">Monterey Park shooting</span> <span class="u-faux-block-link__cta fc-item__headline"><span class="js-headline-text">Beloved dance hall manager named among victims</span></span></a></h3>
                                            </div>
                                            <div class="fc-item__standfirst-wrapper">
                                                <div class="fc-item__standfirst">
                                                    California officials yet to identify eight others who died in Saturday attack, at least 36th mass shooting in US so far this year
                                                </div>
                                            </div>
                                            <div class="fc-item__footer--vertical">
                                                <ul class="fc-sublinks u-unstyled u-faux-block-link__promote">
                                                    <li class="fc-sublink fc-sublink--pillar-news fc-sublink--type-article">
                                                        <h4 class="fc-sublink__title"><a class="fc-sublink__link" href="https://www.example.com"><span class="fc-sublink__kicker">LA mass shooting</span> Man who disarmed California shooter tells of violent struggle for gun</a></h4>
                                                    </li>
                                                </ul>
                                            </div>
                                        </div>
                                    </div>
                                </li>
                            </ul>
                        </div>
                        <div class="fc-slice-wrapper">
                            <ul class="u-unstyled l-row l-row--cols-4 fc-slice fc-slice--q-q-ql-ql">
                                <li class="fc-slice__item l-row__item l-row__item--span-1 u-faux-block-link">
                                    <div class="fc-item fc-item--has-image fc-item--pillar-news fc-item--type-article js-fc-item fc-item--list-media-mobile fc-item--standard-tablet js-snappable">
                                        <div class="fc-item__container">
                                            <div class="fc-item__media-wrapper">
                                                <div class="fc-item__image-container u-responsive-ratio"></div>
                                            </div>
                                            <div class="fc-item__content">
                                                <div class="fc-item__header">
                                                    <h3 class="fc-item__title"><a class="fc-item__link" href="https://www.example.com"><span class="fc-item__kicker">Germany</span> <span class="u-faux-block-link__cta fc-item__headline"><span class="js-headline-text">Five charged over second alleged far-right plot against government</span></span></a></h3>
                                                </div>
                                                <div class="fc-item__standfirst-wrapper">
                                                    <div class="fc-item__standfirst">
                                                        Four men and a woman accused of planning to abduct health minister and overthrow government
                                                    </div>
                                                    <div class="fc-item__meta js-item__meta"></div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </div>
</body>
</html>

现有脚本

const fs = require('fs');
const puppeteer = require('puppeteer');

async function run() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://www.theguardian.com/international/');

    const headlines = await page.evaluate(() => Array.from(document.querySelectorAll('#headlines'), (e) => ({
        kicker: e.querySelector('.fc-item__header .fc-item__kicker').innerText,
        headline: e.querySelector('.fc-item__header .js-headline-text').innerText,
        link: e.querySelector('.fc-item__header  a').href,
        standfirst: e.querySelector('.fc-item__standfirst-wrapper .fc-item__standfirst').textContent.replaceAll("  ", " ").trim(),
    })));

    console.log(headlines);
    
    console.log(headlines);
    // Save data to JSON file
    fs.writeFile('headlines.json', JSON.stringify(headlines), (err) => {
        if (err) throw err;
        console.log('File saved');
    });

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

期望结果

[
  {
    kicker: 'Monterey Park shooting',
    headline: 'Beloved dance hall manager named among victims',
    link: 'https://www.example.com',
    standfirst: 'California officials yet to identify eight others who died in Saturday attack, at least 36th mass shooting in US so far this year'
  },
  {
    kicker: 'Germany',
    headline: 'Five charged over second alleged far-right plot against government',
    link: 'https://www.example.com',
    standfirst: 'Four men and a woman accused of planning to abduct health minister and overthrow government'
  }
]

解决方案

问题根源

你的代码中使用document.querySelectorAll('#headlines'),但#headlines是页面中唯一的section元素,遍历后只会得到一个元素。在这个元素内部使用querySelector时,只会返回第一个匹配的子元素,因此只能提取到第一条新闻的数据。

修正后的脚本

const fs = require('fs');
const puppeteer = require('puppeteer');

async function run() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://www.theguardian.com/international/');

    // 选择每个新闻内容的容器,遍历所有匹配项
    const headlines = await page.evaluate(() => Array.from(document.querySelectorAll('#headlines .fc-item__content'), (item) => {
        // 为避免元素不存在报错,先检查元素是否存在
        const kickerEl = item.querySelector('.fc-item__header .fc-item__kicker');
        const headlineEl = item.querySelector('.fc-item__header .js-headline-text');
        const linkEl = item.querySelector('.fc-item__header a');
        const standfirstEl = item.querySelector('.fc-item__standfirst-wrapper .fc-item__standfirst');

        return {
            kicker: kickerEl ? kickerEl.innerText : '',
            headline: headlineEl ? headlineEl.innerText : '',
            link: linkEl ? linkEl.href : '',
            standfirst: standfirstEl ? standfirstEl.textContent.replaceAll("  ", " ").trim() : ''
        };
    }));

    console.log(headlines);
    // 使用fs.promises.writeFile替代回调式写法,更符合async/await风格
    await fs.promises.writeFile('headlines.json', JSON.stringify(headlines, null, 2));
    console.log('File saved');

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

关键改动说明

  1. 选择器调整:将遍历的目标从#headlines改为#headlines .fc-item__content,这个选择器会匹配所有新闻内容的容器,确保能拿到每一条新闻。
  2. 空值处理:在获取每个子元素时先检查元素是否存在,避免因页面结构变化导致脚本报错。
  3. 文件写入优化:使用fs.promises.writeFile替代传统的回调式写法,与async/await风格保持一致,代码更简洁易读。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:15:41