简单的例子
# coding=utf-8
from selenium import webdriver
import time
# 打开浏览器
# executable_path="./drivers/chromedriver.exe"
dr = webdriver.Chrome()
# 打开百度
dr.get('https://www.baidu.com/')
# 点击新闻链接
dr.find_element_by_link_text("新闻").click()
运行上边代码会发现报错:
selenium.common.exceptions.WebDriverException:
Message:'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home
selenium 需要知道 chromedriver 的路径,确切来说什么是 chromedriver
呢?
selenium 2 发布的时候,引入webdriver
的概念,webdriver
是一个控制运行浏览器的工具。双击运行chromedriver.exe
,将会在终端看到如下信息:
chromedriver.exe
启动浏览器驱动,端口为9515。所有的webdriver
运行原理一样:它们启动一个浏览器驱动,该服务器接收控制浏览器的命令(例如,设置浏览器cookie)。命令必须遵循 WebDriver Protocol 协议格式,该格式定义了一个所有webdriver
都必须实现的RESTish JSON API
接口,大多数编程语言都有适合处理JSON和HTTP的库,因此通过语言绑定,实现与webdriver
交互的客户端相对容易实现。
当自动化脚本运行时,执行以下步骤:
- 对于每个Selenium命令,都会创建一个HTTP请求并发送到浏览器驱动程序
- 浏览器驱动程序使用HTTP服务器来获取HTTP请求
- HTTP服务器确定实现Selenium命令所需的步骤
- 实现步骤在浏览器上执行
- 执行状态被发送回HTTP服务器
- HTTP服务器将状态发送回自动化脚本
简化来说,自动化脚本类似于一个client
,webdriver
类似于一个服务器;自动化脚本执行一步,即发送一个HTTP请求到webdriver
,webdriver
收到请求,操作浏览器并返回执行的状态
webdriver
HTTP请求返回状态码样例,详细参考 here:
0: Success
7: NoSuchElement
11: ElementNotVisible
200: Everything OK
500: Something is wrong
404: Resource not there
501: Valid request but action not done by the server
通过HTTP操作浏览器
下面我们通过执行每个HTTP请求来操作浏览器:
-
首先下载chromedriver,双击
chromedriver.exe
启动; -
创建浏览器实例(类似于
webdriver.Chrome(executable_path="./drivers/chromedriver.exe")
)
创建浏览器实例POST /session
post: http://localhost:9515/session body: { "desiredCapabilities": { } } response:{ "sessionId": "de560fbe3fb72ffeddbbb8bb47ec452f", "status": 13, "value": { "message": "unknown error: DevToolsActivePort file doesn't exist\n (Driver info: chromedriver=2.42.591088 (7b2b2dca23cca0862f674758c9a3933e685c27d5),platform=Windows NT 10.0.17134 x86_64)" } }
在postman执行(或者其他方式调用HTTP请求):
代码执行HTTP请求:import requests url = "http://localhost:9515/session" payload = "{\r\n\t\"desiredCapabilities\": {}\r\n}" headers = { 'Content-Type': "application/json", 'cache-control': "no-cache", 'Postman-Token': "65a26a0d-8d32-4241-8cfb-df3e58bb92fa" } response = requests.request("POST", url, data=payload, headers=headers) print(response.text)
将会启动一个浏览器实例:
-
打开百度(类似于
dr.get('https://www.baidu.com/')
),同样在postman执行,会看到浏览器导航到了百度
导航到某个链接POST /session/{session id}/url
post: http://localhost:9515/session/de560fbe3fb72ffeddbbb8bb47ec452f/url body: {"url":"https://www.baidu.com/"} response:{ "sessionId": "de560fbe3fb72ffeddbbb8bb47ec452f", "status": 0, "value": null }
-
点击新闻链接(类似于
dr.find_element_by_link_text("新闻").click()
),分为两步先找元素,再点击:
a. 找元素POST /session/{session id}/element
post: http://localhost:9515/session/de560fbe3fb72ffeddbbb8bb47ec452f/element body: { "using":"link text", "value":"新闻" } response:{ "sessionId": "de560fbe3fb72ffeddbbb8bb47ec452f", "status": 0, "value": { "ELEMENT": "0.6154515479706024-1" } }
b. 点击元素
POST /session/{session id}/element/{element id}/click
(依赖于找元素返回的元素值)post: http://localhost:9515/session/de560fbe3fb72ffeddbbb8bb47ec452f/element/0.6154515479706024-1/click body: 无 response:{ "sessionId": "de560fbe3fb72ffeddbbb8bb47ec452f", "status": 0, "value": null }
参考:
- https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#basic-terms-and-concepts
- https://www.w3.org/TR/webdriver/#dfn-elements
- https://www.w3.org/TR/webdriver/#back
- https://www.w3.org/TR/webdriver/#dfn-find-element
- https://jobs.zalando.com/tech/blog/selenium-webdriver-explained/?gh_src=4n3gxh1
- https://seleniumjava.com/2015/09/13/how-does-selenium-webdriver-work/