puppeteer / node.js - 进入页面,点击加载更多直到所有评论加载,将页面保存为mhtml

Posted

技术标签:

【中文标题】puppeteer / node.js - 进入页面,点击加载更多直到所有评论加载,将页面保存为mhtml【英文标题】:puppeteer / node.js - enter page, click load more until all comments load, save page as mhtml 【发布时间】:2022-01-20 17:55:33 【问题描述】:

我想要完成的是进入此站点https://www.discoverpermaculture.com/permaculture-masterclass-video-1 等到它加载,从disqus 加载所有cmets(单击“加载更多cmets”按钮直到它不再存在)并将页面保存为mhtml 以供离线使用。

我在这里Puppeteer / Node.js to click a button as long as it exists -- and when it no longer exists, commence action 发现了类似的问题,但不幸的是,由于某种原因,尝试检测“加载更多 cmets”按钮不起作用。

似乎 WaitForSelector('a.load-more__button') 不起作用,因为它打印出来的只是“不可见”。

这是我的代码

const puppeteer = require('puppeteer');
const url = "https://www.discoverpermaculture.com/permaculture-masterclass-video-1";

const isElementVisible = async (page, cssSelector) => 
    let visible = true;
    await page
        .waitForSelector(cssSelector,  visible: true, timeout: 4000 )
        .catch(() => 
            console.log('not visible');
            visible = false;
        );
    return visible;
;

async function run () 

    let browser = await puppeteer.launch(
        headless: true,
        defaultViewport: null,
        args: [
            '--window-size=1920,10000',
        ],
    );
    const page = await browser.newPage();
    const fs = require('fs');
    await page.goto(url);
    await page.waitForNavigation();
    await page.waitForTimeout(4000)

    const selectorForLoadMoreButton = 'a.load-more__button';
    let loadMoreVisible = await isElementVisible(page, selectorForLoadMoreButton);
    while (loadMoreVisible) 
        console.log('load more visible');
        await page
            .click(selectorForLoadMoreButton)
            .catch(() => );
    await page.waitForTimeout(4000);

        loadMoreVisible = await isElementVisible(page, selectorForLoadMoreButton);
    

    const cdp = await page.target().createCDPSession();
    const  data  = await cdp.send('Page.captureSnapshot',  format: 'mhtml' );
    fs.writeFileSync('page.mhtml', data);
    browser.close();

run();

【问题讨论】:

【参考方案1】:

您只是在等待处理 ajax 请求。您可以简单地保存 cmets 的总数(DISQUS 插件的左上角)并将其与 cmets 数组进行比较,一旦数组等于总数,然后您就检索了每个 cmets。

我已经发布了一些关于等待 ajax 请求的内容,您可以在此处查看:https://***.com/a/66092889/3645650。


或者,一种更简单的方法是只使用 DISQUS api。

评论是公开的。您可以使用网站上的 api 密钥:

https://disqus.com/api/3.0/threads/listPostsThreaded?limit=50&thread=7187962034&forum=pdc2018&order=popular&cursor=1%3A0%3A0&api_key=E8Uh5l5fHZ6gD8U3KycjAIAk46f68Zw7C6eW8WSjZvCLXebZ7p0r1yrYDrLilk2F

parameter options
limit Default to 50. Maximum is 100.
thread Thread number. eg: 7187962034.
forum Forum id. eg: pdc2018.
order desc, asc, popular.
cursor Probably the page number. Format is 1:0:0. eg: Page 2 would be 2:0:0.
api_key The platform api key. Here the api key is E8Uh5l5fHZ6gD8U3KycjAIAk46f68Zw7C6eW8WSjZvCLXebZ7p0r1yrYDrLilk2F.

如果您必须遍历不同的页面,则需要拦截 xhr 响应以检索线程号。

【讨论】:

我很确定这个 WaitForSelector 有问题。我已经编辑了我的代码(愚蠢的方法,但添加了一些控制台日志和 4 秒超时,这似乎工作正常,因为当我保存屏幕截图时,我可以看到所有 cmets 都已加载并且“加载更多 cmets”按钮可见。当我运行此代码时屏幕上打印的所有内容都是“不可见”,这看起来很奇怪。 试图通过“span.comment-count”选择器获取评论数,但也没有用。【参考方案2】:

原来问题在于 disqus cmets 在 iframe 中

//needed to add those 2 lines
const elementHandle = await page.waitForSelector('iframe');
const frame = await elementHandle.contentFrame();

//and change 'page' to 'frame' below
let loadMoreVisible = await isElementVisible(frame, selectorForLoadMoreButton);
while (loadMoreVisible) 
    console.log('load more visible');
    await frame
        .click(selectorForLoadMoreButton)
        .catch(() => );
    await frame.waitForTimeout(4000);
    loadMoreVisible = await isElementVisible(frame, selectorForLoadMoreButton);

修改后就完美了

【讨论】:

以上是关于puppeteer / node.js - 进入页面,点击加载更多直到所有评论加载,将页面保存为mhtml的主要内容,如果未能解决你的问题,请参考以下文章

Node.js puppeteer - 如何设置导航超时?

使用Puppeteer将Node悬停在Node.js中的element和getComputedStyle上?

如何使用 puppeteer 和 Node js 为 pdf 页面生成屏幕截图

使用 Puppeteer 和 Node.JS 在网站上的 iFrame 中找不到隐藏的输入元素

Node Js & Puppeteer - 如何选择包裹在 Anchor 标签内的文本

如何在 puppeteer Node.js 中将 const 添加到 await page.$eval?