1、Selenium 介绍
Selenium 是一个用于 Web 应用程序自动化测试工具。其本来的开发目的帮助前端程序员,以来完成 web 网站项目的自动化测试。其特点是:能够完全模拟人的行为,打开浏览器,进行搜索,点击,翻页的操作。正是这些特性,在网络爬虫反反爬技术应用广泛,以躲开网站对爬虫的限制。
1.1 怎么实现浏览器控制
Selenium 具体怎么就能操纵浏览器呢?这要归功于 浏览器驱动 ,Selenium 可以通过 API 接口实现和浏览器驱动的交互,进而实现和浏览器的交互。所以要配置浏览器驱动。
首先安装 python 第三方库:
pip install selenium
下载浏览器驱动,以用于 selenium 对浏览器的控制。
对于不同浏览器,对应不同的驱动,最常使用的浏览器是谷歌 Chrome 和火狐 Firefox。
火狐驱动下载地址: http://npm.taobao.org/mirrors/geckodriver/
谷歌驱动下载地址:https://chromedriver.storage.googleapis.com/index.html
注意:下载的驱动应与浏览器的版本一致。
将下载好的浏览器驱动解压,将解压出的
exe
文件放到 Python 的安装目录下,也就是和python.exe
同目录即可。
配置完这一切,就能使用 python 程序控制浏览器啦!
注意:浏览器驱动也可以放置于对应浏览器的安装目录下;还可以放置与 python 程序同级目录下。
2、使用
2.1 初步上手
from selenium import webdriver
driver=webdriver.Chrome()
driver.get('https://baidu.com')
这样运行程序就能启动浏览器工作了(这里我使用的是谷歌浏览器)。
drive.quit() // 关闭驱动
2.2 搜索交互
2.2.1 CSS 选择器
.find_element_by_css_selector()
// 打开网页
browser.get('https://www.jd.com')
// 定位到网页搜索框 id,并清空
key_button=browser.find_element_by_css_selector('#key')
// 输入关键词
key_button.send_keys(' 固态硬盘 ')
// 点击搜索按钮
cilck_button=browser.find_element_by_css_selector('#search button.button').click()
// 注意这里先找到 button 标签下属性为 button 的类名,在往上找到其独一无二的 id'search'。
2.2.2 Xpath 选择器
.find_element_by_xpath()
key_button=browser.find_element_by_xpath('//*[@id="key"]')
key_button.send_keys(' 固态硬盘 ')
cilck_button=browser.find_element_by_xpath('//*[@id="search"]//div/button').click()
2.2.3 其他方式
根据类名定位元素:.find_element_by_id()
根据类名定位元素:.find_element_by_class_name()
根据标签名定位元素:.find_element_by_tag_name()
根据元素名定位元素:.find_element_by_name()
通过文本 链接 来定位元素:.find_element_by_link_text()
通过文字 链接 中的一部分文字定位,属于 模糊定位:.find_element_by_partial_link_text()
browser.find_element_by_link_text(' 把百度设为主页 ').get_attribute('id')
browser.find_element_by_partial_link_text(' 把百度 ').get_attribute('id')
2.3 渲染
在浏览器搜索关键词跳转到新页面之后,需要有一个渲染过程,等页面加载出来。
2.3.1 页面等待
现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过短导致某个 dom 元素还没出来,但是你的代码直接使用了这个 WebElement,那么就会抛出 ElementNotVisibleException 的异常。
为了避免这种元素定位困难而且会提高产生 ElementNotVisibleException 的概率。所以 Selenium 提供了两种等待方式:
- 一种是隐式等待
- 一种是显式等待
隐式等待
隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。隐式等待是等页面加载完毕,而不是元素加载!!!(隐式等待就是针对页面的,显式等待是针对元素的。)
browser.implicitly_wait(10) // 最多等待 10 秒
隐式等待只需设置一次,后面的都遵循这个规则,不像
time.sleep
。time.sleep
属于强制等待。显式等待
显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,还没有满足某个条件,那么便会抛出异常了。显式等待是等元素加载!!!
/// WebDriverWait: WebDriverWait(driver, timeout) 实例化的 driver timeout 等待的时间 until: 直到 xx 条件符合为止 until(条件) 条件: presence_of_element_located: 当前的元素被加载进来了 presence_of_element_located 是一个类 初始化要写定位的元素 一般是元组格式: (By.ID, 'vaule') /// import time # 导入模块 from selenium import webdriver # 导入等待的显式等待的类 from selenium.webdriver.support.ui import WebDriverWait # WebDriverWait(driver) # 导入判断元素的条件 from selenium.webdriver.support import expected_conditions as EC # 导入选择元素的方法 from selenium.webdriver.common.by import By url = 'https://www.receivesmsonline.net/' browser = webdriver.Chrome() browser.get(url) try: startTime = time.time() # 计算时间戳 print(' 开始进入等待时间 ---->>', startTime) wait = WebDriverWait(driver, 5) # 一直去寻找 (By.ID, 'asdhakhkfl') 被加载进来 直到时间耗尽 如果提前找到 就提前返回 element = wait.until(EC.presence_of_element_located((By.ID, 'asdhakhkfl'))) except: endTime = time.time() print(' 等待了多少秒 ---->>', endTime - startTime)
下面是一些内置的等待条件,可以直接调用,而不用自己写这些等待条件:
title_is
: 判断当前页面的 title 是否完全等于(==)预期字符串,返回布尔值title_contains
: 判断当前页面的 title 是否包含预期字符串,返回布尔值
presence_of_element_located
: 判断某个元素是否被加到了dom
树里,并不代表该元素一定可见visibility_of_element_located
: 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于 0
visibility_of
: 跟上面的方法做一样的事情,只是上面的方法要传入locator
,这个方法直接传定位到的 element 就好了presence_of_all_elements_located
: 判断是否至少有 1 个元素存在于dom
树中。举个例子,如果页面上有 n 个元素的 class 都是column-md-3
,那么只要有 1 个元素存在,这个方法就返回 Truetext_to_be_present_in_element
: 判断某个元素中的 text 是否 包含 了预期的字符串text_to_be_present_in_element_value
: 判断某个元素中的 value 属性是否 包含 了预期的字符串frame_to_be_available_and_switch_to_it
: 判断该frame
是否可以switch
进去,如果可以的话,返回True
并且switch
进去,否则返回False
invisibility_of_element_located
: 判断某个元素中是否不存在于dom
树或不可见element_to_be_clickable
: 判断某个元素中是否可见并且是enable
的,这样的话才叫clickable
staleness_of
: 等某个元素从dom
树中移除,注意,这个方法也是返回 True 或 Falseelement_to_be_selected
: 判断某个元素是否被选中了,一般用在下拉列表element_selection_state_to_be
: 判断某个元素的选中状态是否符合预期element_located_selection_state_to_be
: 跟上面的方法作用一样,只是上面的方法传入定位到的element
,而这个方法传入locator
alert_is_present
: 判断页面上是否存在alert
2.3.2 切换窗口
切换 Frame
虽然 selenium 控制浏览器打开了网页,但是有的网页是由多个 Frame 结构组成的,我们需要切换到目标 Frame 里才能提取到想要的网页元素。
browser.switch_to.frame(0) // 切入目标框内
frame 标签有 frameset、frame、iframe 三种,frameset 跟其他普通标签没有区别,不会影响到正常的定位,而 frame 与 iframe 对 selenium 定位而言是一样的,selenium 有一组方法对 frame 进行操作。
从 frame 中切回主文档(switch_to.default_content())
嵌套 frame 的操作(switch_to.parent_frame())
切换浏览器窗口:
browser.switch_to_window(browser.window_handles[-1]) // 切入浏览器窗口
2.3.3 下拉与翻页
有时候网页元素的逐步加载的,首先只加载网页上部分区域,等到拉动网页的下滑条时,才会逐步往下加载可视区域。只有网页元素加载出来,才能进行选取。
执行 JS 代码,实现下拉滑动条:
// 执行 js 代码 下拉滑动条
js = 'window.scrollBy(0,8000)'
// 执行 js
browser.execute_script(js)
///
注意:
对于含有 iframe 的框也需要先切换进入框内才可以下拉。
///
window.scrollBy(x,y)
, 在当前位置的基础上,再次移动 x,y 像素
window.scrollTo(x,y)
,将滚动条移动到 横坐标为 x,纵坐标为 y 的位置
翻页:
time.sleep(5) // 等待 5 秒
// 找到下一页位置进行点击(以京东为例)
browser.find_element_by_css_selector('#J_bottomPage a.pn-next').click()
2.4 页面操作
除了上面已经提到的【点击 & 输入文本动作】,selenium 还提供了其他丰富的操作方式。
2.4.1 选择下拉框
已经知道了怎样向文本框中输入文字,但是有时候会碰到 标签的下拉框。直接点击下拉框中的选项不一定可行。Selenium 专门提供了 Select 类来处理下拉框。 其实 WebDriver 中提供了一个叫 Select 的方法,可以帮助完成这些事情:http://www.jq22.com/demo/shengshiliandong/
///
下拉框:
Select(element) element 是下拉框的元素
选择的方法:
1. select_by_value(value) value=" 天津市 "
2. select_by_index(1) 通过索引 1 2 3 4 5 6
3. select_by_visible_text(text) 通过可见的文本
///
import time
from selenium import webdriver
from selenium.webdriver.support.select import Select
url = 'http://www.jq22.com/demo/shengshiliandong/'
# 初始化浏览器
driver = webdriver.Chrome()
# 打开
driver.get(url)
# 寻找可以选择的元素 并实例化 Select
elememt = driver.find_element_by_xpath('//*[@id="s_province"]')
# 实例化 Select
select = Select(elememt)
time.sleep(2)
# 选择具体的值
select.select_by_index(5)
time.sleep(2)
select.select_by_value(' 河南省 ')
time.sleep(2)
select.select_by_visible_text(' 四川省 ')
# %%
driver.quit()
以上是三种选择下拉框的方式,它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。注意:
- index 索引从 0 开始
- value 是 option 标签的一个属性值,并不是显示在下拉框中的值
- visible_text 是在 option 标签文本的值,是显示在下拉框的值
2.4.2 鼠标动作链
有些时候,需要在页面上模拟一些鼠标操作,比如双击、右击、拖拽甚至按住不动等,可以通过导入 ActionChains 类来做到:http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable 比如:
///
拖动鼠标:
ActionChains:
ActionChains() --> 直接传入 driver --> ActionChains(driver) 实例化
perform --> 执行动作
drag_and_drop(source, target) source 拖动的元素 target 元素被放置的位置
///
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
# 网址
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
# 初始化
driver = webdriver.Chrome()
# 打开网站
driver.get(url)
# 切入框内
driver.switch_to.frame(0)
# 找到可以拖拽的元素
drag = driver.find_element_by_css_selector('#draggable')
# 需要放置的位置的元素
drop = driver.find_element_by_css_selector('#droppable')
# 实例化
action = ActionChains(driver)
# 定义动作 但是不执行 没有执行
action.drag_and_drop(drag, drop)
# 执行
action.perform()
time.sleep(5)
driver.quit()
///
注意:
perform 才是真正的执行 可以在 perform 之前定义多个动作 最后一起执行
注意切入框内 switch_to.frame(0)
///
2.4.3 其他 (了解)
- 弹窗处理
当你触发了某个事件之后,页面出现了弹窗提示,处理这个提示或者获取提示信息方法如下:driver.switch_to_alert()
- 窗口切换
一个浏览器肯定会有很多窗口,所以我们肯定要有方法来实现窗口的切换。切换窗口的方法如下:switch_to.window("this is window name")
- 页面前进和后退
操作页面的前进和后退功能:前进:driver.forward()
后退:driver.back()
- Cookie
获取页面每个 Cookie 值:driver.get_cookies()
欢迎各位看官及技术大佬前来交流指导呀,可以邮件至 jqiange@yeah.net