百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

更简单地自动化操作浏览器

liebian365 2024-11-18 14:18 16 浏览 0 评论

aardio 可以嵌入一大堆的浏览器组件,而且代码都非常简洁,不过今天我们要说的不是这些功能。

我们知道,在其他编程语言里比较流行的是使用 WebDriver 协议控制浏览器,这个非常方便,但实际用起来要做的事还不少,例如 WebDriver 控制 Chrome 你要安装 ChromeDriver,用 WebDriver 控制 Edge,你要安装 EdgeDriver ,而且每个不同版本的浏览器,要安装的对应的 Driver.exe 都 是不同的,这就真是个大坑了。

试想一下,别人电脑上有没有装 Chrome 还不一定,你得让用户自己装这个,还要自己去爬楼找到对应的 Driver.exe ,这是有多累,即使你基于这些写了个软件工具,大概率也只能自己玩玩了。

不过 aardio 里所有这些事都可以自动完成,aardio 的标准库里有个 chrome.driver,虽然他叫 chrome.driver,但是兼容非常多的浏览器,也兼容现在越来越普及的 Edge。使用 aardio里的 chrome.driver, 你只需要简单 地写自动化控制网页的代码就可以了,所有环境配置都由 aardio 自动处理,aardio 会自动检测系统的 Chrome, Edge浏览器,如果没有就自动安装合适的浏览器,而且自动下载对应版本的 ChromeDriver.exe, EdgeDriver.exe,这样你编写的软件工具也可以方便地分发给普通用户。

实际上我写的库 chrome.driver 主要的代码都是在处理 ChromeDriver,EdgeDriver 的安装部署与配置,至于 WebDriver 协议其实没有几句代码,aardio 先天就可以将任何基于 Web API 的接口自动导入为 aardio 对象,在这方面 aardio 就省事多了。

来看几句 aardio 调用代码体会一下丝滑与轻松的感觉:

import chrome.driver;
var driver = chrome.driver(); 
var browser = driver.startBrowser();

//打开网页
browser.go("http://www.baidu.com")

//查找文本输入框,返回的DOM对象也可以使用ququerySelector继续查找子节点
var ele = browser.querySelector("body").querySelector("#kw"); 

//在网页输入框输入内容
ele.setValue( "ChromeDriver" )

//调用JS,并且可以返回值(也可以返回DOM节点对象)
var searchButton = browser.doScript(` 
    //可以使用arguments访问aardio传来的参数
    return arguments[0].querySelector("#su");
  `
  ,browser.querySelector("body")//可以传任意个调用参数给JS,还可以直接传DOM节点对象
)

//JS返回的DOM节点对象也可以操作控制
searchButton.click();

有老的 aardio 用户看到这里可能就要说了,我 aardio 都用很久了,这些代码你天天吹了不知道多少遍了。好吧,其实今天这篇文章不是要说上面这些。之所以说这些,是考虑还有不少刚接触 aardio 的新手,对 aardio 的节奏和风格先有一个大致的概念。

前面已经说过了,aardio 的风格一贯都是这样,简单,简单 …… 还要更简单,人生苦短,我们没有那么多时间去下载、配置,看文档。能用程序做的事就用程序自动去做。

今天我要说一个新的东西,叫 SeleniumBasic, 一个 VB 用户向我介绍了这个开源组件,Selenium 大家应该知道了,WebDriver 就是 Selenium 使用的协议。而 SeleniumBasic 是基于 Selenium 的 .Net 版本封装的一个 VB 开源组件,用的人应该也不少。然后 SeleniumBasic v3 的作者 ryueifu 提到SeleniumBasic 需要注册 COM 控件,在很多电脑上存在兼容性问题,出现“无法创建对象”,“自动化错误”,所以进行了改进 ...... 具体的我在范例附上了文章链接大家可以自行了解。

我对这个开源组件的注册坑很感兴趣,aardio 中加载 COM 控件通常可以免注册加载,甚至是自内存加载,这不但是省事,不容易出错,对系统的污染也小,而且不同的程序即使用同一个组件也不会出现版本冲突(尤其是这些开源组件,万一有人修改了接口,却用了同一个 ProgID 注册呢?)

我把 SeleniumBasic 下过来看了一下,发现这是一个 .Net 写的组件,一堆 DLL,然后有一个注册的批处理,其实 .Net 的 DLL 不是那种原生 DLL,某种意义上更像是 aardio 中的库模块(把后缀名改为 dll ), 所以他这个注册控件相比原生 DLL 可能有更多的兼容问题,实际上我们也很少看到用 .Net 写的 COM 组件。

这个 SeleniumBasic 组件既然是 .Net 写的,我们其实也就没必要注册了,因为 .Net 的程序集本来就可以直接调用。我写了几句代码试了一下,可以使用,但是这个 DLL 又依赖 3 个其他的 DLL,这个就不太好了。你说写几句代码就拖 4 个 DLL,就算不用注册了,总是不太完美 。

于是我决定把这 4 个 DLL 合并为一个 DLL文件,我们可以用微软提供的 ILMerge 来做这件事,但是这个工具要码一堆命令行,这个就略有些麻烦了,于是顺手就写了个 aardio 扩展库 dotNet.merge 简化了合并程序集操作,然后又顺手写了个 GUI 工具:

用这个工具成功把 SeleniumBasic 合并为一个DLL,这个 DLL 不支持内存加载,不过没关系,用 aardio 提供的 dotNet.loadAppData() 一句代码解决 —— 支持生成独立 EXE 文件。

虽然我们做了一系列的简化,但还不够简单, SeleniumBasic 还是需要自己写一堆初始化的配置参数,需要你自己下载 Chrome,自己去找对应版本的 ChromeDriver.exe …… 于是我继承 aardio 的优良传统,封装了一个扩展库:dotNet.seleniumBasic ,把前面所有这些事同样全自动化的做了。

然后我高兴地发布了扩展库,正准备上公众号写文章向大家介绍介绍,在写以前,随手试了一下 …… 发现在我刚换的这台笔记本上,居然运行不了,原因是他的 ChromeDriver 不支持 Edge Chromium, 亲!你难道不知道 Edge 是正宗的 Chromium 核吗?!

要知道 chrome.driver 是兼容 Edge的,于是我对 dotNet.seleniumBasic 一通改,加了个懒人包函数 SeleniumBasic.CreateDefaultWebDriver() 自动做好所有的事,并且自动安装、切换、兼容 ChromeDriver 与 EdgeDriver。

好吧,最后我们看一下 aardio 调用 SeleniumBasic 到底有多简单:

import console;
console.showLoading(" 正在启动 SeleniumBasic ");
 
import dotNet.seleniumBasic;
var SeleniumBasic = dotNet.seleniumBasic;

var wd = SeleniumBasic.CreateDefaultWebDriver();
if(!wd) error("初始化或配置环境失败",2) 

//打开网站
wd.Url = "https://www.baidu.com"

//查找表单
var form = wd.FindElementById("form")

//查找输入框
var keyword = form.FindElementById("kw")

//清空输入框,aardio 不能像 VB 那样省略函数调用后的括号
keyword.Clear();

//发送字符串    
keyword.SendKeys("aardio");

//自动点击按钮
var button = form.FindElementById("su");
button.Click();

//重开控制台以前置控制台窗口,然后等待按键    
console.close();
console.pause(,"按任意键退出浏览器");

//退出浏览器
wd.Quit();

是不是很简单?!

这个库发布一段时间以后,已经改进为使用 dotNet.reference 函数完美内存加载 SeleniumBasic 的这几个 DLL 了( 比 ILMerge 简单 ),相关源码如下:

dotNet.reference({
		["WebDriver.Support"] = #34;~\lib\dotNet\seleniumBasic\.res\WebDriver.Support.dll";
		["WebDriver"] = #34;~\lib\dotNet\seleniumBasic\.res\WebDriver.dll";
		["SeleniumBasic"] = #34;~\lib\dotNet\seleniumBasic\.res\SeleniumBasic.dll";
	});

aardio 代码在文件路径前加上 $ 符号 —— 表示将这个文件的二进制数据直接嵌入到程序里(发布后就不再需要这个文件了)。

dotNet.reference 函数用于在 .Net 中虚拟内存程序集, 原来的 .Net 代码一般不需要修改, 除非程序集内有获取程序集类径的代码。例如 SeleniumBasic.IWebDriver 构造函数内的

Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) 

需要改为

System.AppDomain.CurrentDomain.BaseDirectory。

相关推荐

月薪 4K 到 4W 的运维工程师都经历了什么?

运维工程师在前期是一个很苦逼的工作,在这期间可能干着修电脑、掐网线、搬机器的活,显得没地位!时间也很碎片化,各种零碎的琐事围绕着你,很难体现个人价值,渐渐的对行业很迷茫,觉得没什么发展前途。这些枯燥无...

计算机专业必须掌握的脚本开发语言—shell

提起Shell脚本很多都有了解,因为无论是windows的Dom命令行还是Linux的bash都是它的表现形式,但是很多人不知道它还有一门脚本编程语言,就是ShellScript,我们提起的Shel...

Linux/Shell:排名第四的计算机关键技能

除了编程语言之外,要想找一份计算机相关的工作,还需要很多其他方面的技能。最近,来自美国求职公司Indeed的一份报告显示:在全美工作技能需求中,Linux/Shell技能仅次于SQL、Java、P...

使用Flask应用框架在Centos7.8系统上部署机器学习模型

安装centos7.8虚拟环境1、镜像链接...

shell编程

简介:Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。...

14天shell脚本入门学习-第二天#脚本和参数#排版修正

脚本是一种包含一系列命令的文本文件,通常用于自动化任务。Shell脚本是用Shell命令编写的脚本,可以在命令行中执行。掌握脚本的基础知识和变量的使用是编写高效脚本的关键。...

嵌入式Linux开发教程:Linux Shell

本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...

实现SHELL中的列表和字典效果

大家好,我是博哥爱运维。编写代码,很多情况下我们需要有种类型来存储数据,在python中有列表和字典,golang中有切片slice和map,那么在shell中,我们能否实现列表和字典呢,答案是肯定的...

14天shell脚本入门学习-第二天#脚本和变量

脚本是一种包含一系列命令的文本文件,通常用于自动化任务。Shell脚本是用Shell命令编写的脚本,可以在命令行中执行。掌握脚本的基础知识和变量的使用是编写高效脚本的关键。...

shell常用命令之awk用法介绍

一、awk介绍awk的强大之处,在于能生成强大的格式化报告。数据可以来自标准输入,一个或多个文件,或者其他命令的输出。他支持用户自定义函数和动态正则表达式等先进功能,是Linux/unix一个强大的文...

Linux编程Shell之入门——Shell数组拼接与合并

在Shell中,可以使用不同的方式实现数组拼接和合并。数组拼接指将两个数组中的元素合并成一个数组,而数组合并指将两个数组逐个组合成一个新数组。以下是关于Shell数组拼接和合并的详细介绍:数...

shell中如何逆序打印数组的内容,或者反转一个数组?

章节索引图首先请注意,有序的概念仅适用于索引数组,而不适用于关联数组。如果没有稀疏数组,答案会更简单,但是Bash的数组可以是稀疏的(非连续索引)。因此,我们需要引入一个额外的步骤。...

如何学好大数据开发?---shell基本语法

昨天我们初步了解到了shell的一些基本知识,比如shell的分类,常用的shell类型。今天就带来大数据开发之shell基本语法,掌握好基础才是最重要的,那接下来就开始学习shell的基本语法。一、...

Linux编程Shell之入门——Shell关联数组

关联数组是Shell中一种特殊的数组类型,它使用字符串作为下标。在关联数组中,每个元素都被标识为一个唯一的字符串键值,也称为关联数组的索引。在Shell中,可以使用declare或typeset命令...

从编译器视角看数组和指针

虽然有单独的文章描述数组和指针,但二者的关系实在值得再写一篇文章。...

取消回复欢迎 发表评论: