一个困扰3天的狗血技术问题终于被解决了。记录下来龙去脉。
问题起因:
RobotFramework终于推出了selenium2的Library,垂涎于selenium2性能的大幅度提升和突破浏览器沙箱限制这两个大亮点,下午闲暇之余三下五除二就装上了selenium2Library。装完后,兴冲冲的写了一个简单的demo想运行一下,在RIDE上点击执行后,发现测试通过,但是IE浏览器却没有能够启动。三天的噩梦开始了。。。。。
过程描述:
day1:
1.怀疑写的脚本有问题,反复查看后发现脚本OK。
2.怀疑selenium2Library安装有问题,卸掉重装,问题依然存在。
3.仔细阅读安装说明,卸掉重装,问题依然存在。
4.运行slenium2Library自带的验收测试和单元测试脚本,发现有11个用例跑不通,查看用例发现就是IEDriver部分有问题。
5.google问题,没有答案,在robotframework社区发了技术请求贴。
6.尝试FirefoxDriver,能够打开FirefoxDriver实例,但是无法进行下一步操作,Chrome也无法打开。
7.切换关键词进行搜索,再切换关键词进行搜索,切换搜索引擎到bing,均没有答案,在社区更新了一些出错信息。
8.设置断点debug源码,发现python的webdriver调用的是一个叫做IEdriver.dll的动态链接库。使用工具见识IEdriver.dll,发现python正常调用IEdriver.dll,但是浏览器就是起不来。
9.google IEdriver.dll源码 无果(其实有技术文档,但是google关键词不对,当时没有找到)
10.认为是python问题,将现有python版本切换到2.7.1,问题依然存在。。。这时候已经晚上8点了。只能回家吃饭。
晚上吃点儿东西后继续尝试,把家中的python升级到2.7.2。Bingo!!!问题被解决了。当时确认为python版本问题。高高兴兴在社区做了回复。
Day2:
1.兴冲冲打开自己电脑,将python升级到2.7.2,公司电脑上问题依旧。
2.继续翻看社区回复,发现没有人回答。
3.认为IEDriver.dll版本有问题,从java版的jar包里解压出一个替换。问题依旧。
4.怀疑浏览器版本有问题,又不能换,把好几个同事的机子折腾了一个遍,尝试数个IE版本。同事的机子也是一个也不行。
5.使用C#调用webdriver,成功了,大兴奋,换出来C#的版本的IEdriver.dll在python下还是不行(这里让我认为不是代理服务器的问题)。
5.由于当天有很多更重要的工作,只能先停滞下来了。
6.晚上换了老婆的机子试验,竟然又成功了。匪夷所思。
Day3:
1.下午3点钟开始有些闲暇,继续深入思索:家里的机子和单位的机子有什么区别呢?C#和python调用有什么区别呢?。。。苦思冥想后得出:家里的机子与单位机子的一个区别是没有使用代理服务器。C#与python调用的区别得读源码。
2.尝试去掉代理,失败。
3.尝试调试C#代码,发现要下载一堆开源工程的源码,心里一万个不愿意。都有一点儿放弃了。
4.漫无目的的google。发现有人提我一样的问题,兴冲冲的点进去,TMD是我自己提的!临近崩溃。
5.最后回到社区,突然发现一个国际友人给了回复,她说,你试试把IE恢复默认值看看。
6.我照做,居然成功了!!!!!
7.在同事的机子上做。也都成功了!
刨根问底:
1.why? Why? Why?
折腾了3天我不想就这么放过去。仔细对比了一下浏览器还原后和以前的区别,最大的区别就是代理服务器
。为什么刚才我去掉代理还失败了呢?仔细回想,原来去掉代理后,没有使用在python中退出webdriver实例,那个dll还在加载中,因此无效!真是分析问题还要更加细致才行!
2.那为什么代理会影响IE被load呢?回家后在selenium的wiki上进行地毯式搜索,终于找到了下面这篇文章,阅读大致了解了问题所在:
InternetExplorerDriverInternals
原来,IEdriver.dll是一个客户端-服务器端的结构,服务器端代码使用COM技术操纵IE,并且会起一个mini的Server,客户端的代码通过一种叫做JsonWireProtocol 的协议和服务器端通讯,从而达到操控IE的目的。服务器端的代码写的太简单,根本没有考虑代理的处理,源码如下:
http://code.google.com/p/selenium/source/browse/trunk/jobbie/src/cpp/InternetExplorerDriver/InternetExplorerDriver.cpp?r=8461
3.为什么FireFox和Chorme在IE设置代理时也出现问题呢?
FireFox没有尝试去掉代理的情况;chrome的代理设置则依赖于系统设置,也就是IE设置。
4.为什么C#可以调用成功呢,仔细琢磨,C#下的IEDriver.dll是动态生成的,生成dll的代码肯定包含了对代理服务器的考虑(搞.net的肯定对IE机制熟透了)。
5.为什么网上那么少人有跟我一样的问题? 国内社区还不成熟,案例少,国外社区的家伙们貌似用windows +IE的是小众。。。。。。 看到n个回帖的哥们说,他们在linux+firefox上工作良好心理感觉还怪怪的。
最终解决方案:
1.去掉代理。
2.在社区给作者发信,请他加入对代理服务器的考虑。
总结:
1.要相信开源社区的力量,众人拾柴火焰高,今后也会努力的去帮助别人。
2.充分利用搜索引擎里的蛛丝马迹,但是要仔细思考,不要被淹没在信息中。
3.真正弄懂原理才能真正解决问题,总是照猫画虎到关键时刻会吃亏。
---------------------------------------------------------------------------------------------
补充:
@吴穹adam 提供了两篇文章:
Webdriver的高级用法:
给出了用程序显式设置proxy的方法:
from selenium import webdriver PROXY = "localhost:8080" webdriver.DesiredCapabilities.INTERNETEXPLORER['proxy'] = { "httpProxy":PROXY, "ftpProxy":PROXY, "sslProxy":PROXY, "noProxy":None, "proxyType":"MANUAL", "class":"org.openqa.selenium.Proxy", "autodetect":False } # you have to use remote, otherwise you'll have to code it yourself in python to # dynamically changing the system proxy preferences driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.INTERNETEXPLORER)
一个哥们类似问题的解决方法:
http://passerbyy.iteye.com/blog/1286292
自己只看了COM互操作的源码,原来在外层是可以设置Proxy的。得继续深入学习。