我正在使用 Puppeteer 进行网页抓取,但我刚刚注意到,有时,由于我通过计算机进行的访问量太大,我尝试抓取的网站会要求提供验证码。验证码表单如下所示:
所以,我需要关于如何处理这个问题的帮助。我一直在考虑将验证码表单发送到客户端,因为我使用 Express 和 EJS 以便将值发送到我的索引网站,但我不知道 Puppeteer 是否可以发送类似的东西。
有任何想法吗?
我正在使用 Puppeteer 进行网页抓取,但我刚刚注意到,有时,由于我通过计算机进行的访问量太大,我尝试抓取的网站会要求提供验证码。验证码表单如下所示:
所以,我需要关于如何处理这个问题的帮助。我一直在考虑将验证码表单发送到客户端,因为我使用 Express 和 EJS 以便将值发送到我的索引网站,但我不知道 Puppeteer 是否可以发送类似的东西。
有任何想法吗?
这是一个 reCAPTCHA(第 2 版,在此处查看演示),向您显示该页面的所有者不希望您自动抓取该页面。
您的选择如下:
由于页面所有者不希望您抓取该页面,您可以简单地尊重该决定并停止抓取。也许有一个文档化的 API 可供您使用。
整个行业都有人(通常在发展中国家)为其他人的机器人填写验证码。我不会链接到任何特定站点,但您可以查看Md. Abu Taher的其他答案以获取有关该主题的更多信息或搜索验证码求解器。
为此,让我解释一下 reCAPTCHA 的工作原理以及使用它访问页面时会发生什么。
每个页面都有一个ID,可以通过查看源代码来查看,例如:
<div class="g-recaptcha form-field" data-sitekey="ID_OF_THE_WEBSITE_LONG_RANDOM_STRING"></div>
加载 reCAPTCHA 代码后,它将向表单添加一个没有值的响应文本区域。它看起来像这样:
<textarea id="g-recaptcha-response" name="g-recaptcha-response" class="g-recaptcha-response" style="... display: none;"></textarea>
在您解决挑战后,当提交表单时,reCAPTCHA 将向此文本字段添加一个很长的字符串(稍后可以由后端的服务器/reCAPTCHA 服务进行检查)。
通过复制该textarea
字段的值,您可以将“已解决的挑战”从一个浏览器转移到另一个浏览器(这也是解决方案为您提供的服务)。整个过程如下所示:
.g-recaptcha
在“爬行”浏览器中使用 reCAPTCHA(例如检查)document.querySelector('#g-recaptcha-response').value
document.querySelector('#g-recaptcha-response').value = '...'
谷歌没有太多公开信息,reCAPTCHA 究竟是如何工作的,因为这是机器人创建者和谷歌检测算法之间的猫捉老鼠游戏,但网上有一些资源提供更多信息:
您应该使用以下组合:
免责声明:请勿使用反验证码插件/服务来滥用资源。资源很贵。
基本上这个想法是使用像 (2captcha) 这样的反验证码服务来处理持久化的验证码。
您可以使用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()
})
PS:
可以使用代理服务器,以便目标站点不会检测到来自单个 IP 地址的大量响应。
(翻译成谷歌翻译)
我尝试了@Thomas Dondorf 的建议,但我认为“如何自己解决验证码”部分中描述的步骤的问题在于验证码的令牌仅有效一次。我将尝试在下面详细解释所有内容。
我在用什么
我使用第一个浏览器(无法解决验证码的浏览器)Google Chrome,以及第二个浏览器(我解决验证码并获取令牌的浏览器)Firefox。
脚步
document.querySelector('#g-recaptcha-response').value
在 google chrome 控制台中输入以下代码,但出现错误(VM22:1 Uncaught TypeError: Cannot read property 'value' of null at :1:48),所以我只是通过在 Google Chrome 中打开 Elements 来搜索令牌并g-recaptcha-response
使用 CTRL+F搜索document.querySelector('#g-recaptcha-response').value = '...'
在 firefox 控制台中键入以下代码,用刚刚复制的 recaptcha 令牌替换“...”