【问题标题】:How to deal with the captcha when doing Web Scraping in Puppeteer?在 Puppeteer 中进行 Web Scraping 时如何处理验证码?
【发布时间】:2019-08-24 21:17:21
【问题描述】:

我正在使用 Puppeteer 进行 Web Scraping,我刚刚注意到,由于我在计算机上进行的访问量很大,我尝试抓取的网站有时会要求提供验证码。验证码表单如下所示:

所以,我需要有关如何处理此问题的帮助。自从我使用 Express 和 EJS 将值发送到我的索引网站以来,我一直在考虑将验证码表单发送到客户端,但我不知道 Puppeteer 是否可以发送类似的东西。

有什么想法吗?

【问题讨论】:

    标签: javascript web-scraping captcha puppeteer


    【解决方案1】:

    这是一个 reCAPTCHA(第 2 版,请查看 demos here),显示给您的是页面所有者不希望您自动抓取该页面。

    您的选择如下:

    选项 1:停止抓取或尝试使用官方 API

    由于网页所有者不希望您抓取该网页,您只需尊重该决定并停止抓取即可。也许有一个记录在案的 API 可供您使用。

    选项 2:自动化/外包验证码解决方案

    整个行业都有人(通常在发展中国家)为其他人的机器人填写验证码。我不会链接到任何特定站点,但您可以查看 Md 的其他答案。 Abu Taher 了解有关该主题的更多信息或搜索 captcha solver

    选项 3:自己解决验证码

    为此,让我解释一下 reCAPTCHA 的工作原理以及当您访问使用它的页面时会发生什么。


    reCAPTCHA (v2) 的工作原理

    每个页面都有一个ID,可以通过查看源代码来检查,例如:

    <div class="g-recaptcha form-field" data-sitekey="ID_OF_THE_WEBSITE_LONG_RANDOM_STRING"></div>
    

    当 reCAPTCHA 代码被加载时,它会在表单中添加一个 response 文本区域,但没有任何值。它看起来像这样:

    <textarea id="g-recaptcha-response" name="g-recaptcha-response" class="g-recaptcha-response" style="... display: none;"></textarea>
    

    在您解决挑战后,reCAPTCHA 会在提交表单时向此文本字段添加一个很长的字符串(稍后可以由后端的 server/reCAPTCHA 服务检查)。


    如何自己解决验证码

    通过复制textarea 字段的值,您可以将“已解决的挑战”从一个浏览器转移到另一个浏览器(这也是解决服务为您提供的内容)。整个过程如下所示:

    1. 检测页面是否在“抓取”浏览器中使用 reCAPTCHA(例如检查 .g-recaptcha
    2. 在非无头模式下使用相同的 URL 打开第二个浏览器
    3. 自己解决验证码
    4. 从以下位置读取值:document.querySelector('#g-recaptcha-response').value
    5. 将该值放入第一个浏览器:document.querySelector('#g-recaptcha-response').value = '...'
    6. 提交表格

    更多信息/阅读

    Google 提供的公开信息并不多,reCAPTCHA 的工作原理是什么,因为这是机器人创建者和 Google 检测算法之间的猫捉老鼠游戏,但网上有一些资源提供了更多信息:

    • Official docs from Google:显然,他们只是解释了基础知识,而不是“在后面”如何工作
    • InsideReCaptcha:这是 2014 年的一个项目,它试图“逆向工程”reCAPTCHA。虽然这很老了,但页面上仍然有很多有用的信息。
    • Another question on stackoverflow:这个问题包含一些关于 reCAPTCHA 的有用信息,但也包含许多关于如何欺骗 reCAPTCHA 的推测性(并且很可能)过时的方法。

    【讨论】:

    • @ThomasDondorf 您能否向我解释一下第三方验证码解决方案在使用另一个 IP 和浏览器打开包含验证码的页面时是如何工作的?谷歌不跟踪正在解决验证码的 IP 和浏览器吗?以及如何使用其他浏览器、IP 和位置解决的响应?
    • @sumeet AFAIK 验证码未绑定到浏览器或 IP 地址。如果你解决了验证码,你就可以通过,不管你的浏览器“指纹”有多么阴暗。
    • 如果网站允许您在显示验证码之前至少提出一个请求,还有第 4 种选择,即使用具有“住宅”IP 地址的代理提供商。他们给你一堆IP地址,你从一个IP地址发出请求,直到你得到验证码,然后切换到一个新的IP地址。
    【解决方案2】:

    您应该使用以下组合:

    • 如果目标网站提供 API,请使用该 API。这是最合法的方式。
    • 增加抓取请求之间的等待时间,不要向服务器发送大量请求。
    • 经常更改/轮换 IP。
    • 更改用户代理、浏览器视口大小和指纹。
    • 对验证码使用第三方解决方案。
    • 自己解决验证码,检查 Thomas Dondorf 的答案。基本上你需要等待验证码出现在另一个浏览器上,然后从那里解决。第三方解决方案为您做到这一点。

    免责声明:请勿使用反验证插件/服务滥用资源。资源很昂贵。


    基本上这个想法是使用像 (2captcha) 这样的反验证码服务来处理持久的验证码。

    您可以使用 berstend 的名为 puppeteer-extra-plugin-recaptcha 的插件。

    // puppeteer-extra is a drop-in replacement for puppeteer,
    // it augments the installed puppeteer with plugin functionality
    const puppeteer = require('puppeteer-extra')
    
    // add recaptcha plugin and provide it your 2captcha token
    // 2captcha is the builtin solution provider but others work as well.
    const RecaptchaPlugin = require('puppeteer-extra-plugin-recaptcha')
    puppeteer.use(
      RecaptchaPlugin({
        provider: { id: '2captcha', token: 'XXXXXXX' },
        visualFeedback: true // colorize reCAPTCHAs (violet = detected, green = solved)
      })
    )
    

    之后,您可以照常运行浏览器。它将获取页面上的任何验证码并尝试解决它。如果存在,您必须找到因站点而异的提交按钮。

    // puppeteer usage as normal
    puppeteer.launch({ headless: true }).then(async browser => {
      const page = await browser.newPage()
      await page.goto('https://www.google.com/recaptcha/api2/demo')
    
      // That's it, a single line of code to solve reCAPTCHAs ?
      await page.solveRecaptchas()
    
      await Promise.all([
        page.waitForNavigation(),
        page.click(`#recaptcha-demo-submit`)
      ])
      await page.screenshot({ path: 'response.png', fullPage: true })
      await browser.close()
    })
    

    PS:

    • 还有其他插件,甚至我也做了一个非常简单的插件,因为即使对于像我这样的人来说,验证码也越来越难以解决。您可以阅读代码here
    • 我强烈不隶属于 2Captcha 或上述任何其他第三方服务。
    • 我创建了自己的解决方案,这与 Thomas Dondorf 的其他答案类似,但很快就放弃了,因为验证码变得越来越荒谬,我没有精力解决它们。

    【讨论】:

    • 遗憾的是,目标网站没有提供 API 来使用。我已经搜索过了...我已经测试了你的代码,但似乎有问题。它不能解决验证码,因为它周围出现红色边框,它告诉我证明我不是机器人:i.imgur.com/jIVPvuE.png。是不是因为我的语言与英语不同?
    • 另外,我应该在令牌中放入什么?我已将那些 XXX 替换为 data-sitekey 值。对吗?
    • 不,你从 2captcha 购买积分,使用他们的 API(我不隶属于他们)。如果您不想用钱,那么唯一的另一种方法是自己解决验证码,我没有将其添加到我的答案中,但 Thomas Dondorf 将其添加到了另一个答案中。有人必须解决验证码,您或其他人。 :D
    【解决方案3】:

    可以使用代理服务器,这样目标站点就不会检测到来自单个 IP 地址的响应负载。

    (翻译成谷歌翻译)

    【讨论】:

      【解决方案4】:

      我尝试了@Thomas Dondorf 的建议,但我认为“如何自己解决验证码”部分中描述的步骤的问题是验证码的令牌仅有效一次。 我将尝试在下面详细解释所有内容。

      我在用什么

      我使用的是第一个浏览器(不会解决验证码的那个)Google Chrome,以及第二个浏览器(我解决验证码并获取令牌的那个)Firefox。

      步骤

      1. 我在本站手动解验证码https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php
      2. 我在 google chrome 控制台中输入以下代码 document.querySelector('#g-recaptcha-response').value,但出现错误 (VM22:1 Uncaught TypeError: Cannot read property 'value' of null at :1:48),所以我只需通过在 Google Chrome 中打开 Elements 并使用 CTRL+F 搜索 g-recaptcha-response 来搜索令牌
      3. 我复制了recaptcha 的标记(这是显示标记在哪里的图像,在以绿色突出显示的文本之后)
      4. 我在 Firefox 控制台中键入以下代码 document.querySelector('#g-recaptcha-response').value = '...',将“...”替换为刚刚复制的验证码
      5. 我收到以下错误,如果您然后单击documentation linked,您会看到该错误是由于令牌只能使用一次这一事实,它当然有已经用于您刚刚解决的 CAPTCHA 以获得令牌本身(所以似乎令牌的唯一目标是说 CAPTCHA 已经被解决,这似乎是一种防止重放攻击的防御措施,如所说在这里official documentation of the recaptcha

      【讨论】:

        猜你喜欢
        • 2021-11-18
        • 2018-03-25
        • 1970-01-01
        • 1970-01-01
        • 2018-02-28
        • 1970-01-01
        • 2021-12-12
        • 2020-12-15
        • 2022-07-14
        相关资源
        最近更新 更多