C# 利用Selenium實(shí)現(xiàn)瀏覽器自動(dòng)化操作的示例代碼
概述
Selenium是一款免費(fèi)的分布式的自動(dòng)化測(cè)試工具,支持多種開(kāi)發(fā)語(yǔ)言,無(wú)論是C、 java、ruby、python、或是C# ,你都可以通過(guò)selenium完成自動(dòng)化測(cè)試。本文以一個(gè)簡(jiǎn)單的小例子,簡(jiǎn)述C# 利用Selenium進(jìn)行瀏覽器的模擬操作,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正。
涉及知識(shí)點(diǎn)
要實(shí)現(xiàn)本例的功能,除了要掌握Html ,JavaScript,CSS等基礎(chǔ)知識(shí),還涉及以下知識(shí)點(diǎn):
- log4net:主要用于日志的記錄和存儲(chǔ),本例采用log4net進(jìn)行日志記錄,便于過(guò)程跟蹤和問(wèn)題排查,關(guān)于log4net的配置和介紹,之前已有說(shuō)明,本文不做贅述。
- Queue:隊(duì)列,先進(jìn)先出模式,本文主要用于將日志信息保存于隊(duì)列中,然后再顯示到頁(yè)面上,其中Enqueue用于添加內(nèi)容到結(jié)尾處,Dequeue用于返回并移除一個(gè)位置的對(duì)象。
- IWebDriver:瀏覽器驅(qū)動(dòng)接口,所有的關(guān)于瀏覽器的操作都可以通過(guò)此接口進(jìn)行,不同瀏覽器有不同的實(shí)現(xiàn)類(lèi),如:IE瀏覽器(InternetExplorerDriver)Chrome瀏覽器(ChromeDriver)等。
- BackgroundWorker:后臺(tái)工作線程,區(qū)別于主線程,通過(guò)事件觸發(fā)不同的狀態(tài)。
Selenium安裝
本例開(kāi)發(fā)工具為VS2019,通過(guò)NuGet進(jìn)行需要的軟件包的安裝與管理,如下所示:

示例效果圖
本例采用Chrome瀏覽器,用于監(jiān)控某一個(gè)網(wǎng)站并獲取相應(yīng)內(nèi)容,如下所示:

Selenium示例介紹
定義一個(gè)webDriver,如下所示:
//谷歌瀏覽器 ChromeOptions options = new ChromeOptions(); this.driver = new ChromeDriver(options);
通過(guò)ID獲取元素并填充內(nèi)容和觸發(fā)事件,如下所示:
this.driver.FindElement(By.Id("email")).SendKeys(username);
this.driver.FindElement(By.Id("password")).SendKeys(password);
//# 7. 點(diǎn)擊登錄按鈕
this.driver.FindElement(By.Id("sign-in")).Click();
通過(guò)XPath獲取元素,如下所示:
string xpath1 = "http://div[@class=\"product-list\"]/div[@class=\"product\"]/div[@class=\"price-and-detail\"]/div[@class=\"price\"]/span[@class=\"noStock\"]"; string txt = this.driver.FindElement(By.XPath(xpath1)).Text;
核心代碼
主要的核心代碼,就是瀏覽器的元素定位查找和事件觸發(fā),如下所示:
using OpenQA.Selenium;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Chrome;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AiSmoking.Core
{
public class Smoking
{
/// <summary>
/// 是否正在運(yùn)行
/// </summary>
private bool running = false;
/// <summary>
/// 驅(qū)動(dòng)
/// </summary>
private IWebDriver driver = null;
/// <summary>
/// # 無(wú)貨
/// </summary>
private string no_stock = "Currently Out of Stock";
/// <summary>
/// # 線程等待秒數(shù)
/// </summary>
private int wait_sec = 2;
private Dictionary<string, string> cfg_info;
private string work_path = string.Empty;
/// <summary>
/// 構(gòu)造函數(shù)
/// </summary>
public Smoking()
{
}
/// <summary>
/// 帶參構(gòu)造函數(shù)
/// </summary>
/// <param name="cfg_info"></param>
/// <param name="work_path"></param>
public Smoking(Dictionary<string, string> cfg_info,string work_path)
{
this.cfg_info = cfg_info;
this.work_path = work_path;
this.wait_sec = int.Parse(cfg_info["wait_sec"]);
//# 如果小于2,則等于2
this.wait_sec = (this.wait_sec < 2 ? 2 : this.wait_sec);
this.wait_sec = this.wait_sec * 1000;
}
/// <summary>
/// 開(kāi)始跑
/// </summary>
public void startRun()
{
//"""運(yùn)行起來(lái)"""
try
{
this.running = true;
string url = this.cfg_info["url"];
string username = this.cfg_info["username"];
string password = this.cfg_info["password"];
string item_id = this.cfg_info["item_id"];
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(item_id))
{
LogHelper.put("配置信息不全,請(qǐng)檢查config.cfg文件是否為空,然后再重啟");
return;
}
if (this.driver == null)
{
string explorer = this.cfg_info["explorer"];
if (explorer == "Chrome")
{
//谷歌瀏覽器
ChromeOptions options = new ChromeOptions();
this.driver = new ChromeDriver(options);
}
else
{
//默認(rèn)IE
var options = new InternetExplorerOptions();
//options.AddAdditionalCapability.('encoding=UTF-8')
//options.add_argument('Accept= text / css, * / *')
//options.add_argument('Accept - Language= zh - Hans - CN, zh - Hans;q = 0.5')
//options.add_argument('Accept - Encoding= gzip, deflate')
//options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko')
//# 2. 定義瀏覽器驅(qū)動(dòng)對(duì)象
this.driver = new InternetExplorerDriver(options);
}
}
this.run(url, username, password, item_id);
}
catch (Exception e)
{
LogHelper.put("運(yùn)行過(guò)程中出錯(cuò),請(qǐng)重新打開(kāi)再試"+e.StackTrace);
}
}
/// <summary>
/// 運(yùn)行
/// </summary>
/// <param name="url"></param>
/// <param name="username"></param>
/// <param name="password"></param>
/// <param name="item_id"></param>
private void run(string url, string username, string password, string item_id)
{
//"""運(yùn)行起來(lái)"""
//# 3. 訪問(wèn)網(wǎng)站
this.driver.Navigate().GoToUrl(url);
//# 4. 最大化窗口
this.driver.Manage().Window.Maximize();
if (this.checkIsExists(By.LinkText("賬戶登錄")))
{
//# 判斷是否登錄:未登錄
this.login(username, password);
}
if (this.checkIsExists(By.PartialLinkText("歡迎回來(lái)")))
{
//# 判斷是否登錄:已登錄
LogHelper.put("登錄成功,下一步開(kāi)始工作了");
this.working(item_id);
}
else
{
LogHelper.put("登錄失敗,請(qǐng)?jiān)O(shè)置賬號(hào)密碼");
}
}
/// <summary>
/// 停止運(yùn)行
/// </summary>
public void stopRun()
{
//"""停止"""
try
{
this.running = false;
//# 如果驅(qū)動(dòng)不為空,則關(guān)閉
//self.close_browser_nicely(self.__driver)
if (this.driver != null)
{
this.driver.Quit();
//# 關(guān)閉后切要為None,否則啟動(dòng)報(bào)錯(cuò)
this.driver = null;
}
}
catch (Exception e)
{
//print('Stop Failure')
}
finally
{
this.driver = null;
}
}
private void login(string username, string password)
{
//# 5. 點(diǎn)擊鏈接跳轉(zhuǎn)到登錄頁(yè)面
this.driver.FindElement(By.LinkText("賬戶登錄")).Click();
//# 6. 輸入賬號(hào)密碼
//# 判斷是否加載完成
if (this.checkIsExists(By.Id("email")))
{
this.driver.FindElement(By.Id("email")).SendKeys(username);
this.driver.FindElement(By.Id("password")).SendKeys(password);
//# 7. 點(diǎn)擊登錄按鈕
this.driver.FindElement(By.Id("sign-in")).Click();
}
}
/// <summary>
/// 工作狀態(tài)
/// </summary>
/// <param name="item_id"></param>
private void working(string item_id)
{
while (this.running)
{
try
{
//# 正常獲取信息
if (this.checkIsExists(By.Id("string")))
{
this.driver.FindElement(By.Id("string")).Clear();
this.driver.FindElement(By.Id("string")).SendKeys(item_id);
this.driver.FindElement(By.Id("string")).SendKeys(Keys.Enter);
}
//# 判斷是否查詢到商品
string xpath = "http://div[@class=\"specialty-header search\"]/div[@class=\"specialty-description\"]/div[@class=\"gt-450\"]/span[2] ";
if (this.checkIsExists(By.XPath(xpath)))
{
int count = int.Parse(this.driver.FindElement(By.XPath(xpath)).Text);
if (count < 1)
{
Thread.Sleep(this.wait_sec);
LogHelper.put("沒(méi)有查詢到item id =" + item_id + "對(duì)應(yīng)的信息");
continue;
}
}
else
{
Thread.Sleep(this.wait_sec);
LogHelper.put("沒(méi)有查詢到item id2 =" + item_id + "對(duì)應(yīng)的信息");
continue;
}
//# 判斷當(dāng)前庫(kù)存是否有貨
string xpath1 = "http://div[@class=\"product-list\"]/div[@class=\"product\"]/div[@class=\"price-and-detail\"]/div[@class=\"price\"]/span[@class=\"noStock\"]";
if (this.checkIsExists(By.XPath(xpath1)))
{
string txt = this.driver.FindElement(By.XPath(xpath1)).Text;
if (txt == this.no_stock)
{
//# 當(dāng)前無(wú)貨
Thread.Sleep(this.wait_sec);
LogHelper.put("查詢一次" + item_id + ",無(wú)貨");
continue;
}
}
//# 鏈接path1
string xpath2 = "http://div[@class=\"product-list\"]/div[@class=\"product\"]/div[@class=\"imgDiv\"]/a";
//# 判斷是否加載完畢
//# this.waiting((By.CLASS_NAME, "imgDiv"))
if (this.checkIsExists(By.XPath(xpath2)))
{
this.driver.FindElement(By.XPath(xpath2)).Click();
Thread.Sleep(this.wait_sec);
//# 加入購(gòu)物車(chē)
if (this.checkIsExists(By.ClassName("add-to-cart")))
{
this.driver.FindElement(By.ClassName("add-to-cart")).Click();
LogHelper.put("加入購(gòu)物車(chē)成功,商品item-id:" + item_id);
break;
}
else
{
LogHelper.put("未找到加入購(gòu)物車(chē)按鈕");
}
}
else
{
LogHelper.put("沒(méi)有查詢到,可能是商品編碼不對(duì),或者已下架");
}
Thread.Sleep(this.wait_sec);
}
catch (Exception e)
{
Thread.Sleep(this.wait_sec);
LogHelper.put(e);
}
}
}
/// <summary>
/// 判斷是否存在
/// </summary>
/// <param name="by"></param>
/// <returns></returns>
private bool checkIsExists(By by)
{
try
{
int i = 0;
while (this.running && i < 3)
{
if (this.driver.FindElements(by).Count > 0)
{
break;
}
else
{
Thread.Sleep(this.wait_sec);
i = i + 1;
}
}
return this.driver.FindElements(by).Count > 0;
}
catch (Exception e)
{
LogHelper.put(e);
return false;
}
}
}
}
關(guān)于日志幫助類(lèi),代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace AiSmoking.Core
{
/// <summary>
/// 日志幫助類(lèi)
/// </summary>
public static class LogHelper
{
/// <summary>
/// 日志實(shí)例
/// </summary>
private static ILog logInstance = LogManager.GetLogger("smoking");
private static Queue<string> queue = new Queue<string>(2000);
public static void put(string msg)
{
queue.Enqueue(msg);
WriteLog(msg, LogLevel.Info);
}
public static void put(Exception ex)
{
WriteLog(ex.StackTrace, LogLevel.Error);
}
public static string get()
{
if (queue.Count > 0)
{
return queue.Dequeue();
}
else
{
return string.Empty;
}
}
public static void WriteLog(string message, LogLevel level)
{
switch (level)
{
case LogLevel.Debug:
logInstance.Debug(message);
break;
case LogLevel.Error:
logInstance.Error(message);
break;
case LogLevel.Fatal:
logInstance.Fatal(message);
break;
case LogLevel.Info:
logInstance.Info(message);
break;
case LogLevel.Warn:
logInstance.Warn(message);
break;
default:
logInstance.Info(message);
break;
}
}
}
public enum LogLevel
{
Debug = 0,
Error = 1,
Fatal = 2,
Info = 3,
Warn = 4
}
}
作者:Alan.hsiang
出處:http://www.cnblogs.com/hsiang/
以上就是C# 利用Selenium實(shí)現(xiàn)瀏覽器自動(dòng)化操作的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于c# 實(shí)現(xiàn)瀏覽器自動(dòng)化操作的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用C# 的webBrowser寫(xiě)模擬器時(shí)的javascript腳本調(diào)用問(wèn)題
這篇文章主要介紹了C# 的webBrowser寫(xiě)模擬器時(shí)的javascript腳本調(diào)用問(wèn)題,需要的朋友可以參考下2017-07-07
C#的Socket實(shí)現(xiàn)UDP協(xié)議通信示例代碼
本篇文章主要介紹了C#的Socket實(shí)現(xiàn)UDP協(xié)議通信示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01
超簡(jiǎn)單C#獲取帶漢字的字符串真實(shí)長(zhǎng)度(單個(gè)英文長(zhǎng)度為1,單個(gè)中文長(zhǎng)度為2)
正常情況下,我們是直接去string的length的,但是漢字是有兩個(gè)字節(jié)的,所以直接用length是錯(cuò)的2018-03-03
C# 使用鼠標(biāo)點(diǎn)擊對(duì)Chart控件實(shí)現(xiàn)數(shù)據(jù)提示效果
這篇文章主要介紹了C# 使用鼠標(biāo)點(diǎn)擊對(duì)Chart控件實(shí)現(xiàn)數(shù)據(jù)提示效果,文章給予上一篇的詳細(xì)內(nèi)容做延伸介紹,需要的小伙伴可任意參考一下2022-08-08
解析C#中[],List,Array,ArrayList的區(qū)別及應(yīng)用
本篇文章主要是對(duì)C#中[],List,Array,ArrayList的區(qū)別及應(yīng)用進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01
C#利用OLEDB實(shí)現(xiàn)將DataTable寫(xiě)入Excel文件中
這篇文章主要為大家詳細(xì)介紹了C#如何利用OLEDB實(shí)現(xiàn)將DataTable寫(xiě)入Excel文件中,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,需要的可以參考一下2023-02-02

