ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: 源理

[原创] vba中使用Selenium

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-22 14:09 | 显示全部楼层
aman1516 发表于 2018-12-22 12:34
关于定位元素的都讲完了。这里很重要!!!!!!!!!!!!是操作网络对象的基础!!!

——掌握了这点,才算是开 ...

获取了网页元素就获得了,网页上大多数的能操作的内容。url也就是他的一个属性,图片视频文档也就是他的下载按钮用了一下click事件。不过这样还得交互一下才能存,如果是批量下载一些图片,还是直接 用xhr异步请求来获得。
selenium适合网页上的操作!!!

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-23 20:46 | 显示全部楼层
8、Cookie
由于网页是无状态的,为了保证服务器知道网页端的状态,就整出了很多东东其中就有cookie。这样服务器就知道你是访问的网页是不是通过了登录。我们多半是为了网页抓取信息或是填写表单。现在我们的思路是:登录后把这个cookie存起来,然后在后续的自动化工作中直接填写这个cookie就能实现自动化了。
Cookie也是键值对存在的名称、值。在selenium中获得cookie是通过Manage。
07-03.png
示例15
获得打开excelhome网页,并把获得网页中会话的cookie,打印到立即窗口输出
效果

07-01

07-01
代码
  1. Sub 示例15()
  2.     Dim cd As New ChromeDriver
  3.     cd.Get "http://www.excelhome.net/"
  4.     Dim cookie As cookie
  5.     For Each cookie In cd.Manage.Cookies
  6.         Debug.Print "name:" & cookie.Name
  7.         Debug.Print "Path:" & cookie.Path
  8.         Debug.Print "Secure:" & cookie.Secure
  9.         Debug.Print "Expiry:" & cookie.Expiry
  10.         Debug.Print "Value:" & cookie.Value
  11.         Debug.Print "Domain:" & cookie.Domain
  12.         Debug.Print "================="
  13.     Next
  14.     Stop
  15.     cd.Quit
  16.     Set cd = Nothing
  17. End Sub
复制代码
Cookie是存在于manage对象中的,此对象除了有获得cookie还有增加cookie的方法AddCookie
语法
instance.AddCookie(name, value, domain, path, expiry, secure,httpOnly)
除secure、httpOnly是布尔类型外,其它都是字符串。具体的意义请百度。
Name,value为必填项,其它为选填项。
示例16
先通过网站登录,记录下登录状态的cookie。然后再运行另一个新的网页,添加cookie,并刷新本页看用户是否登录。
效果:

07-02

07-02
  1. Dim Cookies As Collection
  2. Sub 示例16()
  3.     Dim cd As New ChromeDriver
  4.     Set Cookies = New Collection
  5.     cd.Get "http://www.8888888.com/gskuc"
  6.     Stop '这里进行一下登录操作
  7.     Dim cookie As cookie
  8.     For Each cookie In cd.Manage.Cookies
  9.         If Not hasCookie(cookie.name, Cookies) Then
  10.             Cookies.Add cookie, cookie.name
  11.         End If
  12.     Next
  13.     Stop
  14.     cd.Quit
  15.     Set cd = Nothing
  16. End Sub

  17. Sub 示例16_1()
  18.     Dim cd As New ChromeDriver
  19.     cd.Get "http://www.8888888.com/gskuc"
  20.     Dim cookie As cookie
  21.     '通过上次存的cookie存入本次打开的网页中,这样就能不用再次登录就能记录了
  22.     cd.Manage.DeleteAllCookies
  23.     For Each cookie In Cookies
  24.         cd.Manage.AddCookie cookie.name, cookie.Value
  25.     Next
  26.     cd.Get "http://www.8888888.com/gskuc"
  27.     Stop
  28. End Sub

  29. Function hasCookie(name, Cookies As Collection)
  30.     hasCookie = False
  31.     For Each cookie In Cookies
  32.         If cookie.name = name Then hasCookie = True
  33.     Next
  34. End Function
复制代码
只是技术分享, 不想涉及具体网站,网址就不给了。

小结:cookie能直接绕过很多网站的登录,当然不是全部,另一些还涉及别的知识。

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-27 19:46 | 显示全部楼层
本帖最后由 源理 于 2018-12-27 22:30 编辑

9处理等待
关于等待是一个难点,我也不知道如何下手写。想了很久,但我发现想得太多,不如先记下来我所了解的,以后再补充。
等待是不可避免的,因为网页中的js代码会从后台无刷新带来数据,然后再根据数据添加一些元素在网页上或是删除一些网页元素,这个就是Ajax,这个东西应用太多了。现在我们的遇到的网页基本上都是这种交互。
那么问题来了,一个网页程序在对一个元素进行创建或是删除,我们VBA主线程怎么知道浏览器怎么处理好这个元素。这个网页元素消失了完了吗?这个网页元素创建完了,我们能用了吗?(如果没有创建完,我们不能用就会报错,这个太讨厌了,大大降低了我们的信心)。
为了解决以上问题所以这个我研究了很久,也很肤浅,写出我查资料得出的几个方法。
  • 用Wait方法
  • 用webelement中wait的方法
Wait
说明:主程序等待指定的时间(毫秒)。这个我喜欢用,因为不用考虑太多,直接有效。但很明显,每次网络异步加载的数据时间是不一样的,我这样会取一个最大的值,这样会浪费很多时间。当然有时我们不在意这些时间,我们可以等待。
语法
instance.Wait(timems)
instance:驱动,如chormDriv
timems:毫秒、等待的时间
示例,抓取https://www.epubit.com/book/screen网页1-9页的售出数据
下面为不用Waiter的报错

01

01
加了wait后的代码效果

02

02
代码中加了一个等待1s
Webelement的等待方法

WaitAttribute :等待元素的指定属性变为指定值
WaitNotAttribute:等待元素的指定的属性不等于指定的值

returnValue = instance.WaitAttribute(attribute, pattern,timeout)
returnValue = instance.WaitNotAttribute(attribute,pattern, timeout)
其中attribute为属性名,pattern预期的值,timeout超时时间


WaitCssValue:等待元素指定的Css属性变为指定值
WaitNotCssValue: 等待元素指定的Css属性不等于指定值
returnValue = instance.WaitCssValue(propertyName, value,timeout)
returnValue = instance.WaitNotCssValue(propertyName,  value, timeout)
其中propertyName为css属性名,value为属性值,,timeout超时时间


WaitDisplayed:等待元素的可见性
returnValue = instance.WaitDisplayed(displayed, timeout)
其中displayed为布尔类型是否可见


WaitEnabled:等待元素可用
returnValue = instance.WaitEnabled(enabled, timeout)
其中enabled为布尔类型是否可用


WaitNotElement:等待元素消失
instance.WaitNotElement(by, timeout)
其中by 是by机制查找元素


WaitRemoval:等待元素从dom中被移除 【我测试出来这个不管用】
instance.WaitRemoval(timeout)
等待元素出现其实就是FindElement开头一类的方法,只是注意一下最后一个raise参数,当为false时为不引发异常,给一个空值。可以利用这点来帮我们判断一个元素是否出现。第二个参数time默认是3秒,等3秒如果没有找到看第三个参数是否引发异常,如果这个响应时间长可以设置长一点。这样就能智能的判断不像wait是一个定值。


WaitNotText:等待元素的值不是指定的值
WaitText:等待元素的值是指定的值
returnValue = instance.WaitNotText(pattern, timeout)
returnValue = instance.WaitText(pattern, timeout)
其中pattern指定的值(可匹配正则)



WaitSelection:等待元素指定的选中状态,可选的元素且原生如下拉列表,单元框,复选框元素。
returnValue = instance.WaitSelection(selected, timeout)
其中selected是否被选中布尔型,


这里我就做几个例子,其它的大同小意,当然这里很重要,自己去一个一个试吧。
  1. .FindElementByXPath("//div[@class='ivu-page-options-elevator']/input").WaitAttribute "value", "3", 60000
复制代码

03

03
  1. cd.FindElementByXPath("//ul[@class='ivu-page']").WaitNotElement by.XPath("//li[@title=2]"), 30000
复制代码

04

04
  1. cd.FindElementById("screenList").WaitText "下载版", 60000
复制代码

05

05
在实际案例中,需要分析出网站是那个元素是加载完后,你所要的数据就加载出来了。有的还要分析点击事件是否被js(得看网页原代码)响应完成,响应完成后那才能抓取,还得用到我没讲的waiter,这是一个回调的应用。我给出作者的代码,这块我也没有研究明白。
  1. Private Assert As New Selenium.Assert
  2. Private Waiter As New Selenium.Waiter


  3. Private Sub Should_Wait_For_Delegate()
  4.   Dim driver As New FirefoxDriver

  5.   ' without delegate
  6.   While Waiter.Not(WaitDelegate1(), timeout:=2000): Wend
  7.   
  8.   ' without delegate with argument
  9.   While Waiter.Not(WaitDelegate2(driver), timeout:=2000): Wend

  10.   ' with delegate on the driver
  11.   driver.Until AddressOf WaitDelegate1, timeout:=2000
  12.   
  13.   ' with delegate with argument
  14.   Waiter.Until AddressOf WaitDelegate1, driver, timeout:=2000
  15.   
  16.   ' with delegate without argument
  17.   Waiter.Until AddressOf WaitDelegate2, timeout:=2000
  18. End Sub


  19. Private Function WaitDelegate1()
  20.   WaitDelegate1 = True
  21. End Function


  22. Private Function WaitDelegate2(driver As WebDriver)
  23.   WaitDelegate2 = True
  24. End Function
复制代码
小结:如果是想要重复的操作特别是异步的网页,这个必须要掌握,不然就是一个半自动化办工。异步需要对网页的响应进行全面的分析,花费时间长,不过一切都是值得的。我用这个解决了一无聊系统的无聊工作,大大减少了我的工作时间。这是爽点啊!!

10 js
Selennium可以直接 在网页中响应js,包括网页引用的jquery,easyui什么什么的,可以打开网页原码自己爽。
这里就以最后一个有趣的例子结束这个帖子

通过js给自己改了一个徽章,当然只是页面上显示多了,实际没有什么用。不过很好玩是不是!

06

06
  1. Sub 示例19()
  2.     Dim cd As New ChromeDriver
  3.     cd.Get "http://club.excelhome.net/thread-1452021-1-1.html"
  4.     Stop '请登录
  5.     '通过script获得一个新徽章
  6.     jsStr = "document.getElementById('g_up9762161').firstChild.setAttribute('src','static/image/common/medal20.gif');"
  7.     jsStr = jsStr & "alert('恭喜你获得了新徽章')"
  8.     cd.ExecuteScript jsStr
  9.     Stop
  10. End Sub
复制代码
结语:写了一个星期占用了很多业余时间,感觉也在写的过程中有所得。希望对大家有用吧!


TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-27 19:50 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
差点忘记了!
下面把所有示例的代码放到这里!
帖子示例.rar (69.7 KB, 下载次数: 518)

TA的精华主题

TA的得分主题

发表于 2018-12-27 21:08 | 显示全部楼层
强力点赞,之前只在python中用过,需要的时候才查资料,楼主总结的很丰富,收藏了。

TA的精华主题

TA的得分主题

发表于 2018-12-28 11:04 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
樓主,請問這段怎麼定位?
用class怎樣也定不了


未命名.jpg

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-28 11:19 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
chis3 发表于 2018-12-28 11:04
樓主,請問這段怎麼定位?
用class怎樣也定不了

class如果是唯 一的你就能精准 定位到那个,如果不是唯一的,你看他第几个
用数组定位是那个就行了

TA的精华主题

TA的得分主题

发表于 2018-12-28 11:24 | 显示全部楼层
源理 发表于 2018-12-28 11:19
class如果是唯 一的你就能精准 定位到那个,如果不是唯一的,你看他第几个
用数组定位是那个就行了

像這個,應該怎麼寫?
而且有些class 有空格的 原來空格後的不用寫入去的

TA的精华主题

TA的得分主题

发表于 2018-12-28 13:37 | 显示全部楼层
chis3 发表于 2018-12-28 11:24
像這個,應該怎麼寫?
而且有些class 有空格的 原來空格後的不用寫入去的

classname有空格是复合名,你只需要以空格为分隔符用其中一个就可以了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-28 15:15 | 显示全部楼层
chis3 发表于 2018-12-28 11:24
像這個,應該怎麼寫?
而且有些class 有空格的 原來空格後的不用寫入去的

发连接,和你要抓的元素,我给你做一个示例
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-24 22:08 , Processed in 0.052368 second(s), 8 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表