草蟒中文编程:“自动访问”库(selenium)基本使用

原创
2020/06/16 23:38
阅读数 1.7K

草蟒中文编程:“自动访问”库(selenium)基本使用

参考文章:

1. 简介

  • “自动访问”库 (selenium) 最初是一个自动化测试工具,爬虫中使用它主要是为了解决“网络请求”库 (requests) 无法直接执行 JavaScript 代码的问题。
  • 其本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果。
  • 支持多种浏览器。本次汉化重点是支持谷歌 Chrome 浏览器。对其他浏览器的完整支持待老吴有空再说。
  • 本文未详尽列出涉及到的所有类、方法和属性。欲知详情,请使用草蟒的自动提示和补全功能查看。
  • 本文非原创,而是参考众多网站改编而成。

2. 前提条件

3. 简单使用

从 自动访问 导入 老司机
从 时间 导入 睡眠

# 首先要创建一个开“车”带你到处逛的“司机”对象,这里的“车”就是浏览器
# 如果本库使用频率较高,可以配置环境变量,将驱动程序路径配置到环境变量 Path 中,这样就不必每次都要传入路径参数了
司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe') # 传入驱动程序路径

# 发送 url 请求
司机.获取('https://www.baidu.com')

睡眠(2)
#司机.刷新()

#设置浏览器大小
司机.设置窗口大小(1400, 800)
# 司机.窗口最大化()

# 查看网页标题
司机.标题

# 查看当前网页的 url
司机.当前url

# 根据 id 找到搜索框并输入搜索内容"自动访问"
司机.查找元素_id("kw").发送按键('自动访问')

# 根据 id 找到 "百度一下" 按钮并点击
司机.查找元素_id("su").点击()
睡眠(1)
司机.标题

司机.当前url

# 根据类名找到搜索结果条数信息
司机.查找元素_类名('nums').文本

# 根据 xpath 查找出当前页面的所有搜索结果
元素列表 = 司机.查找所有元素_xpath('//div/h3/a')

# 做一些处理: 打印每个链接的文字内容, 然后找到链接并点击打开
取 元素 于 元素列表[:3]: # 这里仅选取前三条进行演示
    打印(元素.文本)
    司机.查找元素_链接文本(元素.文本).点击()
    睡眠(2)

# 关闭当前窗口
司机.关闭()

# 彻底结束
司机.退出()

4. 元素定位

  • "自动访问"库提供了一系列元素定位方法
  • 这些方法分为两类: '查找元素_xxx' 和 '查找所有元素_xxx', xxx 表示条件
  • 第一类找到的是第一个符合条件的元素, 第二类找到的是所有符合条件的元素
  • 可在编辑器里输入 '司机.查找', 通过弹出的自动补全了解所有定位方法

5. 元素交互

比较常见的用法有:输入文字时用 '发送按键()' 方法,清空文字时用 '清除()' 方法,点击元素时用 '点击()' 方法。传入文件路径的话,'发送按键()' 还能上传文件。

6. 前进和后退

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.获取('https://www.baidu.com')
司机.获取('https://www.taobao.com')
司机.获取('http://www.sina.com.cn/')

司机.后退()
睡眠(2)
司机.前进()

7. 可以获取标签属性

司机.查找元素_css选择器('#SI_Top_Weibo .tn-tab').获取属性('href')

8. 框架切换

在 Web 应用中经常会遇到 frame/iframe 表单嵌套页面的应用,老司机只能在一个页面上对元素识别与定位,对于 frame/iframe 表单内嵌页面上的元素无法直接定位。这时就需要通过 '切换到.框架()' 方法将当前定位的主体切换为 frame/iframe 表单的内嵌页面。

参考:https://www.cnblogs.com/chenshaoping/p/5540434.html (xpath 定位详解)

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.获取('https://www.126.com')

# 司机.切换到.框架(司机.查找所有元素_标签名称("iframe")[0]) 
# 原文直接用'x-URS-iframe', 现已无法定位, 126 网站在后面加上了一串不断变化的数字, 比如 x-URS-iframe1592051452298.8767, 故可用 xpath 模糊匹配方法
xp = 司机.查找元素_xpath('//*[contains(@id, "x-URS-iframe")]')
司机.切换到.框架(xp)
司机.查找元素_名称('email').清除()
司机.查找元素_名称('email').发送按键('username')
司机.查找元素_名称('password').清除()
司机.查找元素_名称('password').发送按键('password')
司机.查找元素_id('dologin').点击()
司机.切换到.默认内容()

9. 三种等待方式

参考:https://www.jianshu.com/p/5edb75d0b687

  • 强制等待: 时间.睡眠()
  • 隐式等待: 在你设置的时间内判断网页是否加载完成,如果完成了,就进行下一步;如果没有加载完成,则会报超时错误. 隐性等待的设置时全局性的,在开头设置过之后,整个的程序运行过程中都会有效,都会等待页面加载完成;不需要每次设置一遍.
  • 显示等待 ('老司机等等我'): 周期性地根据你设定的条件去判断,直到超过你设置的等待时间. 如果设置的条件满足,就进行下一步操作,如果没有满足会报超时错误

10. 窗口句柄

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.隐式等待(10)
司机.获取('https://www.sogou.com')

# 获得搜索窗口句柄
搜索窗口 = 司机.当前窗口句柄

司机.查找元素_链接文本('登录').点击()
司机.查找元素_部分链接文本('注册').点击()

# 获得所有打开窗口的句柄
所有窗口 = 司机.所有窗口句柄

取 窗口 于 所有窗口:
    如果 窗口 != 搜索窗口:
        司机.切换到.窗口(窗口)
        打印('跳转到注册窗口')
        司机.查找元素_id('number_input').发送按键('1234567')
        司机.查找元素_id('message_input').发送按键('1234567')
        睡眠(3)

11. 选择类:处理下拉框

以亚马逊北京控制台登录页面语言选择下拉框为例

从 自动访问.老司机 导入 选择类

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.隐式等待(10)
司机.获取('https://console.amazonaws.cn')

# 找到语言选择下拉框
语言选择 = 司机.查找元素_id('languageSelector')

# 选择类(语言选择).选择_可见文本('English')
# 选择类(语言选择).选择_索引(4)
# 选择类(语言选择).选择_值('ja')
选择类(语言选择).所有选项

12. Cookie 处理

可以方便地对Cookie进行操作,例如获取、添加、删除等。

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.隐式等待(10)
司机.获取('https://weibo.com')
睡眠(3)
司机.获取所有cookie()
司机.获取cookie('SUB')

13. 警示框处理

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.隐式等待(10)
# 下面是我自己写的一个HTML文件, 其中有一个 alert()、一个 confirm() 和 一个 prompt()
司机.获取('file:///E:/test/jstest.html')  

示警 = 司机.切换到.警示框
示警.文本

示警.忽略()

示警2 = 司机.切换到.警示框
示警2.接受()

示警3 = 司机.切换到.警示框
示警3.发送按键('老吴同志') # 在弹出的提示框中输入内容
示警3.接受()

14. 执行 JavaScript

对于某些操作,“自动访问”库并没有提供,但可以模拟运行 JavaScript,使用 '执行脚本()' 方法即可实现.

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.获取('https://www.baidu.com')

司机.查找元素_id('kw').发送按键('李子柒')
司机.查找元素_id('su').点击()
睡眠(3)
js = 'window.scrollTo(100, 450);'
司机.执行脚本(js)

15. 可以自动截图

司机.保存截图('e:/test/bd.jpg')

16. 动作链

有一些操作没有特定的执行对象,比如鼠标拖曳、键盘按键等,这些动作用另一种方式来执行,那就是动作链。

比如,现在实现一个元素的拖曳操作,将其从一处拖曳到另一处,可以这样实现:

从 自动访问.老司机 导入 动作链类

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.隐式等待(10)
司机.获取('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')

司机.切换到.框架('iframeResult')
目标元素 = 司机.查找元素_id('draggable')

动作链 = 动作链类(司机)
动作链.点击并按住(目标元素)

取 i 于 范围(4):
    动作链.偏移(18, 0).完成()
    睡眠(2)

动作链.释放()
动作链.完成()
睡眠(2)
司机.切换到.警示框.接受()

综合实例 1

# 素材图片下载

站长素材url = 'http://sc.chinaz.com/tupian/weimeiyijingtupian.html'
司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.获取(站长素材url)

司机.查找元素_xpath('//*[@id="container"]/div[1]/p/a').点击()

所有句柄 = 司机.所有窗口句柄

司机.切换到.窗口(所有句柄[1])

睡眠(2)

# 点击图片下载
# 按钮 = 司机.查找元素_xpath('/html/body/div[7]/div[5]/div[1]/div[6]/div[2]/div[1]/div/div[3]/a[2]')
# 按钮.点击()

# 通过文本信息定位来下载
司机.查找元素_链接文本('广东电信下载').点击()

司机.退出()

失败案例

药监局反爬虫技术厉害,无法自动访问。

爬取上海药监局数据成功

上海url = 'http://wlxsba.smda.sh.cn/openApi/recordManage'

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.获取(上海url)

# 找到第一页的所有药企
药企列表 = 司机.查找所有元素_xpath('/html/body/div[1]/div[1]/div/div/div[2]/div/div[3]/div[3]/div/table/tbody/tr')

# 打印药企信息
取 企业 于 药企列表:
    打印(企业.文本)

# 当前页码
司机.查找元素_类名('ui-pg-input').获取属性('value')

# 总页数
司机.查找元素_id('sp_1_gp-record').文本

# 自动输入页码, 实现翻页
# 如果写个 '取' 循环, 就能爬取所有页面的数千条数据了

从 自动访问.老司机 导入 按键类 # 回车等特殊按键在这个类中
页码框 = 司机.查找元素_类名('ui-pg-input')
页码框.清除()
页码框.发送按键('10')
页码框.发送按键(按键类.回车)

司机.退出()

自动访问 QQ 空间

从 自动访问 导入 老司机
从 自动访问.老司机 导入 动作链类, 老司机等等我, 期待条件, 方式类

从 时间 导入 睡眠
从 紫檀 导入 紫檀类

司机 = 老司机.谷歌(r'e:/chromedriver/chromedriver.exe')
司机.获取('https://qzone.qq.com/')
司机.窗口最大化()

司机.切换到.框架('login_frame')  # 切换到登录界面
司机.查找元素_id('switcher_plogin').点击()

司机.查找元素_id('u').发送按键('xxxx')  # 填入QQ号
司机.查找元素_id('p').发送按键('xxxx')  # 填入密码
司机.查找元素_id('login_button').点击()

# 等待安全验证界面出现
睡眠(3)
# 切换到安全验证界面
司机.切换到.框架(司机.查找元素_xpath('//iframe'))
# 司机.保存截图('e:/test/安全验证.png')
滑块 = 司机.查找元素_id('slideBlock') # 也可以找 tcaptcha_drag_thumb 这个元素, 即下面的蓝色滑块

# 这里的滑块自动移动算法比较简单, 更复杂的算法参见:
# https://blog.csdn.net/u012067766/article/details/79793264
# https://www.zhihu.com/question/32209043
# https://blog.csdn.net/jingjing_94/article/details/80555511 , 用到图像分割

距离 = 160  # 滑块移动距离初始值, 这里有意设置得偏小
只要 真:
    动作链 = 动作链类(司机)
    动作链.点击并按住(滑块).完成()
    动作链.偏移(距离, 0).完成()
    动作链.重置动作()
    # 司机.保存截图('e:/test/安全验证过程.png')
    # 睡眠(0.5)
    # 动作链.释放().完成()
    睡眠(1)
    试:  # 如果未通过,"安全验证”页面一直会显示“拖动滑块”字样的文字提示
        提示 = 司机.查找元素_类名('tc-title').文本
    捕:
        提示 = ''
    如果 提示:
        打印('需要调整...')
        距离 += 3
        如果 距离 > 190:
            距离 = 160  # 防止滑块越界
        睡眠(2)
    否则: # 通过验证
        # 司机.保存截图('e:/test/安全验证通过.png')
        司机.切换到.父框架()
        跳出

# 等待 QQ 空间页面加载
老司机等等我(司机, 10).直到(期待条件.元素存在((方式类.类名, 'feed_page_container')))

html = 司机.页面源代码
# 打印空间好友发布的一些文字内容
树 = 紫檀类(html, 'html.parser')
条目列表 = 树.选择('.feed_page_container li') 
打印(长(条目列表))  # 显示当前页面有几条内容
取 条目 于 条目列表:
    消息 = 条目.查找(类_='f-info')
    转载 = 条目.查找(类_='txt-box') 
    如果 转载 且 转载.文本 != ' ':
        打印(转载.文本)
        打印()
    或如 消息:
        打印(消息.文本)
        打印()
    否则:
        打印('无\n')

司机.退出()

部分代码截图

本文另有 jupyter notebook 文件,可在草蟒官网下载,方便大家查看实际运行结果。

中文编程是不是有点意思?希望更多人喜欢。

对于英文编程,我现在只想说:Go Foo Your Bar!

展开阅读全文
打赏
2
3 收藏
分享
加载中
更多评论
打赏
0 评论
3 收藏
2
分享
返回顶部
顶部