Puppeteer - 如何自动接受任何 URL 的 cookie 同意提示?

Pupeteer - how can I accept cookie consent prompts automatically for any URL?

使用 pupeteer 对网站进行截图时,会显示 cookie 同意提示。我想在截取屏幕截图之前关闭或接受这些提示。我面临的问题是大多数网站以不同的方式呈现 cookie 提示,因此很难将它们隔离开来。

如何使用 pupeteer 最好地定位和消除这些提示?

我认为没有通用的方法来执行此操作,因为这些提示是与页面中所有其他元素一样的元素。话虽如此,有一些尝试使用扩展名或过滤器列表来阻止它们,您可以尝试:

我没有测试过这些,不知道它们是否有效。

请记住 headless chrome 不支持扩展。在 puppeteer 中加载扩展:

const browser = await puppeteer.launch({
  headless: true,
  args: [
    '--disable-extensions-except=/path/to/manifest/folder/',
    '--load-extension=/path/to/manifest/folder/',
  ]
});

更新:用无头傀儡来对抗 cookie 同意的更通用方法

这种方法也远未完成,但展示了一种以不太具体的方式消除 cookie 同意弹出窗口的有效方法。它使用 语言 和通用的 选择器 来检测同意按钮和链接,而不是仅仅依赖于每个网站的确切选择器。

在下面的示例中,我的目标是容器中的元素 a, button,该容器在 id, class 中使用名称 cookie。我在这方面限制了按钮,所以我不会无意中随意点击网站。

此外,它使用正则表达式来识别通常用于接受 cookie 的按钮文本,可以用 ^(Accept all|Accept|I understand|Agree|Okay|OK)$ 替换或翻译成您选择的任何语言 (不区分大小写).

await page.evaluate(_ => {
    function xcc_contains(selector, text) {
        var elements = document.querySelectorAll(selector);
        return Array.prototype.filter.call(elements, function(element){
            return RegExp(text, "i").test(element.textContent.trim());
        });
    }
    var _xcc;
    _xcc = xcc_contains('[id*=cookie] a, [class*=cookie] a, [id*=cookie] button, [class*=cookie] button', '^(Alle akzeptieren|Akzeptieren|Verstanden|Zustimmen|Okay|OK)$');
    if (_xcc != null && _xcc.length != 0) { _xcc[0].click(); }
});

旧答案:

确实没有通用的方法来处理 cookie 同意弹出窗口,因为它们差异很大,甚至 chrome 扩展程序也无法处理所有问题。但是,您可以复制扩展程序的功能并管理您自己的列表,方法是在截取屏幕截图之前评估目标站点上的 JS 代码。

在我的例子中,我只是全部接受它们,尝试在无头模式下进行。在识别它们时添加更多选择器。如果您愿意,可以改用关闭按钮选择器。

接下来您会发现一些真实世界的场景,应该有助于您继续前进:

  • 处理 ids、类 和自定义 数据属性
  • 隐藏 iframes因为无法评估不同域上的代码
await page.evaluate(_ => {
    var xcc
    // ids
    var xcc_id = [
        'borlabsCookieOptionAll',
        'cookie-apply-all',
        'cookie-settings-all',
        // add ids here
    ];
    for (let i = 0; i < xcc_id.length; i++) {
        xcc = document.getElementById(xcc_id[i]);
        if (xcc != null) {
            xcc.click();
        }
    }
    // classes
    var xcc_class = [
        'accept-all',
        'accept-cookies-button',
        'avia-cookie-select-all',
        // add classes here
    ];
    for (let i = 0; i < xcc_class.length; i++) {
        xcc = document.getElementsByClassName(xcc_class[i]);
        if (xcc != null && xcc.length != 0) {
            xcc[0].click();
        }
    }

    // custom data attributes
    xcc = document.querySelectorAll('[data-cookieman-accept-all]'); if (xcc != null && xcc.length != 0) { xcc[0].click(); }

     // hide iframes, can't eval
    xcc = document.querySelectorAll("iframe[src*=eurocookie]"); if (xcc != null && xcc.length != 0) { xcc[0].style.display = 'none'; }
    xcc = document.querySelectorAll("iframe[src*=eurocookie]"); if (xcc != null && xcc.length > 1) { xcc[1].style.display = 'none'; }

});

肯定是一种更优雅的方式,但通过这种方式我能够快速组织我的列表,即时进行更改,排序和删除重复项代码编辑器,将它们保持为一行或数组。

或者,只需使用 { headless: false } 选项并加载一个扩展程序,按照建议为您执行此操作。干杯。

旁注:如果页面重新加载,与 cookie 同意弹出窗口的交互可能会导致您的代码中断(页面导航错误) .为了避免这种情况,我在 await page.evaluate( ... );

之后使用了 3000-4000 毫秒的固定时间延迟
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
await delay(3500);

它还捕获大量元刷新、JS 重定向并为大型资源加载提供一些额外时间。