欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-11 13:06:46
概述selenium是一款免费的分布式的自动化测试工具,支持多种开发语言,无论是c、 java、ruby、python、或是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进行需要的软件包的安装与管理,如下所示:

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

示例效果图

本例采用chrome浏览器,用于监控某一个网站并获取相应内容,如下所示:

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

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