selenium
selenium 是一个支持各大浏览器的自动化测试工具, 包括 Chrome,Safari,Firefox ,IE 等. 再构造爬虫时, 如果我们加入了 User-Agent, 那么变伪装成了浏览器, 可以骗过一些技术水平不太高的网站. 但如果使用 selenium, 则就不是伪装浏览器, 而是真正的用浏览器去访问. 有时我们可能会遇到这种情况, 前端页面展示出来的东西, 并不在后端源代码中, 自然无法通过使用 requests 请求获得源码进行爬取. 这时候就可以使用 selenium 进行爬取数据, 因为他就是用真实的浏览器去访问页面的, 所以出现的内容和我们在前端看到的是一模一样的.
0x01:selenium 安装
python 下使用 pip 安装
pip install selenium
此外, 因为 selenium 是配合浏览器一起使用, 所以需要下载浏览器的驱动 (webdriver), 以 Chrome 为例
Chrome 的 webdriver: http://chromedriver.storage.googleapis.com/index.html
不同的 Chrome 的版本对应的 chromedriver.exe 版本也不一样, 下载时不要搞错了. 如果是最新的 Chrome, 下载最新的 chromedriver.exe 就可以了. 把 chromedriver 的路径也加到环境变量里.
检测: 运行这段代码, 会自动打开百度
- from selenium import webdriver # 引入 webdriver API
- browser = webdriver.Chrome() # 使用 Chrome 浏览器声明一个 webdriver 对象
- browser.get('http://www.baidu.com/') # 表示使用 Chrome 以 get 的方式请求百度的 url
- driver.find_element_by_id("kw").send_keys("selenium") # 检索到百度的输入框, 输入 selenium
- driver.find_element_by_id("su").click() # 检索到百度的搜索按钮并点击
0x02: 元素选取
在上面的实例中, 最重要的就是找到搜索框和搜索按钮对应的元素, 然后再进行相应的操作 (输入关键字, 点击), 强大的 selenium 提供了多种提取元素的方法.
单个元素提取
- find_element_by_id # 通过元素 id
- find_element_by_name # 通过 name 属性
- find_element_by_xpath # 通过 xpath
- find_element_by_link_text # 通过链接文本
- find_element_by_partial_link_text
- find_element_by_tag_name # 通过标签名
- find_element_by_class_name # 通过 class 名称定位
- find_element_by_CSS_selector # 通过 CSS 选择器定位
多个元素提取, 返回一个列表
- find_elements_by_name
- find_elements_by_xpath
- find_elements_by_link_text
- find_elements_by_partial_link_text
- find_elements_by_tag_name
- find_elements_by_class_name
- find_elements_by_css_selector
0x03: 操作元素方法
clear 清除元素的内容: clear(self)
send_keys 模拟按键输入: send_keys(self, *value)
click 点击元素: click(self)
submit 提交表单: submit(self)
获取元素属性: get_attribute(self, name)
获取元素文本: text
0x04: 页面操作方法
from selenium import webdriver
打开浏览器: driver = webdriver.Chrome()
请求一个 url:driver.get("www.baidu.com")
返回当前页面的 title:title = driver.title
返回当前页面的 url:url = driver.current_url
返回当前页面的源码: source = driver.page_source
关闭当前页面: driver.close()
注销并关闭浏览器: driver.quit()
浏览器前进: driver.forward()
浏览器后退: driver.back()
刷新当前页面: driver.refresh()
获取当前 session 中的全部 cookie:get_cookies(self)
获取当前会中中的指定 cookie:get_cookie(self, name)
在当前会话中添加 cookie:add_cookie(self, cookie_dict)
添加浏览器 User-Agent:
options.add_argument('User-Agent=Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30')
添加设置项 Chrome Options:
- options = webdriver.ChromeOptions()
- options.add_argument('xxxx')
- driver = webdriver.Chrome(chrome_options=options)
0x05: 页面等待
既然 selenium 是使用浏览器发送请求, 那么势必会加载一些东西, 而且现在的网页越来越多采用了 Ajax 技术. 如果代码运行到了提取元素的地方, 而这个元素尚未被加载, 那么就会报错. 为了解决这个问题, selenium 提供了两种等待方式, 隐式等待, 显示等待. 隐式等待是等待特定的时间, 显式等待是指定某一条件直到这个条件成立时继续执行.
隐式等待
隐式等待比较简单, 就是简单地设置一个等待时间, 单位为秒.
- from selenium import webdriver
- driver = webdriver.Chrome()
- driver.implicitly_wait(10) # seconds
- driver.get("http://somedomain/url_that_delays_loading")
- myDynamicElement = driver.find_element_by_id("myDynamicElement")
显式等待
显式等待指定某个条件, 然后设置最长等待时间. 如果在这个时间还没有找到元素, 那么便会抛出异常了.
- from selenium import webdriver
- from selenium.webdriver.support.ui import WebDriverWait
- driver = webdriver.Chrome()
- driver.get("http://somedomain/url_that_delays_loading")
- try:
- element = WebDriverWait(driver, 10).until(
- EC.presence_of_element_located((By.ID, "myDynamicElement"))
- )
- finally:
- driver.quit()
wait 模块的 WebDriverWait 类是显性等待类, 参数如下:
WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时时返回的信息)
这里需要特别注意的是 until 或 until_not 中的可执行方法 method 参数, 很多人传入了 WebElement 对象, 如下:
WebDriverWait(driver, 10).until(driver.find_element_by_id('kw')) # 错误
这是错误的用法, 这里的参数一定要是可以调用的, 即这个对象一定有 call() 方法, 否则会抛出异常:
TypeError: 'xxx' object is not callable
在这里, 你可以用 selenium 提供的 expected_conditions 模块中的各种条件, 也可以用 WebElement 的 is_displayed() ,is_enabled(),is_selected() 方法, 或者用自己封装的方法都可以. 那么接下来我们看一下 selenium 提供的条件有哪些:
expected_conditions:
xpected_conditions 是 selenium 的一个模块, 其中包含一系列可用于判断的条件:
selenium.webdriver.support.expected_conditions(模块)
这两个条件类验证 title, 验证传入的参数 title 是否等于或包含于 driver.title
- title_is
- title_contains
这两个人条件验证元素是否出现, 传入的参数都是元组类型的 locator, 如 (By.ID, 'kw')
顾名思义, 一个只要一个符合条件的元素加载出来就通过; 另一个必须所有符合条件的元素都加载出来才行
- presence_of_element_located
- presence_of_all_elements_located
这三个条件验证元素是否可见, 前两个传入参数是元组类型的 locator, 第三个传入 WebElement
第一个和第三个其实质是一样的
- visibility_of_element_located
- invisibility_of_element_located
- visibility_of
这两个人条件判断某段文本是否出现在某元素中, 一个判断元素的 text, 一个判断元素的 value
- text_to_be_present_in_element
- text_to_be_present_in_element_value
这个条件判断 frame 是否可切入, 可传入 locator 元组或者直接传入定位方式: id,name,index 或 WebElement
frame_to_be_available_and_switch_to_it
这个条件判断是否有 alert 出现
alert_is_present
这个条件判断元素是否可点击, 传入 locator
element_to_be_clickable
这四个条件判断元素是否被选中, 第一个条件传入 WebElement 对象, 第二个传入 locator 元组
第三个传入 WebElement 对象以及状态, 相等返回 True, 否则返回 False
第四个传入 locator 以及状态, 相等返回 True, 否则返回 False
- element_to_be_selected
- element_located_to_be_selected
- element_selection_state_to_be
- element_located_selection_state_to_be
最后一个条件判断一个元素是否仍在 DOM 中, 传入 WebElement 对象, 可以判断页面是否刷新了
staleness_of
上面是所有 17 个 condition, 与 until,until_not 组合能够实现很多判断, 如果能自己灵活封装, 将会大大提高脚本的稳定性.
0x06: 鼠标操作
在现实的自动化测试中关于鼠标的操作不仅仅是 click() 单击操作, 还有很多包含在 ActionChains 类中的操作. 如下:
context_click(elem) 右击鼠标点击元素 elem, 另存为等行为
double_click(elem) 双击鼠标点击元素 elem, 地图 Web 可实现放大功能
drag_and_drop(source,target) 拖动鼠标, 源元素按下左键移动至目标元素释放
move_to_element(elem) 鼠标移动到一个元素上
click_and_hold(elem) 按下鼠标左键在一个元素上
perform() 在通过调用该函数执行 ActionChains 中存储行为
举例如下图所示, 获取通过鼠标右键另存为百度图片 logo. 代码:
- import time
- from selenium import webdriver
- from selenium.webdriver.common.keys import Keys
- from selenium.webdriver.common.action_chains import ActionChains
- driver = webdriver.Firefox()
- driver.get("http://www.baidu.com")
- # 鼠标移动至图片上 右键保存图片
- elem_pic = driver.find_element_by_xpath("//div[@id='lg']/img")
- print elem_pic.get_attribute("src")
- action = ActionChains(driver).move_to_element(elem_pic)
- action.context_click(elem_pic)
- # 重点: 当右键鼠标点击键盘光标向下则移动至右键菜单第一个选项
- action.send_keys(Keys.ARROW_DOWN)
- time.sleep(3)
- action.send_keys('v') #另存为
- action.perform()
- # 获取另存为对话框 (失败)
- alert.switch_to_alert()
- alert.accept()
0x07: 键盘操作
在 webdriver 的 Keys 类中提供了键盘所有的按键操作, 当然也包括一些常见的组合键操作如 Ctrl+A(全选),Ctrl+C(复制),Ctrl+V(粘贴).
send_keys(Keys.ENTER) 按下回车键
send_keys(Keys.TAB) 按下 Tab 制表键
send_keys(Keys.SPACE) 按下空格键 space
send_keys(Kyes.ESCAPE) 按下回退键 Esc
send_keys(Keys.BACK_SPACE) 按下删除键 BackSpace
send_keys(Keys.SHIFT) 按下 shift 键
send_keys(Keys.CONTROL) 按下 Ctrl 键
send_keys(Keys.ARROW_DOWN) 按下鼠标光标向下按键
send_keys(Keys.CONTROL,'a') 组合键全选 Ctrl+A
send_keys(Keys.CONTROL,'c') 组合键复制 Ctrl+C
send_keys(Keys.CONTROL,'x') 组合键剪切 Ctrl+X
send_keys(Keys.CONTROL,'v') 组合键粘贴 Ctrl+V
这里使用的例子参考虫师的书籍《selenium2 python 自动化测试》
- import time
- from selenium import webdriver
- from selenium.webdriver.common.keys import Keys
- driver = webdriver.Firefox()
- driver.get("http://www.baidu.com")
- # 输入框输入内容
- elem = driver.find_element_by_id("kw")
- elem.send_keys("Eastmount CSDN")
- time.sleep(3)
- # 删除一个字符 CSDN 回退键
- elem.send_keys(Keys.BACK_SPACE)
- elem.send_keys(Keys.BACK_SPACE)
- elem.send_keys(Keys.BACK_SPACE)
- elem.send_keys(Keys.BACK_SPACE)
- time.sleep(3)
- # 输入空格 +"博客"
- elem.send_keys(Keys.SPACE)
- elem.send_keys(u"博客")
- time.sleep(3)
- #ctrl+a 全选输入框内容
- elem.send_keys(Keys.CONTROL,'a')
- time.sleep(3)
- #ctrl+x 剪切输入框内容
- elem.send_keys(Keys.CONTROL,'x')
- time.sleep(3)
- # 输入框重新输入搜索
- elem.send_keys(Keys.CONTROL,'v')
- time.sleep(3)
- # 通过回车键替代点击操作
- driver.find_element_by_id("su").send_keys(Keys.ENTER)
- time.sleep(3)
- driver.quit()
参考文章:
https://cuiqingcai.com/2599.html
来源: https://www.cnblogs.com/liangxiyang/p/11587233.html