【问题标题】:Bypassing CAPTCHAs with Headless Chrome using puppeteer使用 puppeteer 通过 Headless Chrome 绕过 CAPTCHA
【发布时间】:2019-09-04 18:44:52
【问题描述】:

google 发现我的浏览器被软件设置为manipulated/controlled/automated,因此我得到reCaptcha。当我手动启动 chromium 并执行相同的步骤时,reCaptcha 不会出现。

Question 1)

使用puppeteer时是否可以通过编程方式解决验证码或摆脱它?有什么办法解决吗?

Question 2)

只有在没有headless选项i.e时才会发生这种情况

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

或者这是我们必须接受并继续前进的事实?

【问题讨论】:

  • 查看这篇博文。这和你自己的情况很接近。 medium.com/@jsoverson/…
  • 我已经看过那个博客了。他使用2captcha 这不是免费的:P
  • 您接受的答案是来自 2captcha.com 的付费服务。如果您想付款,为什么要使用 Headless Chrome + Puppeteer?你为什么不直接使用CURL

标签: javascript node.js puppeteer


【解决方案1】:

尝试使用此npm package 生成随机用户代理。 这通常解决了基于用户代理的保护。

在 puppeteer 页面中可以使用 page.setUserAgent 覆盖浏览器用户代理

var userAgent = require('user-agents');
...
await page.setUserAgent(userAgent.toString())

另外,你可以添加这两个额外的插件,

puppeteer-extra-plugin-recaptcha - 使用一行代码自动解决 reCAPTCHA:page.solveRecaptchas()

注意:puppeteer-extra-plugin-recaptcha 使用付费服务2captcha

puppeteer-extra-plugin-stealth - 应用各种规避技术,使检测无头傀儡变得更加困难。

【讨论】:

  • 此解决方案使用 2captcha.com 的付费服务。如果您使用 2captcha PAID 服务,则不需要所有这些东西!
  • 是的。这不仅仅是一行代码。您还需要注册该服务并为每一个验证码支付费用
【解决方案2】:

以下是我为绕过验证码和类似阻止而采取的一系列措施:

  • 启用隐身模式(通过 puppeteer-extra-plugin-stealth)
  • 随机化用户代理或设置一个有效的(通过随机用户代理)
  • 随机化视口大小
  • 跳过图像/样式/字体加载以获得更好的性能
  • 通过“WebDriver 检查”
  • 通过“Chrome 检查”
  • 通过“通知检查”
  • 通过“插件检查”
  • 通过“语言检查”

Link to full code is here

    const randomUseragent = require('random-useragent');

    //Enable stealth mode
    const puppeteer = require('puppeteer-extra')
    const StealthPlugin = require('puppeteer-extra-plugin-stealth')
    puppeteer.use(StealthPlugin())
    
    const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36';
    
    async function createPage (browser,url) {

        //Randomize User agent or Set a valid one
        const userAgent = randomUseragent.getRandom();
        const UA = userAgent || USER_AGENT;
        const page = await browser.newPage();

        //Randomize viewport size
        await page.setViewport({
            width: 1920 + Math.floor(Math.random() * 100),
            height: 3000 + Math.floor(Math.random() * 100),
            deviceScaleFactor: 1,
            hasTouch: false,
            isLandscape: false,
            isMobile: false,
        });

        await page.setUserAgent(UA);
        await page.setJavaScriptEnabled(true);
        await page.setDefaultNavigationTimeout(0);

        //Skip images/styles/fonts loading for performance
        await page.setRequestInterception(true);
        page.on('request', (req) => {
            if(req.resourceType() == 'stylesheet' || req.resourceType() == 'font' || req.resourceType() == 'image'){
                req.abort();
            } else {
                req.continue();
            }
        });

        await page.evaluateOnNewDocument(() => {
            // Pass webdriver check
            Object.defineProperty(navigator, 'webdriver', {
                get: () => false,
            });
        });

        await page.evaluateOnNewDocument(() => {
            // Pass chrome check
            window.chrome = {
                runtime: {},
                // etc.
            };
        });

        await page.evaluateOnNewDocument(() => {
            //Pass notifications check
            const originalQuery = window.navigator.permissions.query;
            return window.navigator.permissions.query = (parameters) => (
                parameters.name === 'notifications' ?
                    Promise.resolve({ state: Notification.permission }) :
                    originalQuery(parameters)
            );
        });

        await page.evaluateOnNewDocument(() => {
            // Overwrite the `plugins` property to use a custom getter.
            Object.defineProperty(navigator, 'plugins', {
                // This just needs to have `length > 0` for the current test,
                // but we could mock the plugins too if necessary.
                get: () => [1, 2, 3, 4, 5],
            });
        });

        await page.evaluateOnNewDocument(() => {
            // Overwrite the `languages` property to use a custom getter.
            Object.defineProperty(navigator, 'languages', {
                get: () => ['en-US', 'en'],
            });
        });

        await page.goto(url, { waitUntil: 'networkidle2',timeout: 0 } );
        return page;
    }

【讨论】:

  • 这个配置给了我这个消息:Please upgrade to a supported browser to get a reCAPTCHA challenge. 并且不允许登录
  • 尝试将const UA = userAgent || USER_AGENT;改为-const UA = USER_AGENT;
  • 谢谢你,我想这些东西现在已经在puppeteer-extra-plugin-stealth里面了
【解决方案3】:

您是否尝试过设置浏览器代理?

await page.setUserAgent('5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36');

【讨论】:

  • 没有。会试一试。但是拥有相同的 UserAgent 会发生什么? UserAgent 不是 random 吗?能介绍一下吗?
  • 默认代理表示您正在使用 puppeteer,因此将其设置为 chrome(如上)可以让您通过基本测试。但是你仍然会在某个时候得到验证码。如果你登录它也可能有助于让你的刮板工作一段时间。
  • 即使在设置了特定的用户代理之后,我们也会在一些登录后得到验证码。所以我尝试每次使用 npm 包 (npmjs.com/package/random-useragent) 生成随机用户代理。现在它工作正常。
  • 这个答案很好,但是用户代理已经很老了(在我写这个答案时,69.0.3497 已经几个月了),现在最新的是:`` ` Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Brave Chrome/84.0.4147.89 Safari/537.36 ``` [developers.whatismybrowser.com/useragents/explore/software_name/…如果你想要其他版本
【解决方案4】:

经过几次测试,几个包帮助我避免了重复验证:

//const puppeteer = require('puppeteer');
const puppeteerExtra = require('puppeteer-extra');
const pluginStealth = require('puppeteer-extra-plugin-stealth');
const randomUseragent = require('random-useragent');

class PuppeteerService {

    constructor() {
        this.browser = null;
        this.page = null;
        this.pageOptions = null;
        this.waitForFunction = null;
        this.isLinkCrawlTest = null;
    }

    async initiate(countsLimitsData, isLinkCrawlTest) {
        this.pageOptions = {
            waitUntil: 'networkidle2',
            timeout: countsLimitsData.millisecondsTimeoutSourceRequestCount
        };
        this.waitForFunction = 'document.querySelector("body")';
        puppeteerExtra.use(pluginStealth());
        //const browser = await puppeteerExtra.launch({ headless: false });
        this.browser = await puppeteerExtra.launch({ headless: false });
        this.page = await this.browser.newPage();
        await this.page.setRequestInterception(true);
        this.page.on('request', (request) => {
            if (['image', 'stylesheet', 'font', 'script'].indexOf(request.resourceType()) !== -1) {
                request.abort();
            } else {
                request.continue();
            }
        });
        this.isLinkCrawlTest = isLinkCrawlTest;
    }

    async crawl(link) {
        const userAgent = randomUseragent.getRandom();
        const crawlResults = { isValidPage: true, pageSource: null };
        try {
            await this.page.setUserAgent(userAgent);
            await this.page.goto(link, this.pageOptions);
            await this.page.waitForFunction(this.waitForFunction);
            crawlResults.pageSource = await this.page.content();
        }
        catch (error) {
            crawlResults.isValidPage = false;
        }
        if (this.isLinkCrawlTest) {
            this.close();
        }
        return crawlResults;
    }

    close() {
        if (!this.browser) {
            this.browser.close();
        }
    }
}

const puppeteerService = new PuppeteerService();
module.exports = puppeteerService;

【讨论】:

    猜你喜欢
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    • 2018-07-24
    • 2018-06-12
    • 1970-01-01
    • 2021-09-18
    相关资源
    最近更新 更多