文章目录
一、什么是Selenium
Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的。Selenium 可以直接调用浏览器,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器),可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏等。既然可以调用浏览器,就可以做到在浏览器中看到是什么样子,抓取的源码也是什么样子,也就是可见即可爬
二、安装环境
2.1、安装Chrome浏览器
2.2、安装Selenium包
pip install selenium -i https://pypi.douban.com/simple
安装完成后,进入Python命令行交互模式,导入Selenium包,如果没有报错,就说明安装成功
Python 3.7.0 (default, Jun 28 2018, 08:04:48) [MSC v.1912 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import selenium
>>>
2.3、安装ChromeDriver
查看Chrome浏览器版本号,右上角–>设置—>关于Chrome
进入ChromeDriver镜像网站,选择合适的版本
配置环境变量
进入终端模式,输入Chromedriver
三、用法
3.1、简单使用
from selenium import webdriver
# 如果driver没有添加到了环境变量,则需要将driver的绝对路径赋值给executable_path参数
# driver = webdriver.Chrome(executable_path='/home/worker/Desktop/driver/chromedriver')
# 如果driver添加了环境变量则不需要设置executable_path
# 1.实例化对象
driver = webdriver.Chrome()
url = 'https://www.baidu.com/'
# 访问网页
driver.get(url)
# 截图功能
driver.save_screenshot("baidu.png")
# 打印页面的标题
print(driver.title)
# 一定要退出!不退出会有残留进程!
# quit会退出整个浏览器,而close只会关闭一个标签
driver.quit()
driver.close()
- 实例化一个driver对象
- 使用世界要关闭
3.2、Selenium提取数据
- 了解 driver对象的常用属性和方法
- 掌握 driver对象定位标签元素获取标签对象的方法
- 掌握 标签对象提取文本和属性值的方法
3.2.1、driver对象的常用属性和方法
在使用selenium过程中,实例化driver对象后,driver对象有一些常用的属性和方法
driver.page_source
当前标签页浏览器渲染之后的网页源代码driver.current_url
当前标签页的urldriver.close()
关闭当前标签页,如果只有一个标签页则关闭整个浏览器driver.quit()
关闭浏览器driver.forward()
页面前进driver.back()
页面后退driver.screen_shot(img_name)
页面截图
3.2.2、driver对象定位标签元素获取标签对象的方法
在selenium中可以通过多种方式来定位标签,返回标签元素对象
find_element_by_id (返回一个元素)
find_element(s)_by_class_name (根据类名获取元素列表)
find_element(s)_by_name (根据标签的name属性值返回包含标签对象元素的列表)
find_element(s)_by_xpath (返回一个包含元素的列表)
find_element(s)_by_link_text (根据连接文本获取元素列表)
find_element(s)_by_partial_link_text (根据链接包含的文本获取元素列表)
find_element(s)_by_tag_name (根据标签名获取元素列表)
find_element(s)_by_css_selector (根据css选择器来获取元素列表)
- 注意:
- find_element和find_elements的区别:
- 多了个s就返回列表,没有s就返回匹配到的第一个标签对象
- find_element匹配不到就抛出异常,find_elements匹配不到就返回空列表
- by_link_text和by_partial_link_tex的区别:全部文本和包含某个文本
- find_element和find_elements的区别:
3.2.3、标签对象提取文本内容和属性值
find_element仅仅能够获取元素,不能够直接获取其中的数据,如果需要获取数据需要使用以下方法
- 对元素执行点击操作
element.click()
- 对定位到的标签对象输入数据
- 对定位到的标签对象输入数据
- 通过定位获取的标签对象的
text
属性,获取文本内容
- 通过定位获取的标签对象的
- 获取属性值
element.get_attribute("属性名")
- 通过定位获取的标签对象的
get_attribute
函数,传入属性名,来获取属性的值
- 通过定位获取的标签对象的
四、查找节点
4.1、单个节点
所有获取单个节点的方法:
find_element_by_id
——根据id
属性定位find_element_by_name
——根据name
属性定位find_element_by_xpath
——根据Xpath
定位- 用id或者name属性来找到一个靠近的元素(比较理想的是父元素),这样再依靠他们的相对关系来确定目标元素的位置。
- 推荐使用Xpath helper插件
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_element(查找方式By,值)
4.2、多个节点定位
所有获取多个节点的方法(下列方法会返回一个list,其余使用方式相同):
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
通用的方法:
find_elements
五、事件等待(Waits)
利用Waits来给页面动作执行提供了时间间隔——比如加载元素,元素定位等
显示Waits
除了time.sleep()
另外一种更好的办法:它指定要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,就返回。否则抛出超时异常
把WebDriverWait
结合ExpectedCondition
# 来自文档的例子
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delay_loading")
try:
element = WebDriverWait(driver,10)
element.until(EC.presence_of_element_located((By.ID,"myDynamicElement"))
)
finally:
driver.quit()
'''
这段代码会等待10秒,如果10秒内找到元素则立即返回,否则会抛出TimeoutException异常,WebDriverWait默认每500毫秒调用一下ExpectedCondition直到它返回成功为止。ExpectedCondition类型是布尔的,成功的返回值就是true,其他类型的ExpectedCondition成功的返回值就是 not null
'''
expected_condition
等待条件
title_is 标题是某内容
title_contains 标题包含某内容
presence_of_element_located 节点加载出来,传入定位元组,如(By.Id,'P')
visibility_of_element_located 节点可见,传入定位元组
visibility_of 可见,传入节点对象
presence_of_all_elements_located 所有节点加载出来
text_to_be_present_in_element 某个节点文本包含某文字
text_to_be_present_in_element_value 某个节点值包含某文字
frame_to_be_available_and_switch_to_it 加载并切换
invisibility_of_element_located 节点不可见
element_to_be_clickable 节点可点击
staleness_of 判断一个节点是否仍在DOM,可判断页面是否已经刷新
element_to_be_selected 节点可选择,传节点对象
element_located_to_be_selected 节点可选择,传入定位元组
element_selection_state_to_be 传入节点对象以及状态,相等返回 True,否则返回 False
element_located_selection_state_to_be 传入定位元组以及状态,相等返回 True,否则返回 False
alert_is_present 是否出现警告
隐式Waits
如果Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常。
也就是说,查找节点而节点没有出现,隐式等待将等待一段时间后再查找DOM,默认的时间是0
from selenium import webdriver
driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id('myDynamicElement')
比较总结:
隐式Waits会让同一个问题根据不同的操作系统,不同的浏览器,不同的Selenium版本上都会不同的表现。而显示Waits可以在我们能想到的任何条件上更加灵活的处理情况,甚至可以忽略某些异常
六、动作链
没有特别的执行对象,比如鼠标拖曳、键盘按键——动作链
参考文档:动作链
#-----------------链式模型---------------------#
menu = driver.find_element_by_css_selector(".nav")
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()
# 找到两个元素
# 构建ActionChains对象——ActionChains(driver)
# 行为方法加入队列——move_to_element(menu).click(hidden_submenu)
# 执行触发——perform()
#-----------------单个按序---------------------#
menu = driver.find_element_by_css_selector(".nav")
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
actions = ActionChains(driver)
actions.move_to_element(menu)
actions.click(hidden_submenu)
action.perform()
-
click(on_element=None)
- 点击一个元素
- 参数: * on_element:要点击的元素,如果是
None
,点击鼠标当前的位置
-
click_and_hold(on_element=None)
- 鼠标左键点击一个元素并且保持
-
double_click(on_element=None)
- 双击一个元素
-
drag_and_drop(source, target)
- 鼠标左键点击
source
元素,然后移动到target
元素释放鼠标按键 - 参数: source:鼠标点击的元素 target:鼠标松开的元素
- 鼠标左键点击
-
drag_and_drop_by_offset(source, xoffset,yoffset)
- 拖拽目标元素到指定的偏移点释放
- 参数: source:点击的参数 xoffset:X偏移量 * yoffset:Y偏移量
-
key_down(value,element=None)
-
只按下键盘,不释放。我们应该只对那些功能键使用(Contril,Alt,Shift)
-
参数: value:要发送的键,值在
Keys
类里有定义 element:发送的目标元素,如果是None
,value会发到当前聚焦的元素上 -
# 按下Ctrl+C ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
-
ADD = u'\ue025' ALT = u'\ue00a' ARROW_DOWN = u'\ue015' ARROW_LEFT = u'\ue012' ARROW_RIGHT = u'\ue014' ARROW_UP = u'\ue013' BACKSPACE = u'\ue003' BACK_SPACE = u'\ue003' CANCEL = u'\ue001' CLEAR = u'\ue005' COMMAND = u'\ue03d' CONTROL = u'\ue009' DECIMAL = u'\ue028' DELETE = u'\ue017' DIVIDE = u'\ue029' DOWN = u'\ue015' END = u'\ue010' ENTER = u'\ue007' EQUALS = u'\ue019' ESCAPE = u'\ue00c' F1 = u'\ue031' F10 = u'\ue03a' F11 = u'\ue03b' F12 = u'\ue03c' F2 = u'\ue032' F3 = u'\ue033' F4 = u'\ue034' F5 = u'\ue035' F6 = u'\ue036' F7 = u'\ue037' F8 = u'\ue038' F9 = u'\ue039' HELP = u'\ue002' HOME = u'\ue011' INSERT = u'\ue016' LEFT = u'\ue012' LEFT_ALT = u'\ue00a' LEFT_CONTROL = u'\ue009' LEFT_SHIFT = u'\ue008' META = u'\ue03d' MULTIPLY = u'\ue024' NULL = u'\ue000' NUMPAD0 = u'\ue01a' NUMPAD1 = u'\ue01b' NUMPAD2 = u'\ue01c' NUMPAD3 = u'\ue01d' NUMPAD4 = u'\ue01e' NUMPAD5 = u'\ue01f' NUMPAD6 = u'\ue020' NUMPAD7 = u'\ue021' NUMPAD8 = u'\ue022' NUMPAD9 = u'\ue023' PAGE_DOWN = u'\ue00f' PAGE_UP = u'\ue00e' PAUSE = u'\ue00b' RETURN = u'\ue006' RIGHT = u'\ue014' SEMICOLON = u'\ue018' SEPARATOR = u'\ue026' SHIFT = u'\ue008' SPACE = u'\ue00d' SUBTRACT = u'\ue027' TAB = u'\ue004' UP = u'\ue013'
-
-
key_up(value,element=None)
-
move_by_offset(xoffset,yoffset)
- 将当前鼠标的位置进行移动
-
move_to_element(to_element)
- 把鼠标移到一个元素的中间
-
move_to_element_with_offset(to_element,xoffset,yoffset)
- 鼠标移动到元素的指定位置,偏移量以元素的左上角为基准
-
perform()
- 执行所有存储的动作
-
release(on_element=None)
- 释放一个元素上的鼠标按键,
- 参数: * on_element:如果为
None
,在当前鼠标位置上释放
-
send_keys(*keys_to_send)
- 向当前的焦点元素发送键
-
send_keys_to_element(element,*keys_to_send)
- 向指定的元素发送键
七、执行JavaScript
有一些操作,Selenium API并没有提供。比如下拉进度条,但是我们可以通过模拟JavaScript来达到效果
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
broser.execute_script('alert("To Bottom")')
# 拉到底部后,然后弹出alert警告框
八、警告框
class selenium.webdriver.common.alert.Alert(driver)
-
accept()
- 确认提示框
-
authenticate(username,password)
-
向一个认证的对话框发送用户名和密码,会自动点击确认
-
参数: username:username区域要填写的字符串 password:password区域要填写的字符串
-
driver.switch_to.alert.authenticate('cheese','secretGouda')
-
-
dismiss()
- 忽略提示框
-
send_keys(KeysToSend)
- 向对话框输入字符
-
text
- 提示框的文本
接受和忽略弹框:
Alert(driver).accept()
Alert(driver).dismiss()
prompt里输入字符:
name_prompt = Alert(driver)
name_prompt.send_keys("Willian Shakephere")
name_prompt.accept()
读取prompt的提示字符:
alert_text = Alert(driver).text
self.assertEqual("Do you wish to quit?",alert_text)
九、获取节点信息
classselenium.webdriver.remote.webelement.WebElement(parent,id_,w3c=False)
代表一个DOM元素,检测不到元素是是否DOM相连时,会抛出
StaleEleementReferenceException
异常
-
获取属性:get_attribute(name)
- 返回元素指定的属性
- 如果属性不存在,它会返回和属性名相同的字符串,如果没有属性是这个名字,返回
None
- 被认为是真假的值会返回布尔类型,其他所有的非
None
值都会以字符串的形式返回。属性不存在,返回None
-
获取文本值:text
- Beautiful Soup的 get_text() 方法
- pyquery的 text()方法
-
获得id、位置、标签名和大小
-
id——可以用来
==
做比较-
if element1 == element2: print("These 2 are equal")
-
-
location - 元素在可渲染的画布上的位置
-
location_once_scrolled_into_view
- 用这个来检查元素在屏幕的位置以方便我们点击它,这个方法可能造成元素滚动到视图里。 返回屏幕左上角的位置,元素不可见返回
None
- 用这个来检查元素在屏幕的位置以方便我们点击它,这个方法可能造成元素滚动到视图里。 返回屏幕左上角的位置,元素不可见返回
-
size - 元素的尺寸
-
tag_name - 元素的标签名
-
-
其他
-
is_displayed() - 元素对用户是否可见
-
is_enabled() - 元素是否可用
-
is_selected() - 元素是否被选中,可用来检测单选或者复选按钮是否被选中
-
screenshot(filename) - 获取当前元素的截图,有IOError会返回
False
,文件名要包含完整路径 -
send_keys(*value) - 模拟向元素输入
-
form_textfiled = driver.find_element_by_name("username") form_textfiled.send_keys("admin")
-
file_input = driver.find_element_by_name('profilePic') file_input.send_keys('path/to/profilepic.gif')
-
-
submit() - 提交表单
-
value_of_css_property(property_name) - CSS属性的值
-
parent - WebDriver实例的内部引用,元素是从哪里发现的
-
rect - 元素尺寸和位置的dict
-
screenshot_as_base64 - 当前元素截图的base64编码字符串
-
screenshot_as_png - 当前元素截图的二进制数据
-
十、切换Frame
网页有一种节点叫 iframe,也就是子 Frame。
当 Selenium打开页面后,默认是在父级里面操作,是不能获取子 Frame里面的节点
- switch_to_frame(frame_reference)方法来切换Frame
十一、前进和后退
class selenium.webdriver.remote.webdriver.WebDriver(command_executor=‘http://127.0.0.1:4444/wd/hub’, desired_capabilities=None, browser_profile=None, proxy=None, keep_alive=False)
浏览器有前进和后退功能,Selenium完成这个操作的方法是
- back()
- forward()
十二、Cookies
- delete_all_cookies() - 删除当前会话的所有cookie
- delete_cookie(name) - 删除一个指定的cookie
- get_cookie(name) - 返回一个指定的cookie,不存在返回
None
- get_cookies() - 返回一组dict,相当于当前会话的可用cookie
十三、选项卡管理
- browser.execute_script(‘window.open()’)——开启选项卡
- window_handles - 返回当前会话内所有窗口的资源句柄
- switch_to_window(window_name) —切换选项卡
十四、异常处理
参考资料:
FAQ: