C# 利用Selenium实现浏览器自动化操作的示例代码
更新时间:2020年11月3日 15:19 点击:2139
概述
Selenium是一款免费的分布式的自动化测试工具,支持多种开发语言,无论是C、 java、ruby、python、或是C# ,你都可以通过selenium完成自动化测试。本文以一个简单的小例子,简述C# 利用Selenium进行浏览器的模拟操作,仅供学习分享使用,如有不足之处,还请指正。
涉及知识点
要实现本例的功能,除了要掌握Html ,JavaScript,CSS等基础知识,还涉及以下知识点:
- log4net:主要用于日志的记录和存储,本例采用log4net进行日志记录,便于过程跟踪和问题排查,关于log4net的配置和介绍,之前已有说明,本文不做赘述。
- Queue:队列,先进先出模式,本文主要用于将日志信息保存于队列中,然后再显示到页面上,其中Enqueue用于添加内容到结尾处,Dequeue用于返回并移除一个位置的对象。
- IWebDriver:浏览器驱动接口,所有的关于浏览器的操作都可以通过此接口进行,不同浏览器有不同的实现类,如:IE浏览器(InternetExplorerDriver)Chrome浏览器(ChromeDriver)等。
- BackgroundWorker:后台工作线程,区别于主线程,通过事件触发不同的状态。
Selenium安装
本例开发工具为VS2019,通过NuGet进行需要的软件包的安装与管理,如下所示:
示例效果图
本例采用Chrome浏览器,用于监控某一个网站并获取相应内容,如下所示:
Selenium示例介绍
定义一个webDriver,如下所示:
//谷歌浏览器 ChromeOptions options = new ChromeOptions(); this.driver = new ChromeDriver(options);
通过ID获取元素并填充内容和触发事件,如下所示:
this.driver.FindElement(By.Id("email")).SendKeys(username); this.driver.FindElement(By.Id("password")).SendKeys(password); //# 7. 点击登录按钮 this.driver.FindElement(By.Id("sign-in")).Click();
通过XPath获取元素,如下所示:
string xpath1 = "//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;
核心代码
主要的核心代码,就是浏览器的元素定位查找和事件触发,如下所示:
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> /// 是否正在运行 /// </summary> private bool running = false; /// <summary> /// 驱动 /// </summary> private IWebDriver driver = null; /// <summary> /// # 无货 /// </summary> private string no_stock = "Currently Out of Stock"; /// <summary> /// # 线程等待秒数 /// </summary> private int wait_sec = 2; private Dictionary<string, string> cfg_info; private string work_path = string.Empty; /// <summary> /// 构造函数 /// </summary> public Smoking() { } /// <summary> /// 带参构造函数 /// </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> /// 开始跑 /// </summary> public void startRun() { //"""运行起来""" 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("配置信息不全,请检查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 { //默认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. 定义浏览器驱动对象 this.driver = new InternetExplorerDriver(options); } } this.run(url, username, password, item_id); } catch (Exception e) { LogHelper.put("运行过程中出错,请重新打开再试"+e.StackTrace); } } /// <summary> /// 运行 /// </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) { //"""运行起来""" //# 3. 访问网站 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("欢迎回来"))) { //# 判断是否登录:已登录 LogHelper.put("登录成功,下一步开始工作了"); this.working(item_id); } else { LogHelper.put("登录失败,请设置账号密码"); } } /// <summary> /// 停止运行 /// </summary> public void stopRun() { //"""停止""" try { this.running = false; //# 如果驱动不为空,则关闭 //self.close_browser_nicely(self.__driver) if (this.driver != null) { this.driver.Quit(); //# 关闭后切要为None,否则启动报错 this.driver = null; } } catch (Exception e) { //print('Stop Failure') } finally { this.driver = null; } } private void login(string username, string password) { //# 5. 点击链接跳转到登录页面 this.driver.FindElement(By.LinkText("账户登录")).Click(); //# 6. 输入账号密码 //# 判断是否加载完成 if (this.checkIsExists(By.Id("email"))) { this.driver.FindElement(By.Id("email")).SendKeys(username); this.driver.FindElement(By.Id("password")).SendKeys(password); //# 7. 点击登录按钮 this.driver.FindElement(By.Id("sign-in")).Click(); } } /// <summary> /// 工作状态 /// </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 = "//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("没有查询到item id =" + item_id + "对应的信息"); continue; } } else { Thread.Sleep(this.wait_sec); LogHelper.put("没有查询到item id2 =" + item_id + "对应的信息"); continue; } //# 判断当前库存是否有货 string xpath1 = "//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) { //# 当前无货 Thread.Sleep(this.wait_sec); LogHelper.put("查询一次" + item_id + ",无货"); continue; } } //# 链接path1 string xpath2 = "//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); //# 加入购物车 if (this.checkIsExists(By.ClassName("add-to-cart"))) { this.driver.FindElement(By.ClassName("add-to-cart")).Click(); LogHelper.put("加入购物车成功,商品item-id:" + item_id); break; } else { LogHelper.put("未找到加入购物车按钮"); } } else { LogHelper.put("没有查询到,可能是商品编码不对,或者已下架"); } 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; } } } }
关于日志帮助类,代码如下:
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> /// 日志帮助类 /// </summary> public static class LogHelper { /// <summary> /// 日志实例 /// </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实现浏览器自动化操作的示例代码的详细内容,更多关于c# 实现浏览器自动化操作的资料请关注猪先飞其它相关文章!
相关文章
- 我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
- 这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
- 这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
- 本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
- 这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)
这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25- 这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- 本篇文章主要分享了通过window.navigator来判断浏览器及其版本信息的实例代码。具有一定的参考价值,下面跟着小编一起来看下吧...2017-01-23
- 最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
- 这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
- 这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
- 这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
- 这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
- 下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25