我很好奇人们如何为没有公共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#写作是因为这是我最熟悉的语言,但只要他们回答这个问题,我就不介意使用任何其他语言。
答案 0 :(得分:1)
我想,一种方法是在客户端应用程序之外的Web浏览器中处理验证码。
private
private[this]
private[package]
(用户ID)和__cfduid
(解决验证码的证明)。现在困难的部分是(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;
}
}
}
一些注意事项:
编辑:对不起,我在阅读其他答案后非常关注Cloudflare,我没有注意到你需要绕过有时在Cloudflare页面上找到的Recaptcha。我的代码可以为浏览器和cookie部分提供一些帮助,但至少现在你将很难解决Recaptcha问题。几个星期前,他们更加努力。我建议您编译自己的Firefox版本,然后点击复选框自动解决验证码。如果您没有获得那么简单的验证码,那么您需要为用户显示它。请注意,您还需要随机化浏览器的行为以及如何单击复选框,否则它会将您检测为机器人。