iT邦幫忙

0

用JAVA解决验证码问题,已经为什么要避开验证码

在此博客文章中,我们将展示如何使用Java和某些第三方API解决验证码和二次验证码,以及为什么首先应该避免这两个问题。

所需要的Python代码(+验证码API),请参阅该文章
http://scraping.pro/2captcha-service-to-solve-recaptcha-2/ )。

帖子作者是ScrapingNinja.co的Kevin Sahin(https://about.me/kevinsahin)。

验证码求解

完全自动化的公开图灵测试可以区分计算机和人类,这也是验证码所代表的含义。 验证码用于防止漫游器访问网站或应用程序并对其执行操作。 验证码类型有数十种,但绝大多数的人至少看到了以下两种:
https://ithelp.ithome.com.tw/upload/images/20191105/20122505cf2jHAUGX3.png

https://ithelp.ithome.com.tw/upload/images/20191105/201225052KvRkfSyQq.jpg
最后一个是最常用的验证码机制,即Google ReCaptcha v2。这就是为什么我们要看看如何“破解”这些验证码。
用户唯一要做的就是单击复选框内部。然后,该服务将分析许多因素,以确定它是真实用户还是机器人。我们不知道具体如何完成,Google出于明显的原因没有透露这一点,但是已经有很多猜测:
• 点击行为分析,例如“用户点击哪里?”,光标加速等。
• 浏览器指纹
• 点击位置记录(您总是直接点击中心位置,还是像普通用户一样随机选择?)
• 浏览器历史记录和cookie
对于像第一个这样的老式验证码,光学字符识别和最新的机器学习框架提供了出色的求解精度(有时比人类更好),但是对于Recaptcha v2,最简单,更准确的方法是使用第三方服务。
许多公司正在提供使用真实的人工运算符来解决验证码的验证码解决方案API。我不特别推荐一个,但我发现2captcha.com(https://2captcha.com/?from=8377663) 易于使用且可靠,但相对昂贵(1000个Recaptchas( https://2captcha.com/?from=8377663)为2.99美元)。
在后台,这些API需要特定的站点密钥和目标网站URL。有了这些信息,他们就能让操作员解决验证码。

https://ithelp.ithome.com.tw/upload/images/20191105/201225059k5vCpFQSW.jpg

从技术上讲,Recaptcha挑战是一个带有一些神奇Javascript代码和一些隐藏输入的iFrame。当您通过单击或解决图像问题来“解决”问题时,隐藏的输入将填充有有效令牌。
正是这个令牌使我们感兴趣,2captcha API会将其发回。然后,我们将需要用此令牌填充隐藏的输入并提交表单。
您需要做的第一件事是在2captcha.com上创建一个帐户(https://2captcha.com/?from=8377663)并添加一些资金。然后,您将在主仪表板上找到您的API密钥。
我们建立了一个示例网页( https://www.javawebscrapingsandbox.com/captcha ), 其中包含一个简单的表单,一个输入和一个Recaptcha来解决:
https://ithelp.ithome.com.tw/upload/images/20191105/20122505oUZpz3rpoP.jpg

我们将在无标签栏模式下使用Chrome来发布此表单,并使用HtmlUnit对2captcha进行API调用(为此,我们可以使用任何其他HTTP客户端)。现在我们开始编码吧!

final String API_KEY = "YOUR_API_KEY" ;
final String API_BASE_URL = "http://2captcha.com/" ;
final String BASE_URL = "https://www.javawebscrapingsandbox.com/captcha";
WebClient client = new WebClient();
client.getOptions().setJavaScriptEnabled(false);
client.getOptions().setCssEnabled(false);
client.getOptions().setUseInsecureSSL(true);
java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
// replace with your own chromdriver path
final String chromeDriverPath = "/usr/local/bin/chromedriver" ;
System.setProperty("webdriver.chrome.driver", chromeDriverPath);
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless", "--disable-gpu", "--windowsize=1920,1200","--ignore-certificate-errors", "--silent");
options.addArguments("--user-agent=Mozilla/5.0 (X11; Linux x86_64)
AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/60.0.3112.113
Chrome/60.0.3112.113 Safari/537.36");
WebDriver driver = new ChromeDriver(options);
driver.get(BASE_URL);

这是一些实例化代码,可同时实例化WebDriver和WebClient以及API URL和密钥。
然后,我们必须调用与网站键,您的API密钥和网站网址2captcha API,如记录在这里( https://2captcha.com/2captcha-api?from=2354423#solving_recaptchav2_new )。该API应该以以下格式响应:OK | 123456。

String siteId = "" ;
WebElement elem = driver.findElement(By.xpath("//div[@class='g-recaptcha']"));
try {
    siteId = elem.getAttribute("data-sitekey");
} catch (Exception e) {
    System.err.println("Catpcha's div cannot be found or missing attribute data-sitekey");
    e.printStackTrace();
}
String QUERY = String.format("%sin.php?key=%s&method=userrecaptcha&googlekey=%s&pageurl=%s&here=now",
API_BASE_URL, API_KEY, siteId, BASE_URL);
Page response = client.getPage(QUERY);
String stringResponse = response.getWebResponse().getContentAsString();
String jobId = "";
if(!stringResponse.contains("OK")){
    throw new Exception("Error with 2captcha.com API, received : " + stringResponse);
}else{
    jobId = stringResponse.split("\\|")[1];
}

现在我们有了工作ID,我们必须遍历另一个API路由,以了解何时解决ReCaptcha并获取令牌,如文档中所述。如果尚未准备就绪,则返回CAPCHA_NOT_READY;如果准备就绪,则返回 OK | TOKEN:

boolean captchaSolved = false ;
while(!captchaSolved){
response = client.getPage(String.format("%sres.php?key=%s&action=get&id=%s",
API_BASE_URL, API_KEY, jobId));
if (response.getWebResponse().getContentAsString().contains("CAPCHA_NOT_READY")){
   Thread.sleep(3000);
   System.out.println("Waiting for 2Captcha.com ...");
} else {
   captchaSolved = true ;
   System.out.println("Captcha solved !");
}
}
String captchaToken = response.getWebResponse().getContentAsString().split("\\|")[1];

请注意,根据我的经验,最多可能需要1分钟。在循环中实施安全保护/超时可能是一个好主意,因为在极少数情况下,验证码永远不会得到解决。
现在我们有了魔术令牌,我们只需要找到隐藏的输入,用令牌填充它,然后提交表单即可。
Selenium API无法填充隐藏的输入,因此我们必须操纵DOM以使输入可见,填充并再次使其隐藏,以便我们可以单击Submit按钮:

JavascriptExecutor js = (JavascriptExecutor) driver ;
js.executeScript("document
.getElementById('g-recaptcha-response').style.display = 'block';");
WebElement textarea = driver.findElement(By
.xpath("//textarea[@id='g-recaptcha-response']"));
textarea.sendKeys(captchaToken);
js.executeScript("document
.getElementById('g-recaptcha-response').style.display = 'none';");
driver.findElement(By.id("name")).sendKeys("Kevin");
driver.getPageSource();
driver.findElement(By.id("submit")).click();
if(driver.getPageSource().contains("your captcha was successfully submitted")){
System.out.println("Captcha successfuly submitted !");
}else{
System.out.println("Error while submitting captcha");
}

就是这样:-)。您可以在此处(https://gist.github.com/ScrapingNinjaHQ/5df3f882327c58b6e7d6e2aacab1dbc0)找到整个Java代码。
通常,网站不会对每个HTTP请求都使用ReCaptcha,而仅对可疑请求或用于诸如创建帐户之类的特定操作使用ReCaptcha。您应始终尝试确定网站是否向您显示[Re]验证码,因为具有相同IP地址或相同用户代理的太多请求,或者您每秒发出的请求太多。
如您所见,“解决验证码”相当慢,因此“解决”此问题的最佳方法是首先避免验证码!为了做到这一点,我们向您推荐一篇文章,如何在不被阻止的情况下抓取网站(https://www.scrapingninja.co/blog/web-scraping-without-getting-blocked),请查看!
减少获得验证码的机会胜于解决它,它更便宜,更快。有时这是不可能的,因为网页会100%的时间显示验证码,但是在许多情况下,您可以聪明地使用刮板来绕过验证码。


尚未有邦友留言

立即登入留言