由来
本文主要介绍以下动态网页爬取方法中的一种,在web2.0时代,很多都使用异步加载技术。导致有用信息获取不到,那怎么办了?不要慌,肯定是有办法的。 别废话了。QtWebKit是安装了Qt后内置封装好的浏览器内核。需要详细了解的可以到Qt官网查看,有了浏览器内核后,就可以通过它实现分析ajax的连接,或者js事件。可能会有人会说,不是可以使用现在google出的HeadlessChrome。或者selenium操作浏览器或phantom.js。我觉得你还是太年轻,比如下面这种情况,你怎么解决? (逃~,如果你有什么好的方法一定记得告诉我)
$(document).ready(function(){
// 真假浏览器检查
var detect = false;// 默认大家都是好学生,没有被老师发现上课时间在完爬虫……
if (navigator.webdriver || window.webdriver) {
detect = true;// 你竟然是用webdriver驱动的!Headless Chrome 同学,你被老师发现啦……
}
if (window.outerWidth === 0 || window.outerHeight === 0){ // 窗口的外部宽度和高度为零的同学,你很值得怀疑哦……
try {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
var exts = ctx.getSupportedExtensions();
}
catch (e) {
detect = true; // 你竟然不支持WebGL!PhantomJS 同学,你被老师发现啦……
}
}
// 好啦,Headless Chrome 和 PhantomJS 两位同学已经被老师罚站去了。其他同学要好好听课哦!
if (detect) {
var a = '4c59b57a97001c48';var b = 'b1522652fa3c5d1e';var c = 'e32b6f4cad197580';
} else {
var a = 'b1522652fa3c5d1e';var b = 'e32b6f4cad197580';var c = '4c59b57a97001c48';
}
// 使用一次性密码进行AES加密解密。
// a同学的作业是一串密钥,b同学的作业是一串初始向量,c同学的作业是了一串验证码。
var x = CryptoJS.enc.Latin1.parse(a);
var y = CryptoJS.enc.Latin1.parse(b);
// abc三位同学一起去老师那里提交作业。
$.post("data.php",{a:a,b:b,c:c},function(data){
// 老师检查了他们的作业,如果大家都写对了,就奖励他们一个包装好的奖品。
var dec = CryptoJS.AES.decrypt(data,x,{iv:y,padding:CryptoJS.pad.Pkcs7,mode:CryptoJS.mode.CBC});
// 拿到奖品后,用a同学的密钥和b同学的初始向量就可以打开包装啦。原来奖品就是正常可用的账号啊!
var tbdt = $.parseJSON(dec.toString(CryptoJS.enc.Utf8));
.......
还来看看知乎大神们是怎么解决的,selenium爬虫被检测到 该如何破?
是不是发现没有几个答到重点,其实如果不需要效率,我可以针对上面这个问题提供几个方案:
- 使用
qtwebkit
- 油猴脚本
Electron 的爬虫框架 Nightmare
- c#
webbrowser
- 修改被检测特征或设置chrome
就例举上面这几种吧,其实还有很多种方案,就不一一列举了。
web2.0时代,很多都使用异步加载技术。导致有用信息获取不到,那怎么办了?不要慌,肯定是有办法的。 别废话了。QtWebKit是安装了Qt后内置封装好的浏览器内核。需要详细了解的可以到Qt官网查看,有了浏览器内核后,就可以通过它实现分析ajax的连接,或者js事件。可能会有人会说,不是可以使用现在google出的HeadlessChrome。或者selenium操作浏览器或phantom.js。我觉得你还是太年轻,比如下面这种情况,你怎么解决? (逃~,如果你有什么好的方法一定记得告诉我)$(document).ready(function(){
// 真假浏览器检查
var detect = false;// 默认大家都是好学生,没有被老师发现上课时间在完爬虫……
if (navigator.webdriver || window.webdriver) {
detect = true;// 你竟然是用webdriver驱动的!Headless Chrome 同学,你被老师发现啦……
}
if (window.outerWidth === 0 || window.outerHeight === 0){ // 窗口的外部宽度和高度为零的同学,你很值得怀疑哦……
try {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
var exts = ctx.getSupportedExtensions();
}
catch (e) {
detect = true; // 你竟然不支持WebGL!PhantomJS 同学,你被老师发现啦……
}
}
// 好啦,Headless Chrome 和 PhantomJS 两位同学已经被老师罚站去了。其他同学要好好听课哦!
if (detect) {
var a = '4c59b57a97001c48';var b = 'b1522652fa3c5d1e';var c = 'e32b6f4cad197580';
} else {
var a = 'b1522652fa3c5d1e';var b = 'e32b6f4cad197580';var c = '4c59b57a97001c48';
}
// 使用一次性密码进行AES加密解密。
// a同学的作业是一串密钥,b同学的作业是一串初始向量,c同学的作业是了一串验证码。
var x = CryptoJS.enc.Latin1.parse(a);
var y = CryptoJS.enc.Latin1.parse(b);
// abc三位同学一起去老师那里提交作业。
$.post("data.php",{a:a,b:b,c:c},function(data){
// 老师检查了他们的作业,如果大家都写对了,就奖励他们一个包装好的奖品。
var dec = CryptoJS.AES.decrypt(data,x,{iv:y,padding:CryptoJS.pad.Pkcs7,mode:CryptoJS.mode.CBC});
// 拿到奖品后,用a同学的密钥和b同学的初始向量就可以打开包装啦。原来奖品就是正常可用的账号啊!
var tbdt = $.parseJSON(dec.toString(CryptoJS.enc.Utf8));
.......qtwebkitElectron 的爬虫框架 Nightmarewebbrowser实现
看了上面的介绍,差不多就是要我们实现一个简单版的浏览器才可以解决。qtwebkit可以胜任,但是这里需要注意:qtwebkit对HTML5支持不好。后续我会使用Qt新出的qtwebengine组件。因为qtwebengine组件的资料比较少,差不多只有看官方文档,最主要还是c++的。所以我就来说说QtWebkit。
qtwebkit可以胜任,但是这里需要注意:qtwebkit对HTML5支持不好。后续我会使用Qt新出的qtwebengine组件。因为qtwebengine组件的资料比较少,差不多只有看官方文档,最主要还是c++的。所以我就来说说QtWebkit。QtWebkit开发爬虫准备
使用QtWebkit开发爬虫。主要使用里面的两个类:
QWebView 主要是一个浏览器的容器,操作浏览器的各种交互等
QNetworkAccessManager
是一个网络请求管理类,将我们的浏览器和其绑定后,我们的所有浏览器执行的请求都会被这里类管理,譬如我们需要改造请求头或者获取相应头等操作都需要用到这个类,代理设置和cookie之类。
QtWebkit开发爬虫。主要使用里面的两个类:QWebView 主要是一个浏览器的容器,操作浏览器的各种交互等QNetworkAccessManager
是一个网络请求管理类,将我们的浏览器和其绑定后,我们的所有浏览器执行的请求都会被这里类管理,譬如我们需要改造请求头或者获取相应头等操作都需要用到这个类,代理设置和cookie之类。
Qwebview 类
上面描述的这个类是关于浏览器的交互,其实主要是关于QtWebkit进行js解析。有一个问题需要注意:这个类没有自带网页访问超时函数,还有如果有重定向跳转,那么不会获取第一次得到重定向的网页,就需要使用qtimer进行延时。这是因为访问网页返回状态码为 200 的链接就会触发一个函数-->_finished函数代表完成。那么问题就来了。我们一般只要获取返回码为200代表成功。但是重定向时,我们需要得到重定向的网页,那我们就不知道重定向后的网页后又要调用一次**_finished**函数。处理的时候需要注意
def download(self, url, timeout=60):
'''等待下载完成并返回'''
body = ""
loop = QEventLoop()
timer = QTimer()
timer.setSingleShot(True)
timer.timeout.connect(loop.quit)
self.load(QNetworkRequest(QUrl(url)),
QNetworkAccessManager.GetOperation, body)
timer.start(timeout * 1000)
# 等待加载完成
loop.exec_()
if timer.isActive():
# 下载成功
timer.stop()
# return self.page().mainFrame().toHtml()
return self.page().mainFrame().toPlainText()
else:
print ("Request time out:"+ str(url.url().toString()))
以下是对webview的属性设置
def setSettings(self):
# 以下是对webview的属性设置,
# 第一个是设置访问远程url,当使用ajax请求的时候,这个就派上用上
self.page().settings().setAttribute(
QWebSettings.LocalContentCanAccessRemoteUrls, True)
# 下面两句是利用html5的本地存储功能来帮助我们存储程序运行中要保存的数据
self.page().settings().setAttribute(
QWebSettings.LocalStorageDatabaseEnabled, True) # 开始本地存储
self.page().settings().setLocalStoragePath("html/") # 存储的路径
# 是否加载js
self.page().settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
# 自动禁用图像下载
self.page().settings().setAttribute(QWebSettings.AutoLoadImages, False)
# 如何存储cookie呢,并且利用cookiejar
self.page().networkAccessManager().setCookieJar(QNetworkCookieJar(self))
# for cookie in app.mcookiejar.allCookies():
# print cookie.name()
# name是setCooke(name, val)中的name,在请求时候,可以将cookie放在header中发出请求
# mOBJ = AdamOBJ()
##python调用js
# self.page().mainFrame().evaluateJavaScript(QString('alert("hello
# wolrd")'))
# js调用python
# self.page().mainFrame().javaScriptWindowObjectCleared.connect(lambda: self.page(
# ).mainFrame().addToJavaScriptWindowObject(QString('mOBJ'), mOBJ))
# 加入js代码
self.page().mainFrame().evaluateJavaScript(open('jquery.js').read())
self.page().mainFrame().evaluateJavaScript(jsstr)
# 设置默认编码
self.settings().setDefaultTextEncoding("utf-8")
有需要在发起请求时执行某些操作,或者在执行完了执行某些操作。那么需要加入下面函数。
# load成功时候执行。self._loadStarted 是开始的回调函数
self.loadStarted.connect(self._loadStarted)
# 成功渲染时候执行。self._loadFinished 是开始的回调函数
self.loadFinished.connect(self._loadFinished)
我们一般在load成功后,需要上面操作了?一般都是让程序阻塞js代码去掉
def _loadStarted(self):
'''load完成'''
frame = self.page().mainFrame()
frame.evaluateJavaScript("window.alert=function(){}")
frame.evaluateJavaScript("window.confirm=function(){returntrue}")
frame.evaluateJavaScript("window.prompt =function(){return 0}")
frame.evaluateJavaScript("window.open =function(){}")
渲染后_loadFinshed函数处理的事件就比较多了,爬虫一般就在这时候抽取数据。绝大多数网页都会使用javascript处理页面,还有可能使用Ajax技术异步加载。触发事件后才发起或者生成的链接和数据。一般有下面几种:
-
js动态解析
这个在self._loadStarted函数执行完后,webkit内核执行javascript代码生成出html代码。也静态方式获取动态生成的链接及数据
-
自动交互
模仿人的行为来加载数据,比如我们点击鼠标或者鼠标往下拉动加载数据。
-
自动分析表单
自动识别出action中的值为所提交的地址,提取input标签中的name和value作为参数,生成带有参数的链接。
-
hook网络请求
这是一个ajax请求,有别于以上3种基于dom树解析的分析技术,要捉到其请求的url只能通过hook请求,hook住每一个由webkit发送出去的请求,从而拿到了 请求链接
# 给<a>标签设置onclick事件
'''
selectdom=document.querySelectorAll("a");
for(var i= 0; i< selectdom.length; i ++){
if(!selectdom[i].getAttribute("onclick")){
selectdom[i].setAttribute("onclick",selectdom[i].getAttribute("href"))
}
}
'''
# onchange 事件在用户改变输入域的内容时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onchange]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onchange();
}catch(err){
continue;
}
}
'''
# onclick 事件在用户点击时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onclick]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onclick();
}catch(err){
continue;
}
}
'''
# onfocus 事件在对象获得焦点时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onfocus]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onfocus();
}catch(err){
continue;
}
}
'''
# onmouseout 事件在用户鼠标指针移出指定的对象时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onmouseout]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onmouseout();
}catch(err){
continue;
}
}
'''
# onmouseover 事件在用户鼠标指针移动到指定的对象时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onmouseover]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onmouseover();
}catch(err){
continue;
}
}
'''
# 还有其他事件,以后在添加。。。。。。
def _loadFinished(self):
'''渲染完成'''
self.loop.quit()
frame = self.page().mainFrame()
# 事件先按一遍 然后到parse处理
frame.evaluateJavaScript('selectdom=document.querySelectorAll("a");for(var i= 0; i< selectdom.length; i ++){if(!selectdom[i].getAttribute("onclick")){selectdom[i].setAttribute("onclick",selectdom[i].getAttribute("href"))}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onerror]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onerror();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onchange]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onchange();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onclick]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onclick();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onfocus]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onfocus();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onmouseout]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onmouseout();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onmouseover]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onmouseover();}catch(err){continue;}}')
200 的链接就会触发一个函数-->_finished函数代表完成。那么问题就来了。我们一般只要获取返回码为200代表成功。但是重定向时,我们需要得到重定向的网页,那我们就不知道重定向后的网页后又要调用一次**_finished**函数。处理的时候需要注意def download(self, url, timeout=60):
'''等待下载完成并返回'''
body = ""
loop = QEventLoop()
timer = QTimer()
timer.setSingleShot(True)
timer.timeout.connect(loop.quit)
self.load(QNetworkRequest(QUrl(url)),
QNetworkAccessManager.GetOperation, body)
timer.start(timeout * 1000)
# 等待加载完成
loop.exec_()
if timer.isActive():
# 下载成功
timer.stop()
# return self.page().mainFrame().toHtml()
return self.page().mainFrame().toPlainText()
else:
print ("Request time out:"+ str(url.url().toString()))def setSettings(self):
# 以下是对webview的属性设置,
# 第一个是设置访问远程url,当使用ajax请求的时候,这个就派上用上
self.page().settings().setAttribute(
QWebSettings.LocalContentCanAccessRemoteUrls, True)
# 下面两句是利用html5的本地存储功能来帮助我们存储程序运行中要保存的数据
self.page().settings().setAttribute(
QWebSettings.LocalStorageDatabaseEnabled, True) # 开始本地存储
self.page().settings().setLocalStoragePath("html/") # 存储的路径
# 是否加载js
self.page().settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
# 自动禁用图像下载
self.page().settings().setAttribute(QWebSettings.AutoLoadImages, False)
# 如何存储cookie呢,并且利用cookiejar
self.page().networkAccessManager().setCookieJar(QNetworkCookieJar(self))
# for cookie in app.mcookiejar.allCookies():
# print cookie.name()
# name是setCooke(name, val)中的name,在请求时候,可以将cookie放在header中发出请求
# mOBJ = AdamOBJ()
##python调用js
# self.page().mainFrame().evaluateJavaScript(QString('alert("hello
# wolrd")'))
# js调用python
# self.page().mainFrame().javaScriptWindowObjectCleared.connect(lambda: self.page(
# ).mainFrame().addToJavaScriptWindowObject(QString('mOBJ'), mOBJ))
# 加入js代码
self.page().mainFrame().evaluateJavaScript(open('jquery.js').read())
self.page().mainFrame().evaluateJavaScript(jsstr)
# 设置默认编码
self.settings().setDefaultTextEncoding("utf-8")# load成功时候执行。self._loadStarted 是开始的回调函数
self.loadStarted.connect(self._loadStarted)
# 成功渲染时候执行。self._loadFinished 是开始的回调函数
self.loadFinished.connect(self._loadFinished)def _loadStarted(self):
'''load完成'''
frame = self.page().mainFrame()
frame.evaluateJavaScript("window.alert=function(){}")
frame.evaluateJavaScript("window.confirm=function(){returntrue}")
frame.evaluateJavaScript("window.prompt =function(){return 0}")
frame.evaluateJavaScript("window.open =function(){}")javascript处理页面,还有可能使用Ajax技术异步加载。触发事件后才发起或者生成的链接和数据。一般有下面几种:js动态解析
这个在
self._loadStarted函数执行完后,webkit内核执行javascript代码生成出html代码。也静态方式获取动态生成的链接及数据
自动交互
模仿人的行为来加载数据,比如我们点击鼠标或者鼠标往下拉动加载数据。
自动分析表单
自动识别出action中的值为所提交的地址,提取input标签中的name和value作为参数,生成带有参数的链接。
hook网络请求
这是一个ajax请求,有别于以上3种基于dom树解析的分析技术,要捉到其请求的url只能通过hook请求,hook住每一个由webkit发送出去的请求,从而拿到了 请求链接
# 给<a>标签设置onclick事件
'''
selectdom=document.querySelectorAll("a");
for(var i= 0; i< selectdom.length; i ++){
if(!selectdom[i].getAttribute("onclick")){
selectdom[i].setAttribute("onclick",selectdom[i].getAttribute("href"))
}
}
'''
# onchange 事件在用户改变输入域的内容时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onchange]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onchange();
}catch(err){
continue;
}
}
'''
# onclick 事件在用户点击时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onclick]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onclick();
}catch(err){
continue;
}
}
'''
# onfocus 事件在对象获得焦点时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onfocus]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onfocus();
}catch(err){
continue;
}
}
'''
# onmouseout 事件在用户鼠标指针移出指定的对象时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onmouseout]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onmouseout();
}catch(err){
continue;
}
}
'''
# onmouseover 事件在用户鼠标指针移动到指定的对象时执行 JavaScript 代码
'''
selectdom=document.querySelectorAll("[onmouseover]");
for(var i= 0; i< selectdom.length; i ++){
try{
selectdom[i].onmouseover();
}catch(err){
continue;
}
}
'''
# 还有其他事件,以后在添加。。。。。。
def _loadFinished(self):
'''渲染完成'''
self.loop.quit()
frame = self.page().mainFrame()
# 事件先按一遍 然后到parse处理
frame.evaluateJavaScript('selectdom=document.querySelectorAll("a");for(var i= 0; i< selectdom.length; i ++){if(!selectdom[i].getAttribute("onclick")){selectdom[i].setAttribute("onclick",selectdom[i].getAttribute("href"))}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onerror]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onerror();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onchange]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onchange();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onclick]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onclick();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onfocus]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onfocus();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onmouseout]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onmouseout();}catch(err){continue;}}')
frame.evaluateJavaScript('selectdom=document.querySelectorAll("[onmouseover]");for(var i= 0; i< selectdom.length; i ++){try{selectdom[i].onmouseover();}catch(err){continue;}}')QNetworkAccessManager 类
这个类是关于网络方面的,需要使用这个类时候,我们需要把他和webkit内核绑定到一起。这样才能对网络进行监控拦截和修改,一般使用setNetworkAccessManager(manager)函数进行设置绑定,QNetworkAccessManager 类可以满足爬虫中的获取header、proxy等设置。进行网络拦截控制主要重写QNetworkAccessManager类中的createRequest函数,顾名思义就知道这函数是用来创建网络请求,_finished函数后获取状态。
def setProxy(self):
# 可以使用https 代理
QSslSocket.supportsSsl()
proxy = QNetworkProxy()
# Http访问代理
proxy.setType(QNetworkProxy.HttpProxy)
# proxy.setType(QtNetwork.QNetworkProxy.DefaultProxy)
# proxy.setType(QNetworkProxy.Socks5Proxy)
proxy.setHostName('localhost')
proxy.setPort(1337)
proxy.setUser("wushuang5112")
proxy.setPassword("123456")
QNetworkProxy.setApplicationProxy(proxy)
def requests(self, url, headers):
req = QNetworkRequest(QUrl(url))
req.setRawHeader(
"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0")
# for header in headers:
# val = headers[header]
# req.setRawHeader(header, val)
# req.setUrl(QUrl("http://qt.nokia.com"))
# req.setRawHeader("User-Agent", "MyOwnBrowser 1.0")
return req
可以用来进行检测URL 重定向等。
url = str(reply.url().toString())
# 获得返回状态
status =reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
status, ok = status.toInt()
在爬虫中我们是不是有什么还没有说,那就是Cookie的设置和获取,那怎么实现了
设置Cookie
def setCookie(self, my_cookie_dict):
# 将字典转化成QNetworkCookieJar的格式
self.cookie_jar = QNetworkCookieJar()
cookies = []
for key, values in my_cookie_dict.items():
my_cookie = QNetworkCookie(QByteArray(key), QByteArray(values))
my_cookie.setDomain('.baidu.com')
cookies.append(my_cookie)
self.cookie_jar.setAllCookies(cookies)
# 如果没有在前面设置domain,那么可以在这里指定一个url作为domain
# self.cookie_jar.setCookiesFromUrl(cookies,
# QUrl('https://www.baidu.com/'))
# 最后cookiejar替换完成
self.page().networkAccessManager().setCookieJar(self.cookie_jar)
获取Cookie
# 在QWebView中使用下面代码
cookies = []
for citem in self.page().networkAccessManager().cookieJar().cookiesForUrl(QUrl('http://www.baidu.com')):
cookies.append('%s=%s' % (citem.name(), citem.value()))
cookies = common.to_unicode('; '.join(cookies))
print (cookies)
# 删除cookie
def deleteCookie(self,cookieList):
cookie = []
self.mainWindow.settings.value(cookie)
setNetworkAccessManager(manager)函数进行设置绑定,QNetworkAccessManager 类可以满足爬虫中的获取header、proxy等设置。进行网络拦截控制主要重写QNetworkAccessManager类中的createRequest函数,顾名思义就知道这函数是用来创建网络请求,_finished函数后获取状态。def setProxy(self):
# 可以使用https 代理
QSslSocket.supportsSsl()
proxy = QNetworkProxy()
# Http访问代理
proxy.setType(QNetworkProxy.HttpProxy)
# proxy.setType(QtNetwork.QNetworkProxy.DefaultProxy)
# proxy.setType(QNetworkProxy.Socks5Proxy)
proxy.setHostName('localhost')
proxy.setPort(1337)
proxy.setUser("wushuang5112")
proxy.setPassword("123456")
QNetworkProxy.setApplicationProxy(proxy)
def requests(self, url, headers):
req = QNetworkRequest(QUrl(url))
req.setRawHeader(
"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0")
# for header in headers:
# val = headers[header]
# req.setRawHeader(header, val)
# req.setUrl(QUrl("http://qt.nokia.com"))
# req.setRawHeader("User-Agent", "MyOwnBrowser 1.0")
return requrl = str(reply.url().toString())
# 获得返回状态
status =reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
status, ok = status.toInt()Cookie的设置和获取,那怎么实现了Cookiedef setCookie(self, my_cookie_dict):
# 将字典转化成QNetworkCookieJar的格式
self.cookie_jar = QNetworkCookieJar()
cookies = []
for key, values in my_cookie_dict.items():
my_cookie = QNetworkCookie(QByteArray(key), QByteArray(values))
my_cookie.setDomain('.baidu.com')
cookies.append(my_cookie)
self.cookie_jar.setAllCookies(cookies)
# 如果没有在前面设置domain,那么可以在这里指定一个url作为domain
# self.cookie_jar.setCookiesFromUrl(cookies,
# QUrl('https://www.baidu.com/'))
# 最后cookiejar替换完成
self.page().networkAccessManager().setCookieJar(self.cookie_jar)Cookie# 在QWebView中使用下面代码
cookies = []
for citem in self.page().networkAccessManager().cookieJar().cookiesForUrl(QUrl('http://www.baidu.com')):
cookies.append('%s=%s' % (citem.name(), citem.value()))
cookies = common.to_unicode('; '.join(cookies))
print (cookies)
# 删除cookie
def deleteCookie(self,cookieList):
cookie = []
self.mainWindow.settings.value(cookie)QtWebkit开发爬虫实现
上面提过,Webkit对现在的Html5支持不是很好。还有如果在使用服务器运行爬虫,那么需要一个视窗系统才可以正常使用。 那么怎么解决这些问题,对Html5的支持可以使用Qt高版本的qtwebengine组件。使用xvfb虚拟出一个视窗系统,只需把alert, confirm, prompt的代码注释掉(因为会让浏览器阻塞),简单快捷稳定。
其实还有很多方法解决Selenium + Webdriver能被识别的特征。后续继续介绍。
Webkit对现在的Html5支持不是很好。还有如果在使用服务器运行爬虫,那么需要一个视窗系统才可以正常使用。 那么怎么解决这些问题,对Html5的支持可以使用Qt高版本的qtwebengine组件。使用xvfb虚拟出一个视窗系统,只需把alert, confirm, prompt的代码注释掉(因为会让浏览器阻塞),简单快捷稳定。
评论
发表评论