在使用Puppeteer进行网络爬虫时,如何处理验证码?

22
我正在使用Puppeteer进行网页抓取,我刚刚注意到有时候,由于我从我的计算机上进行的访问量过多,所以我尝试抓取的网站要求输入验证码。验证码表单看起来像这样:captcha 因此,我需要帮助处理这个问题。我一直在考虑将验证码表单发送到客户端,因为我使用Express和EJS以便将值发送到我的主页,但我不知道Puppeteer是否可以发送这样的内容。
有什么想法吗?
4个回答

28

这是一个reCAPTCHA (版本2,可以在这里查看演示),它会显示给您,因为页面所有者不希望您自动抓取该页面。

您有以下选项:

选项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代码加载时,它将在表单中添加一个没有值的响应文本区域。它将看起来像这样:

当reCAPTCHA代码加载时,它将在表单中添加一个没有值的响应文本区域。它将看起来像这样:

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

在您解决了验证码之后,reCAPTCHA将在表单提交时向该文本字段添加一个非常长的字符串(之后可以由服务器/后端的reCAPTCHA服务进行检查)。


如何自行解决验证码

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

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

更多信息/阅读材料

谷歌没有太多关于reCAPTCHA如何工作的公共信息,因为这是机器人创建者和谷歌检测算法之间的猫鼠游戏,但是有一些在线资源提供了更多信息:

  • 谷歌的官方文档:显然,他们只解释了基础知识而不是后台如何工作。
  • InsideReCaptcha:这是一个来自2014年的项目,试图“反向工程”reCAPTCHA。尽管这很古老,但页面上仍有很多有用的信息。
  • StackOverflow上的另一个问题:这个问题包含一些关于reCAPTCHA的有用信息,但也有许多推测(很可能)过时的方法来愚弄reCAPTCHA。

@ThomasDondorf,您能否向我解释一下第三方验证码解决方案是如何工作的,当他们使用另一个IP和浏览器打开包含验证码的页面时?谷歌不会跟踪解决验证码的IP和浏览器吗?使用另一个浏览器、IP和位置解决的响应是如何可能的? - Sumeet
2
据我所知,验证码不受浏览器或IP地址的限制。如果您解决了验证码,无论您的浏览器“指纹”有多可疑,都可以通过。 - Thomas Dondorf
如果该网站允许您在显示CAPTCHA之前至少发出一个请求,则还有第四个选项,即使用具有“住宅”IP地址的代理提供商。他们会提供一堆IP地址,您可以从其中一个IP地址发出请求,直到获得CAPTCHA,然后切换到新的IP地址。 - user3064538

14

您应该采用以下组合方法:

  • 如果目标网站提供API,则使用API,这是最合法的方式。
  • 增加爬取请求之间的等待时间,不要向服务器发送大量请求。
  • 频繁更换IP地址。
  • 更改用户代理、浏览器视口大小和指纹。
  • 使用第三方解决方案来解决验证码问题。
  • 自行解决验证码,可以通过Thomas Dondorf的答案验证。基本上您需要等待验证码在另一个浏览器上出现,然后从那里解决它。第三方解决方案会为您完成这些操作。

免责声明:请勿滥用反验证码插件/服务来占用资源。资源是昂贵的。


基本上,使用2captcha等反验证码服务来处理持久性reCAPTCHA的想法是很好的。

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

// 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()
})

附注:

  • 还有其他插件可用,甚至我自己开发了一个非常简单的插件,因为验证码即使对于像我这样的人类来说也越来越难以解决。你可以在这里查看代码。
  • 我与2Captcha或任何其他上述第三方服务没有强烈的关联。
  • 我曾经创建了类似于Thomas Dondorf答案的我的解决方案,但很快就放弃了,因为验证码变得越来越荒谬,我没有精力去解决它们。

很遗憾,目标网站没有提供可用的API。我已经搜索过了...我测试了你的代码,但似乎有些问题。它无法解决验证码,因为它在周围出现了红色边框,并告诉我要证明我不是机器人:https://i.imgur.com/jIVPvuE.png。这是因为我的语言与英语不同吗? - user10021033
另外,token应该放什么呢?我已经将那些XXX替换为data-sitekey值了。这样正确吗? - user10021033
不,你需要从2captcha购买积分,并使用他们的API(我与他们无关)。如果您不想花钱,那么唯一的另一种方法就是自己解决验证码,这不是我的答案,但Thomas Dondorf在另一个答案中添加了它。有人必须解决验证码,可以是您或其他人。 :D - Md. Abu Taher

2
我尝试了@Thomas Dondorf的建议,但我认为在"How to solve the captcha yourself"部分描述的步骤中存在的问题是CAPTCHA的令牌只有一次有效。我将尽力在下面详细解释。 我使用的工具 我首先使用Google Chrome浏览器(不会解决验证码),然后使用Firefox浏览器(解决验证码并获取令牌)。 步骤
  1. 我手动解决了这个网站https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php上的验证码。
  2. 我在Google Chrome控制台中输入以下代码document.querySelector('#g-recaptcha-response').value,但是我得到一个错误(VM22:1未捕获的TypeError:无法读取null的属性'value', 在:1:48),所以我只需通过打开Google Chrome中的Elements并使用CTRL + F搜索g-recaptcha-response来查找令牌。
  3. 我复制了reCAPTCHA的令牌(这里有一张图片显示高亮文本后的令牌位置)here is the part of the code of the webpage that has the token
  4. 我在Firefox控制台中输入以下代码document.querySelector('#g-recaptcha-response').value = '...',将“...”替换为刚刚复制的reCAPTCHA令牌。
  5. 我得到以下错误error,如果您点击链接的文档,您将看到该错误是由于令牌只能使用一次,并且它已经被用于您刚刚解决的CAPTCHA以获取令牌本身(因此似乎令牌的唯一目的是表明CAPTCHA已经被解决,它似乎是一种防御措施,以防止重放攻击,如reCAPTCHA的官方文档中所述)。

1
代理服务器可用于使目标网站不会检测到来自单个IP地址的响应负载。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接