如何在我的客户端应用程序中处理第三方站点上的recaptcha

时间:2016-03-03 09:17:44

标签: c# web-scraping dotnet-httpclient cloudflare recaptcha

我很好奇人们如何为没有公共API 的网站构建第三方应用,但我找不到关于此主题的任何教程。所以我决定尝试一下。我创建了一个简单的桌面应用程序,它使用HttpClient将GET请求发送到我经常使用的站点,然后解析响应并在我的WPF窗口中显示数据。这种方法效果很好(可能因为网站相当简单)。

但是,今天我尝试从不同的地方运行我的应用程序,并且我不断收到403错误以响应我的应用程序的请求。事实证明,我使用的网络通过VPN服务器,而我尝试访问的网站使用CloudFlare作为保护层,这显然迫使VPN用户进入reCaptcha以访问目标站点。

var baseAddress = new Uri("http://www.cloudflare.com");
using (var client = new HttpClient() { BaseAddress = baseAddress })
{
   var message = new HttpRequestMessage(HttpMethod.Get, "/");
   //this line returns CloudFlare home page if I use regualr network and reCaptcha page, when I use VPN
   var result = await client.SendAsync(message);
   //this line throws if I use VPN (403 Forbidden)
   result.EnsureSuccessStatusCode();
}

现在的问题是:在客户端应用程序中处理CloudFlare保护的正确方法是什么?我是否必须像在网络浏览器中那样在我的应用程序中显示reCaptcha?我是否必须设置任何特定标头才能获得正确的响应而不是403?欢迎任何提示,因为这对我来说是一个全新的领域。

P.S。我用C#写作是因为这是我最熟悉的语言,但只要他们回答这个问题,我就不介意使用任何其他语言。

3 个答案:

答案 0 :(得分:1)

我想,一种方法是在客户端应用程序之外的Web浏览器中处理验证码。

  1. 解析响应以查看它是否为验证码页面。
  2. 如果是 - 在浏览器中打开此页面。
  3. 让用户解决验证码。
  4. 获取CloudFlare cookies表单浏览器的cookie存储空间。您需要private private[this] private[package] (用户ID)和__cfduid(解决验证码的证明)。
  5. 将这些cookie附加到客户端应用程序发送的请求中。
  6. 在接下来的24小时内正常使用应用程序(直到CloudFlare cookies过期)。
  7. 现在困难的部分是(4)。手动复制粘贴cookie很容易,使我的问题中的代码片段与VPN一起工作:

    cf_clearance

    但是我认为,由于不同的浏览器在不同的地方和/或格式存储cookie,因此自动获取cookie的过程将是一项棘手的任务。不要说你需要使用外部浏览器才能使用这种方法,这真的很烦人。还有,需要考虑的事情。

答案 1 :(得分:1)

回答"为没有公共API的网站构建第三方应用程序"即使一些软件供应商没有公开的api,他们也有合作伙伴计划。

很好的例子是Netflix,他们曾经有一个公共API。启用Public Api时开发的一些应用程序允许继续使用api。

在您的方案中,您的客户端应用程序充当网络爬虫(下载HTML内容并尝试解析信息)。您要做的是抓取Cloudfare数据,这些数据不应由第三方应用程序(bot)抓取。从云计算方面来看,他们已经做了正确的事情来使用Captcha来阻止自动请求。

此外,如果您尝试以高频率发送请求(请求/秒),并且如果Cloudfare具有威胁检测机制,则您的IP地址将被阻止。我假设他们已经确定了您尝试使用的VPN服务器IP地址并将其列入黑名单,这就是您获得403的原因。

基本上,您完全依赖于您尝试通过客户端应用访问的Cloudfare页面中的安全漏洞。这是一种黑客攻击(做云量限制的事情),我不推荐。

如果您有一个很酷的主意,最好联系他们的开发团队并讨论相关问题。

答案 2 :(得分:1)

如果您仍然需要它,我遇到了同样的问题,并在2年前提出了以下解决方案。

它使用C#WebBrowser类打开Cloudflare保护的网页,等待大约6秒,以便CloudFlare保存许可cookie,然后程序将cookie保存到磁盘。

你需要一个支持javascript的浏览器,比如C#WebBrowser类,因为Cloudflare验证码页面需要javascript才能运行并倒计时以保存cookie,任何其他尝试都将失败。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Net;
using System.Threading;

namespace kek
{
    public partial class Form1 : Form
    {
        [DllImport("wininet.dll", SetLastError = true)]
        public static extern bool InternetGetCookieEx(string url, string cookieName, StringBuilder cookieData, ref int size, Int32 dwFlags, IntPtr lpReserved);

        private Uri Uri = new Uri("http://www.my-cloudflare-protected-website.com");
        private const Int32 InternetCookieHttponly = 0x2000;
        private const Int32 ERROR_INSUFFICIENT_BUFFER = 0x7A;

        public Form1()
        {
            InitializeComponent();

            webBrowser1.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.webBrowser1_DocumentCompleted);

            webBrowser1.Navigate(Uri, null, null, "User-Agent: kappaxdkappa\r\n"); //user-agent needs to be set another way if that doesnt work
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            int waitTime = 0;

            if(webBrowser1.DocumentTitle.Contains("We are under attack")) //check what string identifies the unique cloudflare captcha page and put it here
            {
                waitTime = 6000;
            }

            Task.Run(async () =>
            {
                await Task.Delay(waitTime); //cookie can be saved right away, but the waiting period might not have passed yet

                String cloudflareCookie = GetCookie(Uri, "cf_clearance");

                if (!String.IsNullOrEmpty(cloudflareCookie))
                {
                    System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\CFcookie.blob"); //save to %appdata%\MyProgram\Cookies\clearence.blob
                    file.Write(cloudflareCookie);
                    file.Close();
                }
            });
        }

        String GetCookie(Uri uri, String cookieName)
        {
            int datasize = 0;
            StringBuilder cookieData = new StringBuilder(datasize);

            InternetGetCookieEx(uri.ToString(), cookieName, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero);

            if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER && datasize > 0)
            {
                cookieData = new StringBuilder(datasize);
                if (InternetGetCookieEx(uri.ToString(), cookieName, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
                {
                    if (cookieData.Length > 0)
                    {
                        CookieContainer container = new CookieContainer();
                        container.SetCookies(uri, cookieData.ToString());

                        return container.GetCookieHeader(uri);
                    }
                }
            }

            return String.Empty;
        }
    }
}

一些注意事项:

  • 使用更好的用户代理
  • Cookie也会保存到磁盘上,因为我需要它 其他。不确定内置浏览器是否保存了下一个cookie 时间,但如果没有,这样你就可以再次加载它。
  • 改变"我们正受到攻击"短语到标识的那个 您试图绕过的CF验证码页面。
  • __ cfduid cookie不需要afaik

编辑:对不起,我在阅读其他答案后非常关注Cloudflare,我没有注意到你需要绕过有时在Cloudflare页面上找到的Recaptcha。我的代码可以为浏览器和cookie部分提供一些帮助,但至少现在你将很难解决Recaptcha问题。几个星期前,他们更加努力。我建议您编译自己的Firefox版本,然后点击复选框自动解决验证码。如果您没有获得那么简单的验证码,那么您需要为用户显示它。请注意,您还需要随机化浏览器的行为以及如何单击复选框,否则它会将您检测为机器人。