神器CefSharp在爬虫方面的应用
神器CefSharp在爬虫方面的应用
一、前言概述
提起Web端的自动化,模拟渲染,相信虫子们都能想到一些比较流行的框架,例如Selenium,Puppeteer等。其中Selenium利用的是WebDriver,支持Python,Java,.Net等多种语言,而Puppeteer出自谷歌之手,基于nodejs。两者的底层都是通过DevTools Protocol来操控Chrome的。诚然,这两个框架在Web自动化领域的应用非常强大,其中Puppeteer更是可以对网络请求进行拦截,但是用在爬虫上,hhhhhh,先放张图撑撑场面:
你可能不服,别急,继续往下看就知道了。
自动化测试框架为开发者(这里只针对爬虫而言)带来了很多方便,例如处理ajax请求的动态加载,前端JS混淆加密,人机验证,请求拦截等,但是却有个致命的缺点,就是拥有很多和正常浏览器不同的特征,而这些特征一旦被侦测到,爬虫就无法再进行下去,而目前的大厂们,几乎都或多或少的会进行检测,例如瑞数加密的JS,淘宝Web端页面等,均有检测代码。下面给出几个检测及绕过检测点的例子:
简单来说,目前比较流行的两种方式绕过检测。1.对于部分能够直接修改的特征值,可以通过JS hook的方式进行修改。2.对于其他修改困难的特征值,可以通过操控请求,对目标网站响应的JS文件进行篡改,删除或者替换其用于检测的代码,以达到绕过的目的。
但是,上面两种方法的弊端也很明显,方法1所修改的特征值,可能在刷新页面后失效,而方法2,首先Selenium无法直接做到,需要外挂代理进行实现,而Puppeteer有原生支持。其次,随着反爬虫技术的不断提升,特征检测的位置可能会越来越多,用于检测的JS代码也可能经过了层层的混淆加密,可读性极差,从中找到检测逻辑可能是个极为繁琐的工作。
二、CefSharp介绍
开源项目地址
我们可以将CefSharp理解为一个浏览器核心,类似WebKit东西,然后可以嵌入程序中使用,跟微软的WebBrowser控件有点像,不同的是WebBrowser是IE内核的,像ifram等标签都无法支持,而CefSharp基于Chrome内核,可以做到完美兼容。
换句话说,上面提到的特征检测和反检测的斗争,我不陪你玩了,我们直接拿Chrome内核写个浏览器,随你怎么检测。
三、CefSharp爬虫方面的应用及配置
1、强制当前页打开链接
由于我们使用的是基于Chrome内核的真实浏览器,那么为了防止采集过程中,多个窗口弹出影响采集,需要强制CefSharp使用当前页来打开链接,默认是新窗口。
实现方法很简单,实现ILifeSpanHandler接口的OnBeforePopup方法即可代码如下:
public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
newBrowser = null;
var chromiumWebBrowser = (ChromiumWebBrowser)browserControl;
chromiumWebBrowser.Load(targetUrl);
return true;
}
2、UA,代理等配置
var settings = new CefSettings()
{
//设置UA
UserAgent = "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Mobile Safari/537.36",
};
settings.CefCommandLineArgs.Add("proxy-server", "127.0.0.1:8888");
//加载Flash
//settings.CefCommandLineArgs.Add("ppapi-flash-path", AppDomain.CurrentDomain.BaseDirectory + "\\Plugins\\pepflash\\pepflashplayer.dll");
Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);
3、Cookie操作
ICookieManager cookieManager = CefSharp.Cef.GetGlobalCookieManager();
//读取Cookie
var Cookies = cookieManager.VisitAllCookiesAsync().Result;
//设置Cookie
var domain = "blog.nb-ray.com";
var name = "CookieName";
var value = "CookieValue";
//设置Cookie
cookieManager.SetCookie($"http://{domain}", new CefSharp.Cookie
{
Domain = domain,
Name = name,
Value = value,
Expires = DateTime.MinValue
});
4、执行JS
browser.EvaluateScriptAsync("alert(navigator.webdriver)").Result.Result;
这边我们输出navigator.webdriver特征值看看:
因为使用的是货真价实的浏览器,navigator.webdriver字段的值意料之中是undefined
5、请求拦截
这一部分稍微麻烦点,需要重写RequestHandler,ResourceRequestHandler两个类,并实现IResponseFilter接口,为了方便使用,这部分我已经进行了封装,项目代码放在文章末尾,下面先给出拦截部分的几个应用
RequestHandler = new TrackRequestHandler(new TrackConfig
{
//这里请求进行一系列操作,传入Action或者Func类型的委托
}
5.1、请求阻断
例如 可以阻断所有请求地址以png结尾的请求,这里的请求会直接取消,而不会到达服务端
BlockingRequest = req =>
{
return req.Url.EndsWith(".png");
}
5.2、修改请求
在请求发出前进行修改,例如修改请求的地址,Head,body等,下面的示例代码把请求地址替换为百度
EditRequest = req =>
{
if (req.Url.Contains("http://blog.nb-ray.com/articles/2020/07/02/1593671843093.html"))
{
req.Url = "https://www.baidu.com/";
}
return req;
},
5.3、修改响应
修改来自服务端的响应,下面的代码将地址"http://blog.nb-ray.com/articles/2020/07/02/1593671843093.html"
响应的内容修改为字符串"xxynb"
ReplaceFunc = (row, bts) =>
{
//响应内容转字符串 可能是片段
var encode = Encoding.UTF8;
try
{
encode = Encoding.GetEncoding(row.charset);
}
catch (Exception)
{
}
var str = encode.GetString(bts);
if (row.url.Contains("http://blog.nb-ray.com/articles/2020/07/02/1593671843093.html"))
{
//同一请求分为多个片段传输的情况下 全文替换只生效一次
if (reptime == 0)
{
//例如 将响应内容替换为 "xxynb"
bts = Encoding.GetEncoding(row.charset).GetBytes("xxynb");
reptime++;
}
else
{
bts = Encoding.GetEncoding(row.charset).GetBytes(" ");
}
}
else
{
reptime = 0;
}
return bts;
}
5.3、请求收集
此处可以得到所有请求的详细数据,可以在这里进行爬虫数据清洗等操作,例如下文代码将响应内容进行输出:
RowFunc = row =>
{
if (row.url.Contains("articles"))
{
Console.WriteLine(row.responsedatastring);
}
}
四、项目地址
标题:神器CefSharp在爬虫方面的应用
作者:Cubeeeee
地址:http://blog.nps.fuguicun.com/articles/2020/07/06/1594006931150.html