如何在使用 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脚本 这个是 ...
随机推荐
- LintCode "Sliding Window Median" & "Data Stream Median"
Besides heap, multiset<int> can also be used: class Solution { void removeOnly1(multiset<in ...
- 利用Boost影响Lucene查询结果的排序
转自:http://catastiger.iteye.com/blog/803796 前提:不对结果做sort操作. 在搜索中,并不是所有的Document和Fields都是平等的.有些技术会要 ...
- (转)C# wnform 请求http ( get , post 两种方式 )
本文转载自:http://www.cnblogs.com/hailexuexi/archive/2011/03/04/1970926.html 1.Get请求 string strURL = &quo ...
- (VS TFS) Adding existing project to solution in TFS.
正常的情况话,直接加入project,然后选择"Source control" -> “Add selected projects to source control.... ...
- SpringAOP所支持的AspectJ切点指示器
在spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgumentException异常. 当我们查看上面展示的这些spring支持的指示器时,注意只有execution指示器 ...
- poj 1251 统计难题(字典树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1251 AC代码: #include<iostream> #include<algor ...
- Eclipse控制台输出信息的控制
当你在Eclipse中 running/debugging一个应用程序的时候,有关该应用程序的运行调试信息及日志信息都会输出到控制台(console )显示,但是Eclipse只会显示最后一部分的日志 ...
- Centos下yum配置lnmp环境
首先关闭SELINUX vi /etc/selinux/config #SELINUX=enforcing #注释掉 #SELINUXTYPE=tar ...
- memcached客户端的使用
一. 概念 Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能. 二. 适用场合 1. 分布式应用 ...
- ios6和ios7禁止屏幕旋转
ios6和ios7禁止屏幕旋转 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOr ...