如何在使用 RemoteWebDriver 打开网页的同时获取 Http 状态码
最近一直在用Selenium这个开源项目写一些web 自动化的小玩意。本来一直运行的挺好,直到有一天突然发现资源抓取失败了,翻看日志才发现,原来本该正常打开的页面返回了504错误所以自然失败了。如何避免这种情况呢?事实上对于Selenium提供的RemoteWebDriver 来说,一般都是采用下面两种方式来打开网页:
using (var _driver = new PhantomJSDriver())
{
_driver.Navigate().GoToUrl("http://www.cnblogs.com/");
//或
_driver.Url = "http://www.cnblogs.com/";
}
然而这两种方式都没有提供相应的API或返回值来判断网页是否打开, 所以通常还需要加上一个判断看看是否出现了指定的页面元素才能最终确定页面是否打开:
try
{
_driver.FindElementById("main-content");
Console.WriteLine("Page opened.");
}
catch (NoSuchElementException)
{
Console.WriteLine("Page opened failed.");
}
如果需要对所有Open的页面进行判断的话,整个代码结构就会显得很乱,所以我只是简单的使用了URL进行判断,只要_driver返回的URL和我要前往的URL一致的话,就认为页面打开成功了。但实际上,很多情况下,http出现错误的时候页面并不会redirect
因此URL也不会发生改变。既然不能通过URL进行判断,那么久通过http状态码来判断吧?简单又方便。
然而,等我翻遍RemoteWebDriver的文档才发现,RemoteWebDriver本身并不提供获取Http状态码的API,并没有。。。。。没有。。。。
这简直就是。。。。。。。。。悲剧呀~~~~~~~~~~~~~~
不过好在大路走不通,咱还可以走小路,经过一番耐心细致的google,还是被我找到了一条曲线救国的方法,就是下面这条:
注:本方法只适用于 PhantomJSDriver, 其他的driver, 如:ChromeDriver, FireFoxDriver并不能用(当然也许也可以,但是我确实没有试成功)
PhantomJSDriver本身是对 PhantomJS的封装,而PhantomJS是一个基于 WebKit 的服务器端 JavaScript API。它全面支持web而不需浏览器支持,没有UI界面,使用起来也比其他带UI的WebDriver快速。在它的官网上可以看到PhantomJS提供的一系列API, 而我们要使用的就是其中一个:onResourceReceived, 这个API的详细介绍可以戳这里, 可以看到在这个回调中,返回的参数是一个response结构体,而其中的response.status 就是我们需要的状态码啦。
var webPage = require('webpage');
var page = webPage.create(); page.onResourceReceived = function(response) {
console.log('Response (#' + response.status + ', stage "' + response.stage + '"): ' + JSON.stringify(response));
};
好了,思路已经有了,下来就是怎么实现。要在PhantomJSDriver里使用上面这段JavaScript就需要用到ExecutePhantomJS()这个方法啦,这也是为什么我说这个方法只适用于PhantomJSDriver, 因为这个方法是PhantomJSDriver单独提供的。。。。
怎么用呢,请看下面这段代码, 我们用博客园的首页来试试,看看都加载了那些资源吧。
using (var _driver = new PhantomJSDriver())
{ const string phantomScript =
"var page = this; page.onResourceReceived = function(response) {console.log('***** ' + response.id + ' ***** ' + response.url + ' ***** ' + response.stage + ' ***** ' + response.status + ' ***** ' + response.statusText + ' *****');};";
_driver.ExecutePhantomJS(phantomScript);
_driver.Navigate().GoToUrl("http://www.cnblogs.com/");
}
我们把每一个获取到的response都打印出来看看,还真不少。注意看,有一些response出现了两遍, 对应的response.stage分别是start和end,这是指什么呢?官网上也给出了解释:stage : "start", "end" (FIXME: other value for intermediate chunk?)
当然对于我们来说,不需要这么多,只需要知道http://www.cnblogs.com/这个URL本身的状态,因此我们简化一下上面的代码, 过滤到状态不是end和URL不是http://www.cnblogs.com/的内容。
using (var _driver = new PhantomJSDriver())
{
const string phantomScript =
"var url = 'http://www.cnblogs.com/';" +
"var page = this; page.onResourceReceived = function(response) {if (response.stage !== \"end\" || response.url != url) return; console.log('##### ' + response.id + ' ##### ' + response.url + ' ##### ' + response.stage + ' ##### ' + response.status + ' ##### ' + response.statusText + ' #####'); };";
_driver.ExecutePhantomJS(phantomScript);
_driver.Navigate().GoToUrl("http://www.cnblogs.com/"); }
这下看上去就简洁多了吧。
走到这里,我们已经完成了需求的一大半,成功的获取到了Http的状态码,但是只是打印到console里面可不行,怎么能在代码中取到这个值呢?重定向console输出然后解析文本?No,No,No,我们还需要更优雅的方法。
实际上,对于ExecutePhantomJS()这个方法本身来说是可以有返回值的,例如下面的代码执行之后script的值是2。
string phantomScript = "return 1+1;";
var script = _driver.ExecutePhantomJS(phantomScript);
_driver.Navigate().GoToUrl("http://www.lepan.cc/down2-932746.html");
因此我最开始的想法很简单,直接把response返回出来不就好了?就像下面这段代码:
using (var _driver = new PhantomJSDriver())
{
const string phantomScript =
"var url = 'http://www.cnblogs.com/';" +
"var page = this; page.onResourceReceived = function(response) {if (response.stage !== \"end\" || response.url != url) return; return response; };";
var result= _driver.ExecutePhantomJS(phantomScript);
_driver.Navigate().GoToUrl("http://www.cnblogs.com/");
}
然而运行之后才发现,result的值始终是null,为啥?原来我们忘记了onResourceReceived 是个回调函数,代码运行到page.onResourceReceived = function(response) {if (response.stage !== \"end\" || response.url != url) return; return response; };的时候就直接返回了。所以,此路不通,为之奈何?看来又只能曲线救国了。看看下面这段代码:
using (var _driver = new PhantomJSDriver())
{
const string phantomScript =
"var url = 'http://www.cnblogs.com/';" +
"var page = this; page.onResourceReceived = function(response) {if (response.stage !== \"end\" || response.url != url) return; page.tag = response;};"; _driver.ExecutePhantomJS(phantomScript);
_driver.Navigate().GoToUrl("http://www.cnblogs.com/");
var result = (Dictionary<string, object>) _driver.ExecutePhantomJS("var page = this; return page.tag;");
Console.WriteLine(result["status"]); }
JavaScript是动态语言,我们就可以利用这一点,给page动态的创建一个tag属性,然后把response赋值过去,在页面加载完成后把tag取回来,这样就可以获取到Http的状态码啦。接下来只需要判断result["status"]的值是不是等于200, 就知道页面是否正确打开了。
最后,除了onResourceReceived之外, PhantomJS还提供了很多其他很有用处的API,下一回我们聊聊利用onResourceRequested这个API来进行简单的资源过滤来实现一个基本的AD Block功能。谢谢大家。
如何在使用 RemoteWebDriver 打开网页的同时获取 Http 状态码的更多相关文章
- C#带参数打开网页及url获取
1.带参数打开网页 Response.Redirect("form2.aspx?id=url1&name=ok"); 其中?后面为参数. 2.获取url 命令 结果 Req ...
- 网页中常见返回HTTP状态码含义
在日常网页浏览的过程中大家经常会碰到400,403,404,500,502等HTTP状态码,这些状态码对于一般用户来说出现什么都是一样的,反正就是页面打不开了,但是作为网站开发人员或者从事相关工作者认 ...
- Android -- 真正的 高仿微信 打开网页的进度条效果
(本博客为原创,http://www.cnblogs.com/linguanh/) 目录: 一,为什么说是真正的高仿? 二,为什么要搞缓慢效果? 三,我的实现思路 四,代码,内含注释 五,使用方法与截 ...
- 在WPF程序中打开网页:使用代理服务器并可进行JS交互
本项目环境:使用VS2010(C#)编写的WPF程序,通过CefSharp在程序的窗体中打开网页.需要能够实现网页后台JS代码中调用的方法,从网页接收数据,并能返回数据给网页.运行程序的电脑不允许上网 ...
- 使用urllib2打开网页的三种方法
#coding:utf-8 import urllib2 import cookielib url="http://www.baidu.com" print '方法 1' resp ...
- Apache 打开网页的时候等待时间过长的解决方案
服务器搭建后经常在打开页面的时候,等待很长时间,有时候,都超过一分钟了,然后才能打开,但是打开后,速度又很快,休息一会再点击,又会很慢了,遇到了这种问题很头疼,由于不是专业做服务器配置的,所以刚开始没 ...
- (转)C#调用默认浏览器打开网页的几种方法
转载,原文地址:http://blog.csdn.net/testcs_dn/article/details/42246969 CSharp调用默认浏览器打开网页的几种方法 示例界面: 方法一:从注册 ...
- 用webBrowser打开网页出现脚本错误怎么办
当IE浏览器遇到脚本错误时,在浏览器左下角会出现一个黄色图标,点击可以查看脚本错误的详细信息,并不会有弹出的错误信息框.我们在用webBrowser编写的程序打开网页,遇到脚本有问题是,会弹出一个错误 ...
- js实现打开网页自动弹出添加QQ好友邀请窗口
我们有时进一些网面或专题页面会自动弹出一个加为好友的对话框了,在研究了很久之后发现可以直接使用js来实现,下面我们一起来看js实现打开网页自动弹出添加QQ好友邀请窗口的方法. 第一步.JS脚本 这个是 ...
随机推荐
- 获取网页URL地址及参数等的两种方法(js和C#)
转:获取网页URL地址及参数等的两种方法(js和C#) 一 js 先看一个示例 用javascript获取url网址信息 <script type="text/javascript&q ...
- CSS图片垂直居中方法
让div里面的多行文本垂直居中的方法: div{height:100px;width:100px;border:solid 1px red;text-align:center; display:tab ...
- Android:单元测试Junit的配置
在实际开发中,开发android软件的过程需要不断地进行测试.而使用Junit测试框架,侧是正规Android开发的必用技术,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性.... ...
- Objective C SEl 和@selector是怎么工作的||How do SEL and @selector work in iphone sdk?
SEL is a type that represents a selector in Objective-C. The @selector() keyword returns a SEL that ...
- PLSQL_性能优化系列13_Oracle Index Rebuild索引重建
2014-10-04 Created By BaoXinjian
- kuangbin RMQ
这是kuangbin的RMQ,一维的,代码很简洁,附上: //kuangbin templet(查询最大值) 一维 //若想查最小,看提示更改 + ; ];//第二维是范围,即2^20约等于100万 ...
- codeforces 439 E. Devu and Birthday Celebration 组合数学 容斥定理
题意: q个询问,每一个询问给出2个数sum,n 1 <= q <= 10^5, 1 <= n <= sum <= 10^5 对于每一个询问,求满足下列条件的数组的方案数 ...
- image和字节流之间的相互转换
//将图片转化为长二进制 public Byte[] SetImgToByte(string imgPath) { FileStream file = new FileStream(imgPath, ...
- JAVA 主函数(主方法)
主函数(主方法) 1.public (访问修饰符,公共的)代表该类或者该方法访问权限是最大的 2.static 代表主函数随着类的加载而加载 3.void 代表主函数没有具体的返回 ...
- 深入ThreadLocal之三(ThreadLocal可能引起的内存泄露)
threadlocal里面使用了一个存在弱引用的map,当释放掉threadlocal的强引用以后,map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露. 最好 ...