C# 使用Selenium

时间:2024-11-07 21:56:00

一、介绍:

Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。

1、Selenium Webdriver(也就是Selenium2,Selenium3)和Selenium RCSelenium 1)一样提供了web自动化的各种语言调用接口库。相比Selenium RCSelenium WebDriver的编程接口更加直观易懂,也更加简练。

但是和Selenium RC不同的是,Selenium Webdriver是通过各种浏览器的驱动(web driver)来驱动浏览器的,而不是通过注入JavaScript的方式。

我们的代码运行起来是一个进程,里面调用Selenium WebDriver的库和各个浏览器的驱动进程 进行交互,传递Selenium命令 给它们,并且获取命令执行的结果,返回给我们的代码进行处理。

2、Selenium WebDriver目前包括两个版本Selenium 2Selenium 3。这两个版本从开发代码调用接口上来看,几乎没什么区别。区别在于库的实现和web driver的实现。

Selenium2Selenium组织帮各种浏览器写web driver的,而Selenium 3里面的web driver是由各个浏览器厂商(Apple,Google,Microsoft,Mozilla)自己提供的。所以Selenium 3的自动化效率更高,成功率也更高。

3、Selenium WebDriver 支持浏览器众多:

  • Google Chrome
  • Microsoft Internet Explorer 7,8,9,10,11在 Windows Vista,Windows 7,Windows 8,Windows 8.1.
  • Microsoft Edge
  • Firefox
  • Safari
  • Opera

利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码 ,做到可见即可爬。

所以Selenium现在被广泛用于Python爬虫。查了下资料,发现这个工具确实强大,最重要的是,C#也是可以调用的。

官方支持Java,C#,Python,Ruby,PHP,Perl,Javascript等语言

官方文档(有C#示例):/documentation/

1、安装Selenium:

1、我们新建一个C#控制台程序

2、使用Nuget搜索以下依赖库

需要引用的核心库是,,

然后再需要引用浏览器驱动库,这里我以新版Edge浏览器为例,新版Edge使用方式跟Chrome是一样的,程序包名称为。


备注:也可以在微软WebDriver官网下载Edge (Chromium)的webdriver,需要和当前浏览器版本一致。然后下载放置到项目可执行文件的目录。

 

如果使用Chrome:

先查下本机Chrome的版本

然后去Nuget搜索进行下载安装。

注意:webdriver版本只需要和当前浏览器主版本一致即可。

3、在Main函数中输入以下代码

using ;
using ;
using System;
using ;

namespace WinForm2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var service = (@".", "");
            using (IWebDriver driver = new (service))
            {
                ().GoToUrl("");  // = ""是一样的
                var source = ;
                this. = source;
            }
        }
    }
}

如果是Chrome浏览器,可以这样:

IWebDriver driver = new ();
().GoToUrl("");

运行,会弹出IE浏览器,网页加载完成后,浏览器会自动关闭。控制台输入结果如下

这样我们就可以轻松的获取动态渲染页面的源码。

二、等待

常用的等待分为显示等待WebDriverWait()隐式等待ImplicitlyWait()强制等待sleep()三种,下面我们就分别介绍一下这三种等待的区别

  1. Sleep(): 强制等待,设置固定休眠时间。
  2. ImplicitlyWait():隐式等待,也叫智能等待,是 webdirver 提供的一个超时等待。隐的等待一个元素被发现,或一个命令完成。如果超出了设置时间的则抛出异常。
  3. WebDriverWait():显示等待,同样也是 webdirver 提供的方法。在设置时间内,默认每隔一段时间检测一次当前页面元素是否存在,如果超过设置时间检测不到则抛出异常。默认检测频率为0.5s,默认抛出异常为:NoSuchElementException

1、隐式等待:ImplicitlyWait

用到Timeouts对象。这个对象是用来对设置器进行一些设置的。

  • ImplicitlyWait:设置脚步在查找(定位)元素时最大的超时时间。如FindElement()方法在一些超大网页中进行定位时的超时时间。
  • PageLoad:设置页面操作超时时间(不是页面加载时间)。是在页面进行跳转操作或刷新操作时的等待时间。如Navigation对象的各种操作方法,以及在页面上进行某种操作后的等待时间。
  • AsynchronousJavaScript: 设置脚步异步执行的超时时间。

代码如下:

().GoToUrl("");
ITimeouts timeouts = ().Timeouts();

//设置查找元素最大超时时间为30秒
 = new TimeSpan(0, 0, 30);
//设置页面操作最大超时时间为30秒
 = new TimeSpan(0, 0, 30);
//设置脚本异步最大超时时间为30秒
 = new TimeSpan(0, 0, 30);

2、显示等待:WebDriverWait()

//等待页面元素加载完成
//默认等待100秒
WebDriverWait wait = new WebDriverWait(driver, (100));
//等待页面上ID属性值为submitButton的元素加载完成
IWebElement myElement = ((d) =>
{
    return (("submitButton"));
});

三、查找(定位对象)

通过FindElement()这个方法来查找的。然后把参数传递过去。

( ("kw")).SendKeys("搜索关键字");
(( "su")).Click();

其中("su")就是定位参数,传递一个对象过去。有8种定位方式。传递方式如下图:


注意:其中PartialLinkText是模糊查找。比如百度网页中的关于 参数写“关”就可以了,不用写*这种符号。

//通过ID获取元素
var byID = (("cards"));

//通过类名获取元素by class name
var byClassName = (("menu"));

// 通过标签名获取元素by tag name 
var byTagName = (("iframe"));

// 通过名字获取元素
var byName = (("__VIEWSTATE"));

// 通过链接文本获取元素by linked text  ">linkedtext>  
var byLinkText = (("linkedtext"));

// 通过部分链接文本获取元素by partial link text  :">linkedtext>
var byPartialLinkText = (("text"));

//通过CSS选择器获取元素by css
var byCss = (("#header .content .logo"));

//  通过XPath来获取元素(by xpath
var byXPath = (("//div"));

各方法使用优先原则:

优先使用id,name,classname,link;次之使用CssSelector();最后使用Xpath();

因为Xpath()方法的性能和效率最低下。

四、获取页面元素和元素内容

:标题

();//输出标题名

:链接

();//输出链接

:元素的文本值

 ();//输出元素标记中文本的信息

勾选情况、TagName标记名标、Enabled编辑状态、Displayed显示状态

()获取标签的属性

var byIDAttributeText = ("id");

6.弹出对话框的处理

首先,要先了解三种对话框:Alert、Confirmation以及Prompt。测试网页:

<html>
    <head>
         <title>这是标题</title>
     </head>

    <body>
         <input type="button" οnclick="alert('这是Alert');" value="Alert" /><br/>
         <input type="button" οnclick="confirm('这是confirm');" value="confirm" /><br/>
         <input type="button" οnclick="prompt('这是Prompt');" value="prompt" /><br/>
     </body>


 </html>

下面进行测试:

var service = (@".", "");
IWebDriver driver = new (service);

().GoToUrl("file:///C:/Users//Source/Repos/WinForm2/bin/Debug/");

IWebElement web = (("//input[1]"));
();


WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,2));
 //Wait for the alert to be displayed
 (());

(().Alert().Text);//在接收消息前输出
(1000);
().Alert().Accept();


IWebElement web2 = (("//input[2]"));
();
WebDriverWait wait2 = new WebDriverWait(driver, (10));
(());
(().Alert().Text);//在接收消息前输出
(1000);
().Alert().Accept();


IWebElement web3 = ((@"html/body/input[3]"));
();
(1000);
(().Alert().Text);//在接收消息前输出
().Alert().SendKeys("这是输入的内容");
().Alert().Accept();

五、操作元素对象WebElement

主要是进行Click和SendKeys操作,如图。其它的自己查看定义就知道了。

1、模拟鼠标点击元素

(("copyright")).Click();
  1. SenKeys就是在定位到输入框后,把参数text赋值进去
  2. Click就是进行鼠标点击操作,比如点击按钮等。和IDE上一样的。单选、复选都是通过这个方法这点击的。
  3. Clear方法:是用于清空输入框的值,和SendKeys正好的作用正好相反。自己测试时,建议先给输入框赋值,再用(3000)来暂停一下,再用Clear方法,不然你还没看到效果时,程序已经完成了。
  4. Submit:特殊之处在于,当定位的是Form表单中任何一个元素,当操作完之后,直接调用那个Submit方法就能对整个Form表单完成提交。不用再返回重新查找表单元素。

Selenium中在指定的文本框中输入指定的字符串

//在文本框中输入指定的字符串sendkeys()
(("tranAmtText")).SendKeys(“123456”);

2、下拉列表框Select的操作

().GoToUrl("/f/search/adv");
IList listOption = (("sm")).FindElements(("option"));
string targetStr = "按相关性排序";

foreach (var option in listOption)
{
    if ( == targetStr)  // if (("value").Equals(targetStr))
        ();
}

2、执行JS

var jsReturnValue = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("jsfunname");

3、页面导航

().Forward();
().Back();

Selenium中移动光标到指定的元素上

//移动光标到指定的元素上perform
Actions action=new Actions(driver);
(Find(("//input[@id='submit' and @value='确定']"))).Perform();

4、拖拽操作(可以实现滑动验证码的验证)

var element = (("source"));
IWebElement target = (("target"));
(new Actions(driver)).DragAndDrop(element, target).Perform();

5、模拟鼠标晃动

//模拟光标晃动movebyoffset()
Actions action = new Actions(driver);
(2, 4);

6、截图功能

//WebDriver中自带截图功能
Screenshot screenShotFile = ((ITakesScreenshot)driver).GetScreenshot();
("test", );

7、selenium操作滚轮滑动到底部

driver.execute_script("(0,);")

六、获得窗口标识WindowHandles

要在不同的浏览器窗口之间切换,必须获得不同的窗口(标签)的标识符。用一个集合来保存这些数据。当需要到新窗口里进行操作时,需要将测试器前往新的窗口。开始创建的测试器是对窗口来的,所以当我们需要切换窗口时。需要调用 测试器.SwitchTo().window(获得标识) 这个方法来返回一个新的测试器对象。新的对象是代表的是切换的窗口。代码如下:

var service = (@".", "");
IWebDriver driver = new (service);

().GoToUrl("/f/search/adv");
//找到注册元素
IWebElement register = ((@".//*[@id='com_userbar']/ul/li[5]/div/a"));
();

//显示所有标识
IList<string> listHand = ;//拿到所有标识
foreach (string item in listHand)
{
    (item);
}

/*这里一会插入代码*/

();
();

效果如下:

下面切换到新打开的窗口后,输入一个12345来表示我们成功了
在上面的代码基础下 添加下面代码

//切换到注册窗口再输入12345
().Window(listHand[1]);
(("userName")).SendKeys("12345");

结果如图:

1、关闭多个子Browser窗口

//获取所有的WindowHandle,关闭所有子窗口
string oldwin = ;
ReadOnlyCollection<string> windows = ;
foreach (var win in windows)
{
    if (win != oldwin)
    {
        ().Window(win).Close();
    }
}
().Window(oldwin);

2、对iframe中元素的定位

1、切换焦点到id为固定值的iframe上

进入页面后,光标默认焦点在DefaultContent中,若想要定位到iframe 需要转换焦点

().DefaultContent();
//切换焦点到mainFrame
().Frame("mainFrame");

需要注意的是:切换焦点之后若想切换焦点到其他iframe上 需要先返回到defaultcontent,再切换焦点到指定的iframe上。

2、切换焦点到id值为动态值的iframe上

有时候 页面上浮出层的id为动态值,此时需要先获取所有符合记录的iframe放置在数组中,然后遍历数组切换焦点到目标iframe上。

如下方法:

protected string bizFrameId = ;
protected string bizId = ;
//获取动态iframe的id值
protected void SetIframeId()
{
    ReadOnlyCollection els = (("iframe"));
    foreach (var e in (("iframe")))
    {
        string s1 = ("id");
        if (("window") >= 0 && ("content") >= 0)
        {
            bizFrameId = ("id");
            string[] ss = (new char[] { '_' });
            bizId = ss[1];
        }
    }
}

七、Cookies

在C#中,通过Cookies属性来获取当前的Cookie集合,然后进行增删改查操作。

Cookie由5个部分组成:名称、值、所在域、路径和过期时间。

下面我们进入百度首页,然后获取cookie,并让它变动一下来看到效果。 代码如下:

var service = (@".", "");
IWebDriver driver = new (service);

().GoToUrl("");


//获取Cookie
ICookieJar listCookie = ().Cookies;
// IList listCookie = ( ).;//只是显示 可以用Ilist对象
//显示初始Cookie的内容
("--------------------");
($"当前Cookie集合的数量:\t{}");
for (int i = 0; i < ; i++)
{

    ($"Cookie的名称:{[i].Name}");
    ($"Cookie的值:{[i].Value}");
    ($"Cookie的所在域:{[i].Domain}");
    ($"Cookie的路径:{[i].Path}");
    ($"Cookie的过期时间:{[i].Expiry}");
    ("-----");
}


//添加一个新的Cookie
Cookie newCookie = new Cookie("新Cookie", "新值", "", (1));

(newCookie);
("--------------------");
($"当前Cookie集合的数量:\t{}");
for (int i = 0; i < ; i++)
{

    ($"Cookie的名称:{[i].Name}");
    ($"Cookie的值:{[i].Value}");
    ($"Cookie的所在域:{[i].Domain}");
    ($"Cookie的路径:{[i].Path}");
    ($"Cookie的过期时间:{[i].Expiry}");
    ("-----");
}

//删除这个Cookie并再次显示总数
();

($"当前Cookie集合的数量:\t{}");


();
();

运行效果如下:

八、Window窗口控制

这个属性是可以对当前的窗口进行简单的控制。如获取坐标和大小,还可以将其最大化。下面我们用过示例代码来试试效果。
下面的代码是先打开网页,打印坐标和大小,再控制它最大化,再次打印坐标和大小。

var service = (@".", "");
IWebDriver driver = new (service);

().GoToUrl("");

//打印现在的坐标和大小
IWindow window = ().Window;
("第一次打印");
($"坐标X为{}\tY为{}");
($"大小长为{}\t宽为{}");
("-------------");

//控制最大化
();

//再次打印数据
("第二次打印");
($"坐标X为{}\tY为{}");
($"大小长为{}\t宽为{}");
("-------------");

();
();

效果如下:


这里有两个奇怪的地方:
1.我的屏幕是1080P的,输出后的数据中,长只有1936.如果减去16的话到正好是1920.但是宽应该是1080,如果任务栏的宽度是24的话,到也能说得过去。只是数据和我们要的有点偏差,这里需要注意一下。
属性居然只有位置、大小和最大化方法。居然没有最小化或还原(退出最大化状态)方法。

九、事件

首先是准备好要添加的事件,然后再挂接。这里可以使用C#的语法糖。在+=后面直接按两次tab键,然后再移动到事件区编辑。

 += EventDriver_Navigating;//导航前
 += EventDriver_Navigated;//导航后
 += EventDriver_FindingElement;//查找元素前
 += EventDriver_FindElementCompleted;//查找元素后
 += EventDriver_ElementClicking;//元素单击前
 += EventDriver_ElementClicked;//元素单击后
 += EventDriver_ElementValueChanging;//元素值改变前
 += EventDriver_ElementValueChanged;//元素值改变后
 += EventDriver_ExceptionThrown;//异常发生后事件

挂接事件:

#region 事件区

/// 
/// 导航前发生的事件
/// 
/// 
/// 
private void EventDriver_Navigating(object sender, WebDriverNavigationEventArgs e)
{
    ("-----------------------------------------");
    ($"即将要跳转到的URL为:{}");
}

/// 
/// 导航后发生的事件
/// 
/// 
/// 
private void EventDriver_Navigated(object sender, WebDriverNavigationEventArgs e)
{
    ("-----------------------------------------");
    ($"跳转到的URL为:{}");
}

/// 
/// 查找元素前发生
/// 
/// 
/// 
private void EventDriver_FindingElement(object sender, FindElementEventArgs e)
{
    ("-----------------------------------------");

    ($"即将查找的元素为:{()}");
}

/// 
/// 查找元素后发生
/// 
/// 
/// 
private void EventDriver_FindElementCompleted(object sender, FindElementEventArgs e)
{
    ("-----------------------------------------");
    ($"找到元素,条件为:{()}");
}

/// 
/// 单击元素前发生
/// 
/// 
/// 
private void EventDriver_ElementClicking(object sender, WebElementEventArgs e)
{
    ("-----------------------------------------");
    ($"要单击的元素的value属性为:{("value")}");
}

/// 
/// 单击元素后发生
/// 
/// 
/// 
private void EventDriver_ElementClicked(object sender, WebElementEventArgs e)
{
    (3 * 1000);//暂停3秒
    ("-----------------------------------------");
    ($"单击元素后,现在的URL为:{}");
}

/// 
/// 单击元素前发生
/// 
/// 
/// 
private void EventDriver_ElementValueChanging(object sender, WebElementEventArgs e)
{
    ("-----------------------------------------");
    ($"元素更改前的值为:{("value")}");
}

/// 
/// 单击元素后发生
/// 
/// 
/// 
private void EventDriver_ElementValueChanged(object sender, WebElementEventArgs e)
{
    ("-----------------------------------------");
    ($"元素更改后的值为:{("value")}");
}

/// 
/// 异常(保存截图到本地)
/// 
/// 
/// 
private void EventDriver_ExceptionThrown(object sender, WebDriverExceptionEventArgs e)
{
    //地址
    string strPath = $@"D:\Desktop\{("yyyy-MM-dd HH-mm-ss")}.png";

    //保存截图
    Screenshot screen = (sender as EventFiringWebDriver).GetScreenshot();
    (strPath, );

    //输出保存信息
    ("-----------------------------------------");
    ($"发生异常,截图已保存到:{strPath}");
}

十、关闭浏览器

有下面两种:

  1. Close():关闭WedDriver对象所在的窗口;
    第一个是关闭一个窗口,一个wedDriver对象是可以有多个窗口的(之前的窗口切换也是提到过),需要关闭时要保证当前激活的窗口。比如一个wedDriver对象里有好多个窗口,你要关闭第2个窗口,就要用SwitchTo().Window()方法切换到第2个窗口才能关闭,不能直接关闭第几个窗口的。
  2. Quit():关闭所有相关窗口;
    第二个关闭和这个webDriver对象所有相关的窗口。当然,一个脚本是可以有多个webDriver对象

下面代码的代码展示这了两个方法的用法和用途。
1.打开百度首页,单击“注册”超级链接。
2.在弹出的窗口(百度账户注册)中,调用Close()方法,关闭新弹出的页面
3.再一次点击“注册”超级链接,调用Quit()方法来结束测试。

var service = (@".", "");
IWebDriver driver = new (service);

//导航到百度首页
().GoToUrl("");

//进行点击
("-------------------");
("进行点击");
(("登录")).Click();
(3 * 1000);
(("立即注册")).Click();

//获取窗口句柄
IList<string> listHand = ;

//切换到注册窗口并关闭
("-------------------");
("切换到注册窗口");
().Window(listHand[1]);
(3 * 1000);
("-------------------");
("关闭注册窗口");
();
(3 * 1000);

//切换到主窗口并结束测试
("-------------------");
("切换到主窗口并结束测试");
().Window(listHand[0]);
(("立即注册")).Click();
(3 * 1000);
();

();