简介
Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,Edge等。这个工具的主要功能包括:
1、测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。
2、测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成 .Net、Java、Perl等不同语言的测试脚本。
3、利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码 ,做到可见即可爬。 所以Selenium现在被广泛用于Python爬虫
功能
-
框架底层使用JavaScript模拟真实用户对浏览器进行操作。测试脚本执行时,浏览器自动按照脚本代码做出点击,输入,打开,验证等操作,就像真实用户所做的一样,从终端用户的角度测试应用程序。
-
使浏览器兼容性测试自动化成为可能,尽管在不同的浏览器上依然有细微的差别。
-
使用简单,可使用Java,Python等多种语言编写用例脚本。
优势
1、模拟真实用户操作,支持多平台,可以在 Windows、Linux 和 Macintosh上的 Internet Explorer、Chrome和 Firefox 中运行
2、可以从终端用户的角度来测试应用程序。通过在不同浏览器中运行测试,更容易发现浏览器的不兼容性
3、测试脚本(HTML 的表布局编写的,要么是使用一种受支持的编程语言编写的)可以在受支持的浏览器中运行
使用Selenium
1、创建一个c#控制台程序
2、使用Nuget搜索以下依赖库,需要引用的核心库是Selenium.RC,Selenium.Support,Selenium.WebDriver
然后再需要引用 浏览器驱动库,这里我以IE浏览器为例,Chrome使用方式跟IE是一样的,程序包名称为Selenium.WebDriver.ChromeDriver。
3、在Main函数中输入以下代码
这里使用用了using(){},表示执行完{}里面的代码之后会自动释放括号内的代码资源。
(用于连接数据库的多,这样的话就可以不用写代码去关闭数据库连接了)
1 static void Main(string[] args) 2 { 3 using (IWebDriver driver = new OpenQA.Selenium.IE.InternetExplorerDriver()) 4 { 5 driver.Navigate().GoToUrl("http://www.baidu.com"); //driver.Url = "http://www.baidu.com"是一样的 6 7 var source = driver.PageSource; 8 9 Console.WriteLine(source); 10 } 11 }
运行,会弹出IE浏览器,网页加载完成后,浏览器会自动关闭。控制台输入结果如下
这样我们就可以轻松的获取动态渲染页面的源码。
基本用法:
通过id获取元素
1 //by id
2 //<div id="cards"></div> 3 var byID = driver.FindElement(By.Id("cards"));
通过类名获取元素
1 //by class name
2 //<div class="menu"></div> 3 var byClassName = driver.FindElements(By.ClassName("menu"));
通过标签名获取元素
1 //by tag name
2 //<iframe></iframe>
3 var byTagName = driver.FindElement(By.TagName("iframe"));
通过名字(name属性)获取元素
1 //by name
2 //<div name="__VIEWSTATE"></DIV>
3 var byName = driver.FindElement(By.Name("__VIEWSTATE"));
通过链接文本获取元素
1 //by linked text 2 //<a href="http://www.google.com">linkedtext</a>> 3 var byLinkText = driver.FindElement(By.LinkText("linkedtext"));
通过部分链接文本获取元素
1 //是模糊查找。比如百度网页中的关于 参数写“关”就可以了,不用写*这种符号 2 //<a href="http://www.google.com">linkedtext</a>> 3 var byPartialLinkText = driver.FindElement(By.PartialLinkText("text"));
通过CSS选择器获取元素
1 //by css 2 var byCss = driver.FindElement(By.CssSelector("#header .content .logo"));
通过XPath来获取元素
1 //by xpath 2 var byXPath = driver.FindElements(By.XPath("//div"));
在浏览器上打开开发者工具,然后点击要查看xpath的元素
点击后会自动定位到元素代码,选中右键 -->点击Copy,复制需要的相应内容,我这里用的谷歌,不同浏览器可能复制xpath的位置会不同
模拟鼠标点击元素
1 driver.FindElement(By.Id("copyright")).Click(); 2 或者 3 IWebElement eles = driver.FindElement(By.LinkText("关于百度")); 4 Actions actionsObj = new Actions(driver); 5 actionsObj.Click(eles).Perform();
鼠标双击控件
1 IWebElement eles=driver.FindElement(By.Id("id")); 2 Actions actionsObj = new Actions(driver); 3 actionsObj.DoubleClick(eles).Perform();
鼠标单击拖动
下面的代码演示的是从第1个控件单击并拖动至第4个控件,并选中这4个控件,如下所示(点击长按 -->拖动 --> 松手 )
1 driver.Url = "http://www.jqueryui.org.cn/demo/5640.html"; 2 Thread.Sleep(1000); 3 driver.Manage().Window.Maximize(); 4 ReadOnlyCollection<IWebElement> items = driver.FindElements(By.XPath("//ol[@id='selectable']/li")); 5 Assert.AreEqual<int>(7, items.Count); 6 Actions actionsObj = new Actions(driver); 7 actionsObj.ClickAndHold(items[0]).ClickAndHold(items[4]).Release().Perform();
移动鼠标到指定控件
1 IWebElement eles=driver.FindElement(By.Id("id")); 2 Actions actionsObj = new Actions(driver); 3 actionsObj.MoveToElement(eles).Perform();
鼠标拖放
拖放操作因操作简单易懂,在Web页面中应用也越来越广,特别是一些银行页面中。以下代码演示如何通过Selenium API来完成操作
- 方法一:通过方法DragAndDrop()实现
1 driver.Url = "http://www.jqueryui.org.cn/demo/5622.html"; 2 Thread.Sleep(1000); 3 driver.Manage().Window.Maximize(); 4 IWebElement soureEle = driver.FindElement(By.Id("draggable")); 5 IWebElement targetEle = driver.FindElement(By.Id("droppable")); 6 Actions actionObj = new Actions(driver); 7 actionObj.DragAndDrop(soureEle, targetEle).Perform(); 8 IWebElement textEle = driver.FindElement(By.XPath("//div[@id='droppable']/p")); 9 Assert.IsTrue(textEle.Text.Contains("Dropped!"));
- 方法二:通过方法MoveToElement()实现
1 driver.Url = "http://www.jqueryui.org.cn/demo/5622.html"; 2 Thread.Sleep(1000); 3 driver.Manage().Window.Maximize(); 4 IWebElement soureEle = driver.FindElement(By.Id("draggable")); 5 IWebElement targetEle = driver.FindElement(By.Id("droppable")); 6 Actions actionObj = new Actions(driver); 7 actionObj.ClickAndHold(soureEle).MoveToElement(targetEle).Release(targetEle).Perform(); 8 IWebElement textEle = driver.FindElement(By.XPath("//div[@id='droppable']/p")); 9 Assert.IsTrue(textEle.Text.Contains("Dropped!"));
- 方法三:通过方法MoveByOffset()实现
1 driver.Url = "http://www.jqueryui.org.cn/demo/5622.html"; 2 Thread.Sleep(1000); 3 driver.Manage().Window.Maximize(); 4 IWebElement soureEle = driver.FindElement(By.Id("draggable")); 5 IWebElement targetEle = driver.FindElement(By.Id("droppable")); 6 Actions actionObj = new Actions(driver); 7 actionObj.ClickAndHold(soureEle).MoveByOffset(100, 0).Perform(); 8 IWebElement textEle = driver.FindElement(By.XPath("//div[@id='droppable']/p")); 9 Assert.IsTrue(textEle.Text.Contains("Dropped!"));
拖动进度条或滑块
1 driver.Url = "http://demo.lanrenzhijia.com/2015/drag1218/"; 2 Thread.Sleep(1000); 3 driver.Manage().Window.Maximize(); 4 IWebElement origianlValueEle = driver.FindElement(By.Id("title")); 5 Assert.AreEqual("0", origianlValueEle.Text); 6 IWebElement sliderEle = driver.FindElement(By.Id("btn")); 7 Actions actionsObj = new Actions(driver); 8 actionsObj.DragAndDropToOffset(sliderEle, 100, 0).Perform(); 9 Assert.AreEqual("51%", origianlValueEle.Text);
单击鼠标右键菜单
在部分网站中会有一些操作需要通过右键菜单来实现,对于这种情况Selenium API也提供一种方法ContextClick()方法,详细演示如下所示:
1 driver.Url = "http://www.helloweba.com/demo/2017/basicContext/"; 2 Thread.Sleep(1000); 3 driver.Manage().Window.Maximize(); 4 IWebElement btnEle = driver.FindElement(By.XPath("//button[contains(@class,'btn-success context')]")); 5 Actions actionsObj = new Actions(driver); 6 7 actionsObj.ContextClick(btnEle).Perform();//点击右键菜单 8 IWebElement rightMenu = driver.FindElement(By.XPath("//div[@class='basicContext']/table/tbody/tr[2]")); 9 rightMenu.Click();//选择菜单 10 11 IAlert alert = driver.SwitchTo().Alert(); 12 string alertText = alert.Text; 13 alert.Accept(); 14 Assert.AreEqual<string>("Item clicked!",alertText);
弹框处理
类似下图所示的警告框,无法通过前端工具定位,需要跳转到弹框,然后再对其操作
3种弹框:
-
- 警告类弹框,Alert():一个按钮
- 确认类弹框,Confirmation:一个确认,一个取消
- 消息类弹框,Prompt:一个输入框, 一个确认,一个取消
跳转到弹框:
-
- SwitchTo().Alert()
常用的弹框处理方法:
-
- Text 获取警告框的内容
- Accept() 相当于点击确认按钮
- Dismiss() 相当于点击取消按钮
- SendKeys() 向警告框输入值
1 IAlert alert = driver.SwitchTo().Alert();//获取警告框 2 string alertText = alert.Text;//获取警告框中的内容 3 alert .Accept();//接受(确认)
执行JS
1 //execute javascript 2 var jsReturnValue = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("jsfunname");
当点击的元素包含href跳转的时候可以使用JavaScript来进行点击操作
(IJavaScriptExecutor)driver.ExecuteScript("arguments[0].click();", driver.FindElement(By.XPath("/html/body/div[2]/div/div[2]/div[2]/div[1]/h3/a")));
获取元素的值和属性
1 //get element value and attribute value
2 //var byID = driver.FindElement(By.Id("cards"));
3 var byIDText = byID.Text;
4 var byIDAttributeText = byID.GetAttribute("id");
页面导航
1 //Navigation()方法 摘要:指示驱动程序将将来的命令发送到不同的框架或窗口。说明:就是对对象进行进一些基本操作,比如刷新,打开,回退,向前 2 driver.Navigate().Forward(); //向前 3 driver.Navigate().Back(); //返回
4 driver.Navigate().Refrsh();//刷新当前打开的页面
5 driver.Close();//关闭当前选中的浏览器窗口,如果是最后一个窗口就退出浏览器
6 driver.Quit();//退出,关闭测试其对象,也会退出所有关联的窗口
7 driver.Manage().Window.Maximize();//浏览器最大化
8 .GoToUrl(Uri url)和 GoToUrl(string Url) //打开链接,在Navigate()方法后调用,将对象定位到指定的URL中去。如果是第一次调用,新打开一个浏览器窗体。和Open()方法一样
模拟键盘 SendKeys.SendWait()用法
1 SendKeys.SendWait("{F5}"); //发送F5按键 2 SendKeys.SendWait("^s"); //发送 Ctrl + s 键 3 SendKeys.SendWait("%{F4}"); // 发送 Alt + F4 键 4 5 //按键 代码 6 //BACKSPACE {BACKSPACE}, {BS}, 或 {BKSP} 7 //BREAK {BREAK} 8 //CAPS LOCK {CAPSLOCK} 9 //DEL or DELETE {DELETE} 或 {DEL} 10 // DOWN ARROW {DOWN} 11 //END {END} 12 //ENTER {ENTER}或 ~ 13 //ESC {ESC} 14 //HELP {HELP} 15 //HOME {HOME} 16 //INS or INSERT {INSERT} 或 {INS} 17 //LEFT ARROW {LEFT} 18 //NUM LOCK {NUMLOCK} 19 //PAGE DOWN {PGDN} 20 //PAGE UP {PGUP} 21 //PRINT SCREEN {PRTSC} 22 //RIGHT ARROW {RIGHT} 23 24 //为了指定重复键,使用 {key number} 的形式。必须在 key 与 number 之间放置一个空格。例如,{LEFT 42} 意指 42 次按下 25 //LEFT ARROW 键;{h 10} 则是指 10 次按下 H 键。
//为弹出windows文件选择框写入地址
Thread.Sleep(1000);
SendKeys.SendWait(@path);//path是传入的路径
Thread.Sleep(1000);
SendKeys.SendWait(@"{Enter}");
获取table中tr的数据
1 var ssoTr = driver.FindElement(By.XPath("/html/body/div[2]/div/div[2]/div[2]/div[3]/div[1]/table/tbody")).FindElements(By.TagName("tr")); 2 var toDayTr = ssoTr.Where(x => x.Text.Contains(DateTime.Now.ToString("yyyy-MM-dd"))).ToList();
iFrame的切换
1 //如果要取的元素显示报错找不到,其中一个原因可能是被iframe标签包裹住了,这个时候就要切换到iframe中,然后再取元素。 2 //注意,切换到iframe中就不可以继续操作主文档中的元素,如果要操作主文档的元素就需要切回到主文档 3 var iframe = driver.FindElement(By.Id("login-iframe-2019"));//找到ifram元素 4 driver.SwitchTo().Frame(iframe);//切换到ifram 5 6 driver.switch_to.default_content();//切回主文档
嵌套的iFrame操作
1 <html> 2 <iframe id="frame1"> 3 <iframe id="frame2" / > 4 </iframe> 5 </html>
1 //从主文档切到frame2,一层层切进去 2 driver.SwitchTo().Frame("rame1) 3 driver.SwitchTo().Frame("rame2) 4 //从frame2再切回frame1,这里selenium给我们提供了一个方法能够从子frame切回到父frame,而不用我们切回主文档再切进来。 5 driver.SwitchTo().ParentFrame() // 如果当前已是主文档,则无效果 6 7 //补充:之前曾看到过用点分法来切入嵌套frame的方法,但我没有试过不知道额能否成功 8 //切到 “frame1” 下的 “第一个frame” 下的 “frame3” 中。 9 driver.SwitchTo().Frame("frame1.0.frame1");
鼠标滚动
1 IJavaScriptExecutor js = (IJavaScriptExecutor)driver; 2 3 js.ExecuteScript("window.scrollTo(0,100)");//滚动鼠标位置到100 4 js.ExecuteScript("window.scrollTo(0,0)");//滚动鼠标至顶部 5 js.ExecuteScript("window.scrollTo(0,document.body.scrollHeight)'");//滚动鼠标至底部-这个我用报错了,暂时还没研究是啥问题 知道的小伙伴可以留言告诉我~
避免登录时总是需要手机号验证
Selenium启动浏览器时,默认是打开一个新用户,不会加载原有的配置以及插件,所以每次都需要登录,有的可能识别出时自动而是软件还会需要手机号验证码。
两种解决办法(我这里以谷歌浏览器为例):
1、加载浏览器配置文件(我试了这个方法没有效果,有尝试成功过的欢迎分享~)
①打开谷歌浏览器,输入chrome://version/,得到个人资料路径地址
②这里打开阿里云,但是打开之后还是需要输入账号密码登录,没有加载浏览器配置文件,百度到有人说登录进入之后就不需要再次登录了,但是我试过没有效果(执行脚本时需要关掉谷歌浏览器,不然可能会报错)
1 var option = new ChromeOptions(); 2 option.AddArgument(@"个人资料路径地址,地址截取到User Data 即可,路径后面的Default不需要,不然还是打开一个新用户"); 3 driver = new ChromeDriver(option); 4 driver.Url = "https://account.aliyun.com/login/login.htm?spm=5176.19720258.J_8058803260.35.e9392c4aykXZ6w&oauth_callback=https%3A%2F%2Fwww.aliyun.com%2F";
还有一种方式,打开时指定chrome驱动
①右键谷歌 ---》 属性,复制起始位置中的地址
②配置本地谷歌环境变量;
此电脑 --》 右键属性 --》点击高级系统设置 --》环境变量 --》选中Path,点击编辑 --》点击新建,将刚刚复制的路径粘贴上去一路点击确认下来即可
最后打开刚刚复制的路径,将下载的谷歌驱动 chromedriver.exe粘贴
var option = new ChromeOptions();
option.AddArgument(@"个人资料路径地址,地址截取到User Data 即可,路径后面的Default不需要,不然还是打开一个新用户");
driver = new ChromeDriver(@"C:UsersAdministratorAppDataLocalGoogleChromeApplicationchromedriver.exe", option);
driver.Url = "https://account.aliyun.com/login/login.htm?spm=5176.19720258.J_8058803260.35.e9392c4aykXZ6w&oauth_callback=https%3A%2F%2Fwww.aliyun.com%2F";
②
这里我一直报C:UsersAdministratorAppDataLocalGoogleChromeApplicationchromedriver.exe路径不存在,但是这个是有的
1 var option = new ChromeOptions(); 2 option.AddArgument(@"个人资料路径地址,地址截取到User Data 即可,路径后面的Default不需要,不然还是打开一个新用户"); 3 driver = new ChromeDriver(@"C:UsersAdministratorAppDataLocalGoogleChromeApplicationchromedriver.exe", option); 4 driver.Url = "https://account.aliyun.com/login/login.htm?spm=5176.19720258.J_8058803260.35.e9392c4aykXZ6w&oauth_callback=https%3A%2F%2Fwww.aliyun.com%2F";
2、使用Debug方式启动浏览器,使用Selenium连接到一个已打开的浏览器
1 chrome.exe --remote-debugging-port=9222 --user-data-dir="C:selenumAutomationProfile 2 3 // chrome:表示启动chrome浏览器 4 // remote-debugging-port:表示执行浏览器端口 5 // 9222为个人设置的端口 6 // --user-data-dir="C:selenumAutomationProfile":表示新建一个浏览器配置信息,地址自己定义
1 //先打开一个网页或者直接win+r打开cmd,输入命令行chrome.exe --remote-debugging-port=9222 --user-data-dir="C:selenumAutomationProfile",端口号可以自己定义; 2 Process proc = new Process(); 3 proc.StartInfo.FileName = @"C:UsersAdministratorAppDataLocalGoogleChromeApplicationchrome.exe"; 4 proc.StartInfo.Arguments = "https://vod.console.aliyun.com/?spm=5176.12818093.ProductAndService--ali--widget-home-product-recent.dre0.419916d0LZyB0A#/media/video/list --new-window --remote-debugging-port=9222 --user-data-dir=E:\selenum"; proc.Start(); 5 6 //将selenium连接到已经打开的浏览器,创建WebDriver并将浏览器的连接地址和端口作为参数传递给WebDriver 7 ChromeOptions options = new ChromeOptions(); 8 options.DebuggerAddress = "127.0.0.1:9222"; 9 driver = new ChromeDriver(options);