[TOC]
简介
Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成 .Net、Java、Perl等不同语言的测试脚本。
简单来说,Selenium 是一个 Web 应用自动化测试工具,它可以驱动浏览器执行特定动作,完全模拟真实用户对网页进行的操作。
使用 Selenium 甚至可以抓取浏览器 实时 的页面源码,这对于网页中存在异步渲染的页面获取是非常有用的...
环境搭建
Selenium 支持多种主流浏览器的自动化操作,但不同的浏览器必须由其对应的 WebDriver 进行驱动。
Selenium WebDriver 其实代表两层含义:
-
WebDriver 提供了多种语言的编程接口:
其支持的语言有:C#、JavaScript、Java、Python、Ruby...
注:本篇文章主要介绍使用 Selenium 提供的 Python 版本的 API 来操作浏览器。
-
WebDriver 实现了对应浏览器的自动化操作代码
WebDriver 可以驱动本地浏览器进行自动化操作 ,它使用浏览器厂商提供的自动化操作 API 来操控浏览器和进行自动化测试,这其实就相当于一个真实的用户在操作浏览器。
更确切地说,WebDriver 会和各个浏览器的驱动进程进行交互,传递控制行为给到本地浏览器进行执行,并将结果返回给我们。
下面介绍下 Selenium 具体的环境搭建流程:
注:这里我们使用 Chrome 浏览器进行测试
下载 Chrome 浏览器
-
下载 Chrome 浏览器对应的 WebDriver,并将其设置到系统环境变量上,具体设置方法如下:
- Windows 平台:以管理者权限打开一个控制台,输入以下内容永久设置环境变量:
# <WebDriver-diretory> 表示下载 WebDriver 的目录 $ setx /m path "%path%;<WebDriver-diretory>"
- Mac、Linux 平台:打开控制台,输入以下内容:
# <WebDriver-diretory> 表示下载 WebDriver 的目录 $ export PATH=$PATH:<WebDriver-diretory> >> ~/.profile
最后在控制台中输入
chromedriver
测试下是否设置成功。注:下载的 WebDriver 要和 Chrome 浏览器的版本一致。
Chrome 浏览器的版本可通过在 URL 输入框中输入如下内容进查看:chrome://settings/help
-
安装 Selenium WebDriver 的 Python 库(提供通用编程接口):
# 创建虚拟环境 $ python -m venv venv # 开启虚拟环境(Unix 平台使用:source venv/bin/activate) $ venv\Scripts\activate.bat # 安装 Seleninum $ pip install selenium
-
输入以下代码进行测试:
from selenium import webdriver driver = webdriver.Chrome() driver.get('https://www.baidu.com')
执行该文件,可以看到 Chrome 浏览器弹出来并显示百度页面。
以上,Selenium 的环境搭建就完成了。
下面具体介绍下 Selenium 的自动操作接口功能。
创建浏览器驱动对象
因为 Selenium 支持多种主流浏览器的自动化操作,因此其可创建多种不同的浏览器驱动对象,如下所示:
# 创建 Chrome 浏览器驱动对象
from selenium.webdriver import Chrome
# WebDriver 配置在系统环境变量中
driver = Chrome()
# 或者直接指定 WebDriver 路径
driver = Chrome(executable_path='/path/to/chromedriver')
# 创建 Firefox 浏览器驱动对象
from selenium.webdriver import Firefox
with Firefox() as driver:
#your code inside this indent
# ...
访问网址
Selenium 中模拟浏览器访问网址的接口为:webdriver.get()
,如下所示:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
# 查看当前网址
print(f'current_url: {driver.current_url}')
driver.quit()
WebDriver.get(url)
方法可以加载访问目标url
,比如上述代码,就可以对百度页面进行访问。
注:使用WebDriver.get(url)
加载网页时,Selenium WebDriver 默认使用的加载策略为normal
模式,即WebDriver.get(url)
会阻塞直到页面全部加载完毕后,才会执行下去。
更具体来讲,WebDriver.get(url)
会等到页面设置document.readyState='complete'
且触发load
事件后,才会执行下去。
更多详细内容请查看后文:页面加载策略
延时等待
前面我们已经讲过,默认情况下,Selenium WebDriver 使用的页面加载策略为normal
模式,也即会阻塞等待直到页面完全加载,这种情况下,页面中的任何元素我们都是可以获取得到的。
但是,如果页面存在元素异步生成的情况,那么我们是存在可能无法直接获取得到生成的元素的。比如:
<!DOCTYPE html>
<html lang="en">
<head>
<script>
window.addEventListener('load', function () {
setTimeout(() => {
var newElement = document.createElement('p');
newElement.textContent = 'Hello from JavaScript!';
document.body.appendChild(newElement);
}, 1000);
});
</script>
</head>
<body></body>
</html>
对于上述页面,如果我们直接获取p
元素,如下所示:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
driver = webdriver.Chrome()
driver.get('http://127.0.0.1:5500/index.html')
try:
el = driver.find_element(By.TAG_NAME, "p")
print(f'locate tag p: {el.text}')
except NoSuchElementException:
print('failed to locate p element!!')
finally:
driver.quit()
实际上,我们是无法直接定位到p
元素的,因为p
元素是使用 JavaScript 在页面完全加载 2 秒后才动态生成的,在我们查找的时间点时还未存在,因此会抛出NoSuchElementException
异常。
另一方面,当前主流的 Web 应用架构是 前后端分离,这种架构下,前端涉及到的数据渲染基本上都是采用 Ajax 请求后端数据,然后手动渲染到页面上,因此,我们是无法在页面刚加载完成时,就获取到这些数据的。
针对上述问题,Selenium 采用的解决方案为:延时等待。
在 Selenium 中,延时等待 机制具体方案有如下三种:
-
Implicit wait:在隐式等待模式下,WebDriver 在进行元素定位时,如果找不到该定位元素,就会每隔 500ms 轮询该元素,直至找到或者超出隐式等待时间。
默认情况下,隐式等待时间为0
,表示失能隐式等待模式。针对上文示例页面,隐式等待解决方案的代码如下所示:
from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By driver = webdriver.Chrome() # 设置隐式等待 10 秒 driver.implicitly_wait(10) driver.get('http://127.0.0.1:5500/index.html') try: el = driver.find_element(By.TAG_NAME, "p") print(f'locate tag p: {el.text}') except NoSuchElementException: print('failed to locate p element!!') finally: driver.quit()
-
Explicit wait:显示等待模式是定时(每隔 500ms)轮询给定条件,直到条件为真时才进行元素查找,或者等到
WebDriverWait
设置的超时时间后结束轮询。注:不要同时使用 隐式等待 和 显示等待,否则可能会造成无法预测的延时等待时间。
针对上文示例页面,显式等待解决方案的代码如下所示:
from selenium import webdriver from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait driver = webdriver.Chrome() driver.get('http://127.0.0.1:5500/index.html') try: # 设置 WebDriverWait 的超时时间为 10 秒 wait = WebDriverWait(driver, timeout=10) # 条件为 lambda 表达式 el = wait.until(lambda d: d.find_element_by_tag_name("p")) print(f'locate tag p: {el.text}') except TimeoutException: print('failed to locate p element!!') finally: driver.quit()
WebDriver.until(method, message='')
会轮询method
执行返回值,在规定时间内,method
返回真就结束轮询,并把method
返回值返回给WebDriver.until(method,message='')
方法,所以上述代码中,我们直接让method
定位我们需要的元素,成功找到时,until(..)
方法就可以直接返回该元素。
如果超出规定时间,method
仍返回false
,那么until(..)
方法会抛出TimeoutException
异常。由于显示等待是针对 条件 的判断,在日常使用中,我们的很多操作都需要同步 DOM,因此 Selenium 针对这些常用的操作,预定义了其对应的 预期条件(Expected conditions),对 Python 接口来说,具体包含如下内容:
更多详细内容,请参考:expected_conditions
采用 预期条件 改写我们上述示例,如下所示:
from selenium import webdriver from selenium.common.exceptions import NoSuchElementException, TimeoutException 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.Chrome() driver.get('http://127.0.0.1:5500/index.html') try: # 设置 WebDriverWait 的超时时间为 10 秒 wait = WebDriverWait(driver, timeout=10) # 条件为 lambda 表达式 el = wait.until( # 预期条件:元素加载完成 EC.presence_of_element_located( (By.TAG_NAME, 'p') ) ) print(f'locate tag p: {el.text}') except TimeoutException: print('failed to locate p element!!') finally: driver.quit()
-
FluentWait:使用 FluentWait,我们可以自定义条件等待超时时间,以及条件轮询间隔时间。具体如下:
driver = Firefox() driver.get("http://somedomain/url_that_delays_loading") wait = WebDriverWait(driver, 10, poll_frequency=1, ignored_exceptions=[ElementNotVisibleException, ElementNotSelectableException]) element = wait.until(EC.element_to_be_clickable((By.XPATH, "//div")))
其实从上述代码中,可以看到,Python 中的 FluentWait 和 显示等待 没有区别,这是因为不同语言的接口有些许不同,像
FluentWait
在 Python 接口中并没有提供,因为使用WebDriver
就可以设置超时时间和轮询时间,而 Java 接口就提供了FluentWait
类...
元素操作
-
元素定位:对网页页面的操作,通常操作的都是特定元素,因此对 Html 页面元素的定位是一个十分重要的操作。
元素定位可分为如下两种定位类型:
- 单元素定位:获取单个标签元素
- 多元素定位:获取多个标签元素
Selenium 提供的元素定位接口如下表所示:
单元素定位 多元素定位 释义 find_element_by_id find_elements_by_id 通过元素 id 定位 find_element_by_class_name find_elements_by_class_name 通过元素类名定位 find_element_by_tag_name find_elements_by_tag_name 通过元素标签定位 find_element_by_css_selector find_elements_by_css_selector 通过 css 选择器定位 find_element_by_xpath find_elements_by_xpath 通过元素 xpath 定位 find_element_by_name find_elements_by_name 通过元素 name 属性定位 find_element_by_link_text find_elements_by_link_text 通过元素完整超链接定位 find_element_by_partial_link_text find_elements_by_partial_link_text 通过元素部分连接定位 find_element find_elements 通用元素定位接口 注:
find_element(..)
/find_elements(..)
是其他所有元素定位方式的通用接口,具体使用请查看以下示例:# index.html # <div id="myId" class="myClass">Hello Selenium</div> # <input type="text" name="myName" value="selected by name attribute" /> # <div class="myClass"> # <a href="https://www.baidu.com">selected by link text</a> # </div> from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('http://127.0.0.1:5500/index.html') # 单元素定位 try: ele = driver.find_element_by_id('myId') print(f'find_element_by_id ==> {ele.text}') ele = driver.find_element_by_class_name('myClass') print(f'find_element_by_class_name ==> {ele.text}') ele = driver.find_element_by_tag_name('div') print(f'find_element_by_tag_name ==> {ele.text}') ele = driver.find_element_by_css_selector('div#myId') print(f'find_element_by_css_selector ==> {ele.text}') ele = driver.find_element_by_xpath(r'//*[@id="myId"]') print(f'find_element_by_xpath ==> {ele.text}') ele = driver.find_element_by_name('myName') print(f'find_element_by_name ==> {ele.get_attribute("value")}') ele = driver.find_element_by_link_text('selected by link text') print(f'find_element_by_link_text ==> {ele.text}') ele = driver.find_element_by_partial_link_text('link text') print(f'find_element_by_partial_link_text ==> {ele.text}') ele = driver.find_element(By.ID, 'myId') print(f'find_element(By.ID) ==> {ele.text}') ele = driver.find_element(By.CLASS_NAME, 'myClass') print(f'find_element(By.CLASS_NAME) ==> {ele.text}') ele = driver.find_element(By.CSS_SELECTOR, 'div#myId') print(f'find_element(By.CSS_SELECTOR) ==> {ele.text}') ele = driver.find_element(By.XPATH, r'//*[@id="myId"]') print(f'find_element(By.XPATH) ==> {ele.text}') except NoSuchElementException as e: print(e) # 多元素获取 for ele in driver.find_elements_by_css_selector('div.myClass'): print(f'find_elements_by_... ===> {ele.text}') for ele in driver.find_elements(By.CSS_SELECTOR, 'div.myClass'): print(f'find_elements ===> {ele.text}')
注:Selenium WebDriver 中元素类型为
WebElement
,对元素的操作都封装到该类里面。 -
属性获取:定位到元素之后,就可以对元素的属性进行获取。
Selenium WebDriver 中对元素属性获取的通用方式为:
WebElement.get_attribute(name)
,比如:# Check if the "active" CSS class is applied to an element. is_active = "active" in target_element.get_attribute("class")
另外,对于一些常见的标签属性,Selenium WebDriver 提供了一些更加简便的获取方式,如下所示:
-
WebElement.text
:获取元素文本内容 -
WebElement.tag_name
:获取元素标签名 -
WebElement.size
:获取元素大小 -
WebElement.location
:获取元素位置
-
-
iframe 切换:当前页面嵌套最常用的方式就是 iframe 标签,Selenium 中无法直接获取 iframe 内部页面内容,因此,如果想操作 iframe 内部页面,则需要将驱动切换到要进行操作的 iframe 元素上,切换的方式为:
webdriver.switch_to.frame
,具体使用方式如下所示:-
定位 iframe 元素并进行切换:如下代码所示:
# <div id="newPage"> # <iframe # id="myFrameID" # src="https://www.baidu.com" # width="800" # height="400"></iframe> # </div> from selenium import webdriver from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time driver = webdriver.Chrome() driver.get('http://127.0.0.1:5500/index.html') iframe = driver.find_element(By.CSS_SELECTOR, '#myFrameID') # 切换到 iframe driver.switch_to.frame(iframe) inputKeyWord = driver.find_element(By.CSS_SELECTOR, '#kw') inputKeyWord.send_keys('Selenium') time.sleep(0.5) searchBtn = driver.find_element(By.CSS_SELECTOR, '#su') searchBtn.click()
-
通过 ID/名称进行切换:如果 iframe 设置了
id
获取name
属性,则可以直接进行切换,如下所示:# <div id="newPage"> # <iframe # id="myFrameID" # name="myFrameName" # src="https://www.baidu.com" # width="800" # height="400"></iframe> # </div> from selenium.common.exceptions import NoSuchFrameException try: # 根据 id 进行切换 driver.switch_to.frame('myFrameID') # 根据 name 进行切换 driver.switch_to.frame('myFrameName') except NoSuchFrameException: pass
-
通过索引进行切换:在 JavaScript 中,
window.frames
是一个类数组对象,其存放了当前页面中所有的框架元素,每个元素都是一个Window
对象,通过该数组我们可以很方便获取到对应索引的框架对象。同样,Selenium 也支持我们通过索引对框架进行切换,如下所示:# <div id="newPage"> # <iframe # src="https://www.baidu.com" # width="800" # height="400"></iframe> # </div> # ... try: # 切换到第 1 个 iframe driver.switch_to.frame(0) # ... except NoSuchFrameException: pass
- 退出 iframe:对子页面操作完毕后,就可以退出子页面,回到主页面,退出方式如下所示:
# switch back to default content driver.switch_to.default_content()
-
鼠标操作
Selenium WebDriver 中,将有关鼠标操作的接口都封装到 ActionChains 类中,其鼠标操作相关接口如下表所示:
鼠标操作 | 释义 |
---|---|
click | 鼠标左键单击 |
click_and_hold | 鼠标左键保持按下状态 |
context_click | 鼠标右键单击 |
double_click | 鼠标左键双击 |
drag_and_drop | 拖放 |
drag_and_drop_by_offset | 拖放到指定偏移位置 |
move_by_offset | 鼠标移动到指定偏移位置 |
move_to_element | 鼠标移动到指定元素中间位置(也起悬停作用) |
move_to_element_with_offset | 鼠标移动到指定元素上的偏移位置 |
release | 释放鼠标按下状态(即松开鼠标) |
以下对几个常用的鼠标操作进行简介:
-
context_click(on_element=None)
:表示鼠标右击操作。
当参数on_element
为None
时,表示右击鼠标所在位置。
当参数on_element
指定相关元素时,表示右击指定元素。from selenium.webdriver.common.action_chains import ActionChains driver = webdriver.Chrome() driver.get('http://127.0.0.1:5500/index.html') # 最大话窗口 driver.maximize_window() # 获取窗口大小 width, height = driver.get_window_size().values() print(f'[{width},{height}]') # 构造动作链 actions = ActionChains(driver) # 移动到窗口中间 actions.move_by_offset(width/2, height/2) # 鼠标右击 actions.context_click() # 执行动作链 actions.perform()
注:
ActionChains
表示一系列动作的组合,前面介绍的接口调用只是将相应的动作描述存储进ActionChains
实例内部的一个队列之中,因此最后必须调用perform()
函数依序触发实际动作。 -
move_to_element
:表示将鼠标移动到指定元素上,实际鼠标此时会其 悬停 作用,这对于那些会响应鼠标悬停的元素十分有用。如下所示:# <head> # <style> # .menu { # display: none; # width: 80px; # border: 1px solid #f5f5f5; # } # #show_menu:hover .menu{ # display: block; # } # </style> # </head> # <body> # <div id="show_menu"> # <div>hover me to show the menu</div> # <div class="menu"> # <ul> # <li>one</li> # <li>two</li> # <li>three</li> # </ul> # </div> # </div> # </body> # </html> from selenium.webdriver.chrome import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('http://127.0.0.1:5500/index.html') ActionChains(driver).move_to_element(driver.find_element(By.CSS_SELECTOR, '#show_menu')).perform()
-
drag_and_drop
:表示支持拖放元素。如下所示:# <p>Drag the image into the rectangle</p> # <div # id="dropArea" # style="width: 200px; height: 150px; border: 1px solid #aaaaaa;" # ></div> # <img # id="dragableElement" # draggable="true" # width="150" # src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1906469856,4113625838&fm=26&gp=0.jpg" # /> # <script> # // 可拖拽元素(drag) # const img = document.querySelector('#dragableElement'); # img.addEventListener('dragstart', (ev) => { # // 拖拽效果 # ev.dataTransfer.dropEffect = 'move'; # // 传送数据为可拖拽元素的 id # ev.dataTransfer.setData('text/plain', ev.target.id); # }); # // 可存放元素(drop) # const dropArea = document.querySelector('#dropArea'); # // 悬浮在释放区域 # dropArea.addEventListener('dragover', (ev) => { # ev.preventDefault(); # ev.dataTransfer.dropEffect = 'move'; # }); # // 释放拖拽元素 # dropArea.addEventListener('drop', (ev) => { # ev.preventDefault(); # const data = ev.dataTransfer.getData('text/plain'); # ev.target.appendChild(document.getElementById(data)); # }); # </script> from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('http://127.0.0.1:5500/index.html') actions = ActionChains(driver) dragEl = driver.find_element(By.CSS_SELECTOR, '#dragableElement') dropAreaEl = driver.find_element(By.CSS_SELECTOR, '#dropArea') actions.drag_and_drop(dragEl, dropAreaEl) actions.perform()
注:
drag_and_drop(..)
似乎无法在 Html5 上执行,参考:issue。
如果遇到这种情况,那么可以通过原生 JavaScript 模拟生成鼠标拖拽事件方式进行执行,如下所示:driver = webdriver.Chrome() driver.get('http://127.0.0.1:5500/index.html') # format 中使用 {{ 表示转义为一个 { drag_and_drop_script = """ const dataTransfer = new DataTransfer(); dataTransfer.setData('text/plain', '{sourceId}'); const target = document.querySelector('{target}') target.dispatchEvent(new DragEvent('drop', {{ dataTransfer: dataTransfer }})); """.format(sourceId='dragableElement',target='#dropArea') driver.execute_script(drag_and_drop_script)
键盘操作
Selenium WebDriver 中模拟键盘操作提供的接口主要为send_keys
、key_down
,key_up
。
-
send_keys
:表示发送按键字符。对应不同的场景,
send_keys
来源不同,比如:- 对于节点元素的键盘操作,对应的接口为
WebDriver.send_keys(*value)
- 对于执行链的键盘操作,对应的接口为
ActionChains.send_keys(*keys_to_send)
send_keys
的参数为输入的键盘字符串,对于特殊按键,比如回车,删除键等,其键盘字符封装到类Keys
中。下面列举一些常见的键盘操作:
键盘操作 释义 send_keys('Selenium 你好')
按键发送字符串 Selenium 你好
sned_keys(Keys.ENTER)
回车键(Enter) sned_keys(Keys.BACK_SPACE)
删除键(BackSpace) sned_keys(Keys.SPACE)
空格键(Space) sned_keys(Keys.TAB)
制表键(Tab) sned_keys(Keys.ALT)
ALT 键 sned_keys(Keys.CONTROL)
Ctrl 键 sned_keys(Keys.SHIFT)
Shift 键 sned_keys(Keys.ARROW_DOWN)
方向下键(类似的还有 Keys.ARROW_UP
/Keys.ARROW_LEFT
/Keys.ARROW_RIGHT
)sned_keys(Keys.F1)
F1 键(类似的还有 F2
~F12
)除了特殊字符外,
send_keys
还支持组合按键,只需将组合按键键值传递给该函数即可,比如:组合按键 释义 send_keys(Keys.CONTROL,'a')
全选(<Ctrl+a>) send_keys(Keys.CONTROL,'c')
复制(<Ctrl+c>) send_keys(Keys.CONTROL,'v')
粘贴(<Ctrl+v>) 示例:如下所示,打开网页后按下
<Ctrl+a>
全选:from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get('https://www.jianshu.com') html = driver.find_element(By.CSS_SELECTOR, 'html') html.send_keys(Keys.CONTROL, 'a')
- 对于节点元素的键盘操作,对应的接口为
key_down
:表示按下给定键,并保持按下状态(不释放)。
该方法应当只用于 Ctrl 键、Alt 键 和 Shift 键的按键操作。key_up
:表示释放指定按键。
注:key_down
和key_up
只存在于ActionChains
中,因此构建按键动作链时,才可以进行使用。
示例:如下所示,打开网页后按下<Ctrl+a>
全选:
driver = webdriver.Chrome()
driver.get('https://www.jianshu.com')
# 动作链:按下<Ctrl>,按下 a,松开<Ctrl>
ActionChains(driver).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
浏览器操作
-
窗口操作:浏览器的一个标签页面,就是一个窗口页面。
对窗口页面的主要操作有如下几种:
标题:窗口标题获取接口很简单:
WebDriver.title
当前网址:获取当前窗口 URL:
WebDriver.current_url
-
尺寸:对窗口大小进行设置,包含如下方面:
-
设置大小:设置窗口的大小,有以下几个操作可选:
精确值:将窗口设置为指定大小:
WebDriver.set_window_size(width,height,..)
最大化:当前窗口最大化,使用:
WebDriver.maximize_window()
最小化:当前窗口最小化,使用:
WebDriver.minimize_window()
-
获取大小:获取窗口大小,本质就是获取窗口的宽和高:
宽度:
WebDriver.get_window_size()['width']
高度:
WebDriver.get_window_size()['height']
-
关闭窗口:也即关闭当前标签页:
WebDriver.close()
-
创建窗口:Selenium WebDriver 并没有提供直接创建窗口的 API,因此我们需要通过其他路径进行创建。
一般功能如果没有现成 API 的化,那么就可以考虑下使用 JavaScript 脚本完成,比如:url = 'https://www.baidu.com' driver.execute_script('window.open("{url}");'.format(url=url))
注:理论上也可以通过模拟按键(比如:
<Ctrl+t>
)来创建新窗口,但本人经过实验后(只在 Chrome 运行),发现没有作用,程序也没有报错,目前不清楚问题出现在哪。如有知情者,烦请告知,感谢 _注:官方文档示例给出一个新的 API:
new_window
,但该 API 在官方文档搜索不到,这个新的 API 应该是 Selenium 4 版本的,但是目前 Selenium 4 尚处于 Alpha 测试阶段,还未正式发布。
本人使用pip install selenium
安装 Selenium 的当前最新版本为:Selenium 3.141.0
-
Tab 窗口切换:如果要进行窗口切换操作,首先需要了解以下几个概念:
WebDriver.current_window_handle
:表示当前窗口句柄。
每个窗口都会携带一个唯一的标识符,也就是当前窗口句柄,只有通过窗口句柄获取到该窗口后,才能对窗口进行操作。WebDriver.window_handles
:标识当前浏览器打开的所有窗口句柄集合。
我们可以通过遍历该集合,然后依次切换到当前窗口,进行操作。WebDriver.switch_to.window(window_handle)
:表示切换到window_handle
标识的窗口。
了解了以上内容,我们就可以完成窗口切换功能,比如:
# <a href="https://www.baidu.com" target="_blank">baidu</a> from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() wait = WebDriverWait(driver, 10) driver.get('http://127.0.0.1:5500/index.html') # 记录当前窗口句柄 original_window = driver.current_window_handle # 点击<a>标签,跳转到新标签页 driver.find_element(By.LINK_TEXT, 'baidu').click() # 预期窗口数量为 2 wait.until(EC.number_of_windows_to_be(2)) # 遍历窗口 for handler in driver.window_handles: # 找到新窗口 if handler != original_window: # 切换到新窗口(注:必须切换到新窗口,才能对新窗口进行操作) driver.switch_to.window(handler) break # 打印新窗口标题 print(f'new tab title: {driver.title}')
注:当我们在代码中点击
<a>
标签后,本地浏览器会自动跳转到新标签页,但是WebDriver
仍然停留在旧页面上,此时必须手动进行切换,才能让WebDriver
操作新标签页面。 前进:即前进到下一个历史记录网址,其操作接口为:
WebDriver.forward()
后退:即回退到上一个历史记录网址,其操作接口为:
WebDriver.back()
刷新:刷新当前页面:
WebDriver.refresh()
-
设置代理:有多种方法可以设置浏览器代理,这里列举主要的两种方式:
-
设置
DesiredCapabilities
:DesiredCapabilities
类封装了一系列浏览器需要的功能集合,我们可以通过为其增加代理功能,从而完成对浏览器设置代理,具体代码如下所示:from selenium import webdriver PROXY = '127.0.0.1:10808' # 设置代理 webdriver.DesiredCapabilities.CHROME['proxy'] = { 'socksVersion': 5, 'socksProxy': PROXY, # socks5 代理 'httpProxy': PROXY, # http 代理 'sslProxy': PROXY, # https 代理 "proxyType": "MANUAL", } driver = webdriver.Chrome() driver.get('https://www.google.com/ncr')
-
设置浏览器选项:浏览器本身提供了设置代理的功能,我们只需通过选项进行设置即可,如下所示:
from selenium import webdriver PROXY = '127.0.0.1:10808' options = webdriver.ChromeOptions() # Chrome 浏览器设置代理选项 options.add_argument(f'--proxy-server=socks5://{PROXY}') driver = webdriver.Chrome(options=options) driver.get('https://www.google.com/ncr')
-
关闭浏览器:操作完成后,本地浏览器不会自动关闭,此时可以通过代码进行关闭:
WebDriver.quit()
Headless 模式
-
Headless 模式:即无头/无界模式,即不显示本地浏览器,直接以后台运行操作。
为浏览器设置 Headless 方法很简单,只需传递--headless
/headless
选项,如下所示:from selenium import webdriver from selenium.webdriver import ChromeOptions options = ChromeOptions() options.add_argument('headless') with webdriver.Chrome(options=options) as driver: driver.get('https://baidu.com') print(driver.title)
注:在很久以前,Selenium 中如果想后台运行自动化操作(即不显示浏览器),通常都是使用 PhantomJS,但后来随着 Chrome 浏览器等提供了 Headless 模式后,现在已经没有必要再使用 PhantomJS 了,PhantomJS 目前也处于不再维护的状态了。
页面源码实时获取
Selenium 虽然被称为 Web 应用程序自动化测试工具,但是它也可以用来进行爬虫抓取,尤其当网页中存在使用 JavaScript 进行异步渲染或者请求接口存在加密数据时,可以借助 Selenium 等待异步渲染完成后,再获取此时的页面数据即可,无需自己去解密加密数据,唯一的缺点就是由于存在渲染等因素,导致速度会比直接解析慢。
前面在 延时等待 章节也介绍过,由于当前主流的 Web 开发架构是 前后端分离,因此前端会存在大量请求后端数据,异步渲染页面等操作。
通常写爬虫,我们都会自己手动去抓取分析这些数据接口,但是有时候有些接口加密了,破解难度比较大,这时就可以借助 Selenium 来完成数据抓取,我们无需关心具体的数据请求过程,只需等到数据渲染到页面上时,直接获取页面数据即可,虽说牺牲了爬取速度,但获取难度直线下降啊。
最后,Selenium WebDriver 中获取当前页面实时源码方法为:WebDriver.page_source
执行 JavaScript 脚本
Selenium 虽然提供了很多 API 供我们操作浏览器,但是还是无法覆盖所有内容。
因此,Selenium 提供了一项本人认为是杀手级功能的特性:执行 JavaScript 脚本
这项功能其实赋予了我们几乎可以完全操控浏览器的功能,Selenium WebDriver 提供的接口为:WebDriver.execute_script(script, *args)
示例:加载网页后,让其垂直滚动到最底部。
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://baidu.com')
# window.scrollTo(x,y)
driver.execute_script(f'window.scrollTo(0,{driver.get_window_size()["height"]});')
Cookie 操作
Selenium WebDriver 中对 Cookie 的操作,主要有如下几种:
Cookie 操作 | 释义 |
---|---|
get_cookies() | 获取所有 Cookie 信息 |
get_cookie(name) | 获取名称为 name 的 Cookie 信息 |
add_cookie(cookie_dict) | 添加 Cookie |
delete_cookie(name) | 删除名称为 name 的 Cookie |
delete_all_cookies() | 清空 Cookie |
示例:如下所示:
from selenium import webdriver
with webdriver.Chrome() as driver:
driver.get('https://baidu.com')
print('------- Cookie Info (Original) -------------')
# 打印 Cookie 信息
print(driver.get_cookies())
cookie_dict = {
'name': 'Whyn_cookie_id',
'value': 'Whyn_cookie_value',
# 'path': r'/',
# 'secure':False
# 'expiry': 162721599
}
# 添加 Cookie
driver.add_cookie(cookie_dict)
print('------- Cookie Info (Add) -------------')
for cookie in driver.get_cookies():
print('''
{{
"domain": "{domain}",
"{name}": {value},
"path": {path},
"secure": {secure},
"expiry": {expiry}
}}'''.format(
domain=cookie.get('domain', None),
name=cookie['name'],
value=cookie['value'],
path=cookie.get('path', '/'),
secure=cookie.get('secure', False),
expiry=cookie.get('expiry', None)
))
# 删除 Cookie
driver.delete_cookie('Whyn_cookie_id')
print('------- Cookie Info (Delete) -------------')
for cookie in driver.get_cookies():
print('{"%s":"%s"}' %(cookie['name'],cookie['value']))
# 清空 Cookie
print('------- Cookie Info (Clear) -------------')
driver.delete_all_cookies()
for cookie in driver.get_cookies():
print('{"%s":"%s"}' %(cookie['name'],cookie['value']))
截屏
通过搜索文档,可以发现,Selenium 提供了以下两种类型的截屏功能:
-
[WebElement.screenshot(filename)][WebElement.screenshot]
:该方法可以对元素进行截屏,如下代码所示: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 from selenium.webdriver import ChromeOptions options = ChromeOptions() options.add_argument('headless') with webdriver.Chrome(options=options) as driver: driver.get('https://www.jianshu.com') wait = WebDriverWait(driver,10) # 文章区域 el = wait.until(EC.presence_of_element_located( (By.CSS_SELECTOR,'#list-container') )) # 浏览器窗口设置为元素大小,以保证能完全截取元素区域 driver.set_window_size(el.size['width'],el.size['height']) el.screenshot('D:\\jianshu.png')
-
WebDriver.save_screenshot(filename)
:截取浏览器当前页面。具体代码如下所示:options = ChromeOptions() options.add_argument('headless') with webdriver.Chrome(options=options) as driver: driver.get('https://www.jianshu.com') wait = WebDriverWait(driver,10) # 文章区域 wait.until(EC.presence_of_element_located( (By.CSS_SELECTOR,'#list-container') )) width = driver.execute_script("return document.documentElement.scrollWidth") height = driver.execute_script("return document.documentElement.scrollHeight") print(f'page scroll size: {width} x {height}') # 将窗口设置为页面滚动宽高 driver.set_window_size(width, height) print('screenshot done') if driver.save_screenshot('D:\\jianshu.png') else print('screenshot failed!!')
注:截屏时我们需要将窗口的宽高设置为元素/页面滚动宽高,这样就可以完整截取整个元素/页面内容,但一个前提是必须使用 Headless 模式,否则窃取的只是当前视口高度内容。
页面加载策略(Page loading strategy)
Selenium 加载页面时,可选择如下几种模式的加载策略:
normal
:该模式会让 Selenium WebDriver 等待整个页面全部加载完成,也即 WebDriver 会等待直到页面触发load
事件。
注:normal
模式为 Selenium 默认的页面加载策略。eager
:该模式下,Selenium WebDriver 等待直到文档解析完毕,也即页面触发DOMContentLoaded
事件,此时页面中图片,CSS 和 子frame 等尚未真正进行加载。-
none
:该模式下,Selenium WebDriver 仅仅等待直到页面下载完成。from selenium import webdriver from selenium.webdriver.chrome.options import Options options = Options() # 设置页面加载策略 options.page_load_strategy = 'normal' driver = webdriver.Chrome(options=options) # Navigate to url driver.get("http://www.google.com") driver.quit()
到这里差不多已经把 Selenium 的基本用法都讲述了。
下面介绍几个好用的 Selenium 进阶用法。
巧用 Cookie
-
复用 Cookie:如果我们使用 Selenium 模拟登录操作,当然是可行的,但是有些登录操作比较复杂,并且现在网站有相当多的登录验证都得人工进行操作才可以(比如图片识别...),用 Selenium 模拟登录通常来说是一个费力不讨好的事情,因为无论多复杂的登录操作,目的就是为了获取得到相应的 Cookie,而 Selenium 是有提供 Cookie 操作的 API 哦,那其实我们完全可以手动进行登录,然后直接从浏览器开发者工具抓取到需要的 Cookie 字符串,设置到 Selenium 中即可。具体代码如下所示:
# 切割字符串,获取每条 Cookie 键值 def str2Cookie(cookieStr): def getCookieInfo(cookie): return cookie.split('=', maxsplit=1) for cookie in cookieStr.split(';'): name, value = getCookieInfo(cookie.strip()) yield {'name': name, 'value': value} def imitateLogin(driver): # 手动抓取的 Cookie 字符串 cookieStr = r'__yadk_uid=vJVlSDVQ4aq4hdF3A0DbFmiTdt76cbOB; _ga=GA1.2.1004530019.1590339033; _gid=GA1.2.1890133014.1595150121; remember_user_token=W1syMjIyOTk3XSwiJDJhJDEwJE9XSC5RdnhmNDRKWkRVZS9rRWtrOC4iLCIxNTk1NzM4MDY5LjMxODAxOTIiXQ%3D%3D--7807e1b7a5480d4883e8884a74c2d18dbffb20d9; read_mode=day; default_font=font2; locale=zh-CN; _m7e_session_core=e0ee38cfe3ad01ef5263a1fc7d8e4a26; Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1595234295,1595234452,1595754538,1595785636; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%222222997%22%2C%22%24device_id%22%3A%221724796c82722-05b58554ba041f-d373666-1049088-1724796c828e0%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_utm_source%22%3A%22recommendation%22%2C%22%24latest_utm_medium%22%3A%22seo_notes%22%2C%22%24latest_utm_campaign%22%3A%22maleskine%22%2C%22%24latest_utm_content%22%3A%22user%22%2C%22%24latest_referrer_host%22%3A%22%22%7D%2C%22first_id%22%3A%221724796c82722-05b58554ba041f-d373666-1049088-1724796c828e0%22%7D; Hm_lpvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1595789596' # 必须先访问页面,然后才能操作 Cookie driver.get('https://www.jianshu.com/') # 清空 Cookie driver.delete_all_cookies() # 解析 cookieStr,并添加到 selenium 当前会话的的 Cookie 中 for cookie in str2Cookie(cookieStr): driver.add_cookie(cookie) # 刷新当前页面,使 Cookie 生效 driver.refresh() if __name__ == '__main__': driver = webdriver.Chrome() imitateLogin(driver)
结果如下图所示:
-
持久化 Cookie:上面内容我们是直接手动获取 Cookie,这种做法可能存在 Cookie 抓取不完全,导致某些页面无法访问。其实更好地做法是对 Cookie 进行持久化,我们只需使用 Selenium 模拟一个登录,然后持久化此时的 Cookie,下次再次登录时,直接加载这些 Cookie,无需进行真实登录操作。具体持久化方法如下所示:
# 持久化 Cookie def saveCookies(cookies,filename='cookies.json'): with open(filename,mode='w',encoding='utf-8') as file: import json file.write(json.dumps(cookies)) # 加载 Cookie def loadCookies(filename='cookies.json'): cookies = None try: with open(filename,mode='r',encoding='utf-8') as file: import json cookies = json.loads(file.read()) except FileNotFoundError: cookies = None except PermissionError: cookies = None return cookies if __name__ == '__main__': driver = webdriver.Chrome() # 需要先访问下网址 driver.get('https://www.jianshu.com/') # 先获取持久化的 Cookie cookies = loadCookies() # Cookie 存在 if cookies is not None: # 清空重置 Cookie driver.delete_all_cookies() # 添加 Cookie for cookie in cookies: driver.add_cookie(cookie) # 刷新一下 driver.refresh() # Cookie 不存在,则进行真实登录 else: # 此处进行真正的登录操作 # 登录成功后,持久化此时的 Cookie saveCookies(driver.get_cookies()) # 现在就是已登录状态
请求拦截
很多时候,我们其实需要对请求进行拦截,比如添加自定义请求头等操作,但是,Selenium 原生不提供请求拦截功能。因此,我们只能另辟渠道。
目前使用最多的应该是通过代理服务器对请求进行拦截,因为 Selenium 提供了设置代理的功能,这样就很好地对请求,甚至是响应(其实通过代理基本上什么都能弄,包括上面讲述的 巧用 Cookie _)进行拦截修改。
这里本人使用的代理库为:BrowserMob Proxy。
将 BMP 设置为浏览器代理,这样 BMP 就可以对浏览器的所有请求和响应进行捕获,并且也可以将捕获的数据保存到 HAR 文件中,方便查看全部请求过程。
同时,BMP 提供了独立的代理服务,我们可以通过 RESTful API 设置代理服务器。
而如果想扩展更多的功能,BMP 还可以嵌入到我们的代码中进行调用,尤其是结合到 Selenium 代码中非常好用。
这里我们就直接以例子进行讲解,介绍下如何为 Selenium 请求添加自定义头部。
为了能有更大的扩展性,我们就通过代码来进行实现。
注:BMP 的独立使用方法可以移步到 附录 区进行查看。
注:由于 BMP 是采用 Java 代码进行编写,而我们这里是使用 Python 代码,所以我们这里无法直接将 BMP 嵌入到我们代码中使用。
我这边的做法是新开一个 Java 工程,然后调用 BMP 接口,创建一个代理服务器,具体过程如下所示:
-
首先创建一个普通的 Maven Java 工程,如下图所示:
-
在 pom.xml 中导入 BMP 依赖,如下所示:
<project xmlns="http://maven.apache.org/POM/4.0.0"> <!-- ... --> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>net.lightbody.bmp</groupId> <artifactId>browsermob-core</artifactId> <version>2.1.5</version> </dependency> </dependencies> </project>
-
使用以下代码生成证书、密钥和公钥(为了支持 HTTPS 代理):
// 证书存放在 E:\\cert 目录中 private static void generateRootCertificate(){ // create a CA Root Certificate using default settings RootCertificateGenerator rootCertificateGenerator = RootCertificateGenerator.builder().build(); // save the newly-generated Root Certificate and Private Key -- the .cer file can be imported // directly into a browser rootCertificateGenerator.saveRootCertificateAsPemFile(new File("E:\\cert\\certificate.cer")); rootCertificateGenerator.savePrivateKeyAsPemFile(new File("E:\\cert\\private-key.pem"), "password"); // or save the certificate and private key as a PKCS12 keystore, for later use rootCertificateGenerator.saveRootCertificateAndKey("PKCS12", new File("E:\\cert\\keystore.p12"), "privateKeyAlias", "password"); }
注:代码生成证书的详细内容,请参考:mitm module
注:也可以直接下载 BMP 提供的证书:ca-certificate-rsa.cer
但是还是建议使用代码生成证书,这样更加安全。 -
为 Chrome 浏览器添加上一步生成的证书,具体步骤如下所示:
- 打开页面:
chrome://settings/?search=certificate
,找到Manage certificates
条目 - 点击
Manage certificates
条目,弹出证书导入框,选择Trusted Root Certification Authorities
标签 - 选择
Import
按钮,导入我们生成的证书。
对于上述代码,我们生成的证书路径为:E:\cert\certificate.cer
- 打开页面:
-
编写代码,创建代理服务器,具体代码如下:
public class ProxyServer { public static void main(String[] args) { // ProxyServer.generateRootCertificate(); BrowserMobProxy proxy = new BrowserMobProxyServer(); // 代理服务器配置证书公钥(不是代码自动生成的证书可以不用进行设置) proxy.setMitmManager(ProxyServer.configKeystore()); // 全局自定义请求头 proxy.addHeader("MyHeader", "This is a customed global header"); // 请求拦截器 proxy.addRequestFilter(new RequestFilter() { @Override public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) { System.out.println("filter Reqeust => " + messageInfo.getOriginalUrl()); // 拦截请求,添加请求头 request.headers().add("FilterHeader", "This is a filter header"); return null; } }); // 响应拦截器 proxy.addResponseFilter(new ResponseFilter() { @Override public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) { System.out.println("filter rEsponse......"); } }); // 启动代理服务器 proxy.start(0); // 获取代理服务器端口 int port = proxy.getPort(); // get the JVM-assigned port System.out.println("proxy server running on port " + port); } // 获取公钥内容 private static ImpersonatingMitmManager configKeystore() { CertificateAndKeySource existingCertificateSource = new KeyStoreFileCertificateSource("PKCS12", new File("E:\\cert\\keystore.p12"), "privateKeyAlias", "password"); // configure the MitmManager to use the custom KeyStore source ImpersonatingMitmManager mitmManager = ImpersonatingMitmManager.builder() .rootCertificateSource(existingCertificateSource) .build(); return mitmManager; } }
注:上述代码我们通过
proxy.addHeader(..)
增加了一个全局请求头:MyHeader: This is a customed global header
,
通过在请求拦截器中增加了一个请求头:FilterHeader: This is a filter header
-
执行上述代码,启动代理服务器,从输入内容中可以查看到代理服务器的端口号,如下图所示:
-
Selenium 配置代理,如下代码所示:
# 注意端口号 PROXY = '127.0.0.1:3582' # 设置代理 webdriver.DesiredCapabilities.CHROME['proxy'] = { 'httpProxy': PROXY, 'sslProxy': PROXY, "proxyType": "MANUAL", } driver = webdriver.Chrome() driver.get('https://httpbin.org/headers') print(driver.page_source)
上述代码执行结果如下图所示:
反爬措施
由于使用 Selenium 可以很方便对网页进行自动化操作,这同时也表示说 Selenium 是一个非常好用的爬虫处理器。
也因此,有一些网站就增加了对 Selenium 的检测,以禁止 Selenium 进行爬虫操作。
目前使用最多的检测 Selenium 爬取的方式为:通过检测浏览器当前页面的window.navigator
,如果其包含有webdriver
这个属性,那就表示使用了 Selenium 进行爬取,反之,如果检测到webdriver
为undefined
,则表示正常操作。
比如对于网站:https://antispider1.scrape.cuiqingcai.com/
如果我们直接使用 Selenium 进行爬取,如下所示:
driver = webdriver.Chrome()
driver.get('https://antispider1.scrape.cuiqingcai.com/')
print(driver.page_source)
运行上述代码后,可以看到如下结果:
而如果想解决这个问题,依据先前我们介绍的原理可知,只要我们能将window.navigator.webdriver
设置为undefined
即可,
但是我们不能简单地调用如下代码进行设置:
driver.execute_script('Object.defineProperty(navigator, "webdriver", {get: () => undefined})')
因为WebDriver.execute_script(..)
是在页面加载完成后才执行,在时序上慢于网页检测。
因此,我们的变量修改必须尽早地在页面加载完成时进行设置。
而 Selenium 中提供的相应机制为:CDP(即 Chrome Devtools-Protocol,Chrome 开发工具协议)
对应的接口为:WebDriver.execute_cdp_cmd(cmd, cmd_args)
对应于上述示例,如果我们想要尽早在页面加载完成时执行我们的 JavaScript 脚本,需要使用的 CDP 命令为:Page.addScriptToEvaluateOnNewDocument
,具体的代码如下所示:
options = ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)
browser=webdriver.Chrome(options=options)
browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
browser.get('https://antispider1.scrape.cuiqingcai.com/')
附录
各浏览器 WebDriver 下载地址:quick-reference
-
BrowserMob Proxy 独立使用:下面介绍下 BMP 作为独立应用的代理服务类的基本用法,主要有如下内容:
首先下载 BMP 的可执行命令行工具,可以在 releases page 下载或源码编译
-
进行 BMP 源码
bin
目录下,可以看到可执行文件browsermob-proxy
,输入以下命令,启动 BMP 的 RESTful API:# 指定 BMP 运行在 8080 端口 $ ./browsermob-proxy -port 8080
-
访问 BMP 的
/proxy
接口,生成一个代理服务器实例:$ curl -X POST http://localhost:8080/proxy {"port":8081}
注:返回的内容
{"port":8081}
表示代理服务器的端口号
注:到这里,其实我们就可以把 Selenium 设置到代理服务器127.0.0.1:8081
上 -
接下来我们就可以根据 BMP 提供的其他 RESTful 服务对我们刚才生成的代理进行设置,以下简单列举设置:
- 查询 BMP 创建代理数量:对应接口为
/proxy
,如下所示:
$ curl -X GET http://localhost:8080/proxy {"proxyList":[{"port":8081}]}
- 关闭代理服务器:对应接口为
/proxy/[port]
,如下所示:
# 关闭端口号为 8081 的代理服务器 $ curl -X DELETE http://localhost:8080/proxy/8081
- 设置或覆盖代理服务器请求头:接口为
/proxy/[port]/headers
,如下所示:
# 设置代理服务器 8081 的请求头 $ curl -X POST -d "{\"User-Agent\": \"this is my user agent\"}" --header "Content-Type: application/json" http://localhost:8080/proxy/8081/headers # 查看设置效果 $ curl http://httpbin.org/headers --proxy http://localhost:8081
更多 BMP 提供的 RESTful 服务,请参考:REST API
- 查询 BMP 创建代理数量:对应接口为