C# 利用Selenium实现浏览器自动化操作的示例代码

概述

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# 实现浏览器自动化操作的资料请关注我们其它相关文章!

(0)

相关推荐

  • C#实现微信跳一跳小游戏的自动跳跃助手开发实战

    一.前言: 前段时间微信更新了新版本后,带来的一款H5小游戏"跳一跳"在各朋友圈里又火了起来,类似以前的"打飞机"游戏,这游戏玩法简单,但加上了积分排名功能后,却成了"装逼"的地方,于是很多人花钱花时间的刷积分抢排名.后来越来越多的聪明的"程序哥们"弄出了不同方式不同花样的跳一跳助手(外挂?),有用JS实现的.有JAVA实现的.有Python实现的,有直接物理模式的.有机械化的.有量尺子的等等,简直是百花齐放啊-- 赶一下潮流

  • C#实现基于IE内核的简单浏览器完整实例

    本文实例讲述了C#实现基于IE内核的简单浏览器.分享给大家供大家参考.具体如下: Form1.cs如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Kit

  • C#定时每天00点00分00秒自动重启软件

    本文实例为大家分享了C#定时每天自动重启软件的具体代码,供大家参考,具体内容如下 1.添加Timer控件,这个控件可以显示倒计时功能 2.Timer控件的Tick事件代码: private void timerDownCount_Tick(object sender, EventArgs e) { string dateDiff = null; //获取当前时间 DateTime DateTime1 = DateTime.Now; //第二天的00点00分00秒 DateTime DateTim

  • C#编程实现简易图片浏览器的方法

    本文实例讲述了C#编程实现简易图片浏览器的方法.分享给大家供大家参考,具体如下: 首先需要加上命名空间 using system.io; 拖一个PICTUREBOX,两个TEXTBOX string fold = "";//用来存不包含文件后缀名的路径 string[] files;//用来存当前所有统一后缀文件的总路径 int pos=0;//用于图片切换 private void button1_Click(object sender, EventArgs e) { OpenFil

  • C#实现清除IE浏览器缓存的方法

    本文实例讲述了C#实现清除IE浏览器缓存的方法.分享给大家供大家参考.具体如下: 项目中碰到wpf webbrowser的几个问题,在此记录一下 1.webbrowser中对于jquery的bind事件的处理. 在普通的浏览器下一下这种写法没有任何问题 var content = $("<div><h4><span>" + category_name + "</span>(<a id='href_" + guid

  • C#使用Selenium+PhantomJS抓取数据

    手头项目需要抓取一个用js渲染出来的网站中的数据.使用常用的httpclient抓回来的页面是没有数据.上网百度了一下,大家推荐的方案是使用PhantomJS.PhantomJS是一个没有界面的webkit浏览器,能够和浏览器效果一致的使用js渲染页面.Selenium是一个web测试框架.使用Selenium来操作PhantomJS绝配.但是网上的例子多是Python的.无奈,下载了python按照教程搞了一下,卡在了Selenium的导入问题上.遂放弃,还是用自己惯用的c#吧,就不信c#上没

  • 跳一跳自动跳跃C#代码实现

    最近这款"跳一跳"很火,在段子里面看到有人才放了张画着坐标的纸在手机上,说根据距离确定摁的"嘟"的次数,还有通过程序来实现自动计算的.看得心血来潮忍不住来试一试?话不多说,先上图. 因为比较急着做出成品,所以细节上没多细抠.感觉设置的跳跃速度稍快了一点,有兴趣的同学可以实测一下.也有一个因素是测试时后台程序比较多,影响了结果.        原理其实也是跟大家想的一样很简单,无非就是三个要素:距离.速度.时间.就是通过当前小蓝人脚底所在的像素坐标和目标平台中心像素的

  • C#使用Selenium的实现代码

    介绍: Selenium 是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等. 利用它可以驱动浏览器执行特定的动作,如点击.下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码 ,做到可见即可爬. 所以Selenium现在被广泛用于Python爬虫.查了下资料,发现这个工具确实强大,最重要的是,C#也是

  • 微信跳一跳自动脚本C#代码实现

    前言 CSDN前阵子推送了篇文章,讲的是微信跳一跳的技术实现,大致浏览,发现难度不高,很适合练手. 思路 ADB得到屏幕截图,转换成bitmap逐像素分析图像,得到跳跃起点和终点坐标,最后ADB按压屏幕进行跳跃 相关知识 ADB创建 ·在https://adb.clockworkmod.com提前下载ADB ·通过 Process类 创建进程运行ADB Process p = new Process(); p.StartInfo = new ProcessStartInfo() { FileNa

  • C# 模拟浏览器并自动操作的实例代码

    本文主要讲解通过WebBrowser控件打开浏览页面,并操作页面元素实现自动搜索功能,仅供学习分享使用,如有不足之处,还请指正. 涉及知识点 WebBrowser:用于在WinForm窗体中,模拟浏览器,打开并导航网页. HtmlDocument:表示一个Html文档的页面.每次加载都会是一个全新的页面. GetElementById(string id):通过ID或Name获取一个Html中的元素. HtmlElement:表示一个Html标签元素. BackgroundWorker 后台执行

  • C#使用默认浏览器打开网页的方法

    本文实例讲述了C#使用默认浏览器打开网页的方法.分享给大家供大家参考.具体实现方法如下: public static bool OpenBrowser(String url) { RegistryKey key = Registry.ClassesRoot.OpenSubKey(@"http\shell\open\command\"); String s = key.GetValue("").ToString(); String browserpath = null

随机推荐