前言
以下关于Selenium的内容讲解,强烈推荐深入了解的查看官方文档。
英文版:Selenium、 https://selenium-python.readthedocs.io/
Selenium介绍安装
- 介绍
selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并行处理(Selenium Grid)。Selenium的核心Selenium Core基于JsUnit,完全由JavaScript编写,因此可以用于任何支持JavaScript的浏览器上。
selenium可以模拟真实浏览器,自动化测试工具,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。 - 安装使用 selenium
virtualenv 来创建隔离的Python环境。
pip install selenium - 选择下载浏览器驱动
下载以下driver后,放到Python虚拟环境的 Scripts 文件夹下。
- PhantomJS
PhantomJS是一个而基于WebKit的服务端JavaScript API,支持Web而不需要浏览器支持,其快速、原生支持各种Web标准:Dom处理,CSS选择器,JSON等等。PhantomJS可以用用于页面自动化、网络监测、网页截屏,以及无界面测试。速度比Selenium快很多,最后进行讲解。
Selenium 的基本使用
- 声明浏览器对象、访问页面
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("http://www.baidu.com")
print(browser.page_source)
browser.close()
- 查找单元素
- 获取方式
以下通过三种不同的方式去获取响应的元素,第一种是通过id的方式,第二个中是CSS选择器,第三种是xpath选择器,结果都是相同的。
- 获取方式
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("http://www.taobao.com")
input_first = browser.find_element_by_id("q")
input_second = browser.find_element_by_css_selector("#q")
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first)
print(input_second)
print(input_third)
browser.close()
CSS选择器、xpath选择器 可以直接采用chrome浏览器的右击复制,如下图:
- 查找元素方法
- find_element_by_name
- find_element_by_id
- find_element_by_xpath
- find_element_by_link_text
- find_element_by_partial_link_text
- find_element_by_tag_name
- find_element_by_class_name
- find_element_by_css_selector
以上方法也可以通过By.NAME等进行获取。如以下代码
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("http://www.taobao.com")
# 匹配的元素的ID
# input_first_By_ID = browser.find_element_by_id('q')
# 以下类似,都有两种方式。
input_first_By_ID = browser.find_element(By.ID, "q")
# 匹配的元素的xpath定位器
input_first_By_XPATH = browser.find_element(By.XPATH, "//*[@id=\"q\"]")
# 匹配的元素的name属性
input_first_By_NAME = browser.find_element(By.NAME, "q")
# 匹配的元素的文本
input_first_LINK_TEXT = browser.find_element(By.LINK_TEXT, "领淘金币抵钱")
# 匹配的元素的标签名称,例如:h1,a,span
input_first_CSS_SELECTOR = browser.find_element(By.CSS_SELECTOR, "#q")
print(input_first_CSS_SELECTOR)
browser.close()
"""
<selenium.webdriver.remote.webelement.WebElement (session="4ee277c466be7248d4c7e078cbf927db", element="0.09114132600392044-1")>
"""
-
多元素查找
与以上类似,只不过在以上的方法 find_element_by_css_selector -> find_elements_by_css_selector ,加一个s。并且在输出的时候是以list的形式返回,例如以上的输出修改为:
[<selenium.webdriver.remote.webelement.WebElement (session=“cdbd8f4c90c313c9e94519414365f552”, element=“0.40080093360381364-1”)>]
疑问查看:WebDriver API https://selenium-python.readthedocs.io/api.html
- 交互动作
以下代码完成在菜鸟教程 http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable 的拖拽。
from selenium import webdriver
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = "http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable"
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
target = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()
- 元素交互操作:输入、清空、点击
对于获取的元素调用交互方法,主要是元素值的输入、清空、点击等操作。
以下代码运行为:程序自动打开Chrome浏览器并打开淘宝输入ipad,然后删除,重新输入MakBook pro,并点击搜索。
from selenium import webdriver
import time
browser = webdriver.Chrome()
browser.get("http://www.taobao.com")
input_str = browser.find_element_by_id('q')
input_str.send_keys("ipad")
time.sleep(1)
input_str.clear()
input_str.send_keys("MakBook pro")
button = browser.find_element_by_class_name('btn-search')
button.click()
time.sleep(3)
browser.close()
chromeOptions
chromeOptions 是一个配置 chrome 启动是属性的类。通过这个类,我们可以为chrome配置如下参数(这个部分可以通过selenium源码看到)
- 添加实验性质的设置参数 add_experimental_option
代码如下:
# 实例化一个启动参数对象
options = webdriver.ChromeOptions()
# 设置浏览器窗口大小
options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
# 启动浏览器
browser = webdriver.Chrome(chrome_options=chrome_options)
常用的参数如下:
- 设置为开发者模式 (‘excludeSwitches’, [‘enable-automation’)
- 不加载图片,加快访问速度 (“prefs”, {“profile.managed_default_content_settings.images”: 2})
- 模拟手机打开网页 (‘mobileEmulation’, {‘deviceName’: ‘Apple iPhone 4’})
- 关闭保存密码提示
options = webdriver.ChromeOptions()
prefs = {}
# 设置这两个参数就可以避免密码提示框的弹出
prefs['credentials_enable_service'] = False
prefs['profile.password_manager_enabled'] = False
options.add_experimental_option('prefs', prefs)
browser = webdriver.Chrome(chrome_options=options)
- 添加启动参数 add_argument
完整的参数可以查看地址:https://peter.sh/experiments/chromium-command-line-switches/
启动参数 | 作用 |
---|---|
–user-agent=" | 设置请求头的User-Agent |
–window-size=1366,768 | 设置浏览器分辨率(窗口大小) |
–headless | 无界面运行(无窗口) |
–start-maximized | 最大化运行(全屏窗口) |
–incognito | 隐身模式(无痕模式) |
–disable-javascript | 禁用javascript |
–disable-infobars | 禁用浏览器正在被自动化程序控制的提示 |
- 添加扩展应用 (add_extension, add_encoded_extension)
- 设置 chrome 二进制文件位置 (binary_location)
- selenium源码
在目录 \env\Lib\site-packages\selenium\webdriver\chrome\optitions.py 下。
class Options(object):
KEY = "goog:chromeOptions"
def __init__(self):
self._binary_location = ''
self._arguments = []
self._extension_files = []
self._extensions = []
self._experimental_options = {}
self._debugger_address = None
self._caps = DesiredCapabilities.CHROME.copy()
执行JavaScript
- 调用js方法
下面的例子是通过登录知乎然后通过js翻到页面底部,并弹框提示。
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("http://www.zhihu.com/explore")
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')
- 获取元素属性、文本值
可以通过 get_attribute(‘class’) 获取元素的class属性、href属性、文本值等。
from selenium import webdriver
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo)
print(logo.get_attribute('class')) # zu-top-link-logo
print(logo.text) # 知乎
- 获取ID,位置,标签名
from selenium import webdriver
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)
"""
0.8051799500933536-1
{'x': 758, 'y': 7}
button
{'height': 32, 'width': 66}
"""
Frame
涉及到切入到frame中以及切出来的问题,常用的是switch_to.from()和switch_to.parent_frame(),如以下代码:
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
print(source)
try:
logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:
print('NO LOGO')
browser.switch_to.parent_frame()
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)
等待 Waits
以下内容基本摘自:https://selenium-python.readthedocs.io/waits.html
- 显式等待
WebDriverWait与ExpectedCondition相结合是一种可以实现的方法。EC.presence_of_element_located()是确认元素是否已经出现。
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_delays_loading")
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
在抛出TimeoutException之前等待最多10秒,除非它发现元素在10秒内返回。默认情况下,WebDriverWait每500毫秒调用一次ExpectedCondition,直到它成功返回。对于所有其他ExpectedCondition类型,ExpectedCondition类型的布尔返回true或非null返回值成功返回。
- 常用的判断条件如下
预期条件 | 目的 |
---|---|
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 | frame加载并切换 |
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 | 是否出现Alert |
- 自定义等待条件
如果以前的便捷方法都不符合您的要求,您还可以创建自定义等待条件。可以使用带有__call__方法的类创建自定义等待条件,该方法在条件不匹配时返回False。示例 : 略…
- 隐式等待
到了一定的时间发现元素还没有加载,则继续等待我们指定的时间,如果超过了我们指定的时间还没有加载就会抛出异常,如果没有需要等待的时候就已经加载完毕就会立即执行。
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
其他操作
- 浏览器的前进和后退
- 后退:back()
- 前进:forward()
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.python.org/')
browser.back()
time.sleep(1)
browser.forward()
browser.close()
- cookie操作
- get_cookies()
- delete_all_cookes()
- add_cookie()
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'zhaofan'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())
- 选项卡管理
通过执行js命令实现新开选项卡window.open()
不同的选项卡是存在列表里browser.window_handles
通过browser.window_handles[0]就可以操作第一个选项卡
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.execute_script('window.open()')
print(browser.window_handles)
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(1)
browser.switch_to_window(browser.window_handles[0])
browser.get('https://python.org')
- 异常处理
这里的异常比较复杂,官网的参考地址:http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions
这里只进行简单的演示,查找一个不存在的元素,抛出NoSuchElementException异常。
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
except TimeoutException:
print('Time Out')
try:
browser.find_element_by_id('hello')
except NoSuchElementException:
print('No Element')
finally:
browser.close()
selenium 模拟手机
有些操作,需要模拟手机才能继续进行,例如微信的公众号、服务号。直接上代码,模拟手机型号等属性。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
mobile_emulation = {"deviceName": "Pixel 2 XL",
}
options = Options()
options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome(chrome_options=options)
...
PhantomJS
- 下载使用
直接到官网 http://phantomjs.org/download.html 下载对应版本,得到phantomjs.exe,放入到虚拟环境的Script文件夹下。 - 使用
from selenium import webdriver
browser = webdriver.PhantomJS()
browser.get("http://www.baidu.com")
print(browser.page_source)
browser.close()
由于selenium对phantomjs不再支持,因此会警告:UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead