Selenium WebDriver原理(二):Selenium是如何操縱瀏覽器的?


前言

上一篇文章《selenium webdriver 是怎么運行的》用了一個簡單的例子——搭出租車,形象地講解selenium webdriver 是如何運行的,而這一篇文章可以理解為深入了解selenium是如何和瀏覽器驅動進行交互,也可以認為是乙醇老師寫的《selenium是如何啟動瀏覽器的》 文章的2.0版本 。

環境准備:

python 3.0以上
selenium 3.0以上
瀏覽器 Chrome
瀏覽器驅動 ChromeDriver
接口測試工具

小編的環境:

python 3.6.4
selenium 3.13
瀏覽器 :Chrome 68
瀏覽器驅動: ChromeDriver 2.38
接口測試工具:python requests

首先,我們運行下述代碼塊

#encoding:utf8
from selenium import webdriver
import logging
logging.basicConfig(level=logging.DEBUG)
dr = webdriver.Chrome()
dr.implicitly_wait(10)
#打開深圳-逸遙 博客園首頁
dr.get('https://www.cnblogs.com/snailrunning')
#定位深圳-逸遙 第一篇博文標題
el = dr.find_element_by_css_selector('.postTitle a')
#點擊第一篇博文標題
el.click()

運行結果:

DEBUG:selenium.webdriver.remote.remote_connection:
POST http://127.0.0.1:4102/session 
{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName":     "chrome", "platformName": "any", "goog:chromeOptions": {"extensions": [], "args": []}}}, 
 "desiredCapabilities": {"browserName": "chrome", "version": "", "platform": "ANY", "goog:chromeOptions": {"extensions": [], "args": []}}}
DEBUG:selenium.webdriver.remote.remote_connection:
b'{"sessionId":"7cbbff953318267ef0089dc66f127051",
   "status":0,
   "value":{"acceptInsecureCerts":false,"acceptSslCerts":false,"applicationCacheEnabled":false,"browserConnectionEnabled":false,"browserName":"chrome","chrome":{"chromedriverVersion":"2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb)","userDataDir":"C:\\\\Users\\\\lenovo\\\\AppData\\\\Local\\\\Temp\\\\scoped_dir13812_4179"},"cssSelectorsEnabled":true,"databaseEnabled":false,"handlesAlerts":true,"hasTouchScreen":false,"javascriptEnabled":true,"locationContextEnabled":true,"mobileEmulationEnabled":false,"nativeEvents":true,"networkConnectionEnabled":false,"pageLoadStrategy":"normal","platform":"Windows NT","rotatable":false,"setWindowRect":true,"takesHeapSnapshot":true,"takesScreenshot":true,"unexpectedAlertBehaviour":"","version":"68.0.3440.106","webStorageEnabled":true}}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

DEBUG:selenium.webdriver.remote.remote_connection:
POST 
http://127.0.0.1:4102/session/7cbbff953318267ef0089dc66f127051/timeouts/implicit_wait 
{"ms": 10000.0, "sessionId": "7cbbff953318267ef0089dc66f127051"}
DEBUG:selenium.webdriver.remote.remote_connection:
b'{"sessionId":"7cbbff953318267ef0089dc66f127051","status":0,"value":null}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

DEBUG:selenium.webdriver.remote.remote_connection:
POST http://127.0.0.1:4102/session/7cbbff953318267ef0089dc66f127051/url 
{"url": "https://www.cnblogs.com/snailrunning", "sessionId": "7cbbff953318267ef0089dc66f127051"}
DEBUG:selenium.webdriver.remote.remote_connection:
b'{"sessionId":"7cbbff953318267ef0089dc66f127051","status":0,"value":null}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

DEBUG:selenium.webdriver.remote.remote_connection:
POST 
http://127.0.0.1:4102/session/7cbbff953318267ef0089dc66f127051/element 
{"using": "css selector", "value": ".postTitle a", "sessionId": "7cbbff953318267ef0089dc66f127051"}
DEBUG:selenium.webdriver.remote.remote_connection:
b'{"sessionId":"7cbbff953318267ef0089dc66f127051","status":0,"value":{"ELEMENT":"0.3612689441010788-1"}}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

DEBUG:selenium.webdriver.remote.remote_connection:
POST http://127.0.0.1:4102/session/7cbbff953318267ef0089dc66f127051/element/0.3612689441010788-1/click
{"id": "0.3612689441010788-1", "sessionId": "7cbbff953318267ef0089dc66f127051"}
DEBUG:selenium.webdriver.remote.remote_connection:
b'{"sessionId":"7cbbff953318267ef0089dc66f127051","status":0,"value":null}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

從上述代碼運行結果,我們可以得出以下結論

  • 對於每個Selenium命令,都會創建一個HTTP請求並將其發送到瀏覽器驅動程序
  • 每一個命令的執行結果都會返回給自動化代碼
  • ChromeDirver創建session時打開了瀏覽器
  • Selenium代碼和瀏覽器驅動的交互都根據ChromeDriver創建的sessionId

文章到這里,很多測試的同學看了會頭暈,沒關系,我們現在先根據上述返回的結果來拆解一下請求的接口和返回,以及我們通過接口工具來模擬Selenium自動化代碼來操縱瀏覽器

1、啟動瀏覽器接口

請求方式:post  
請求url : http://127.0.0.1:4102/session
請求body: {"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName":     "chrome", "platformName": "any", "goog:chromeOptions": {"extensions": [], "args": []}}}, 
 "desiredCapabilities": {"browserName": "chrome", "version": "", "platform": "ANY", "goog:chromeOptions": {"extensions": [], "args": []}}}
 
返回body : b'{"sessionId":"7cbbff953318267ef0089dc66f127051",
   "status":0,
   "value":{"acceptInsecureCerts":false,"acceptSslCerts":false,"applicationCacheEnabled":false,"browserConnectionEnabled":false,"browserName":"chrome","chrome":{"chromedriverVersion":"2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb)","userDataDir":"C:\\\\Users\\\\lenovo\\\\AppData\\\\Local\\\\Temp\\\\scoped_dir13812_4179"},"cssSelectorsEnabled":true,"databaseEnabled":false,"handlesAlerts":true,"hasTouchScreen":false,"javascriptEnabled":true,"locationContextEnabled":true,"mobileEmulationEnabled":false,"nativeEvents":true,"networkConnectionEnabled":false,"pageLoadStrategy":"normal","platform":"Windows NT","rotatable":false,"setWindowRect":true,"takesHeapSnapshot":true,"takesScreenshot":true,"unexpectedAlertBehaviour":"","version":"68.0.3440.106","webStorageEnabled":true}}'

1.1 開啟ChomeDriver

image

Starting ChromeDriver 2.38.552522   開啟ChromeDriver 版本號2.38.552522
(437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb) on port 9515 監聽的端口是9515
Only local connections are allowed. ; 只允許本地鏈接

1.2 構造請求

請求方式 :POST
請求地址 :http://localhost:9515/session
請求body :{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName":     "chrome", "platformName": "any", "goog:chromeOptions": {"extensions": [], "args": []}}}, 
 "desiredCapabilities": {"browserName": "chrome", "version": "", "platform": "ANY", "goog:chromeOptions": {"extensions": [], "args": []}}}

1.3 使用python requests 向 ChromeDriver發送請求

#encoding:utf8
import requests
session_url = 'http://localhost:9515/session'
session_pars = {"capabilities": {"firstMatch": [{}], \
                      "alwaysMatch": {"browserName": "chrome",\
                                      "platformName": "any", \
                                      "goog:chromeOptions": {"extensions": [], "args": []}}}, \
                "desiredCapabilities": {"browserName": "chrome", \
                             "version": "", "platform": "ANY", "goog:chromeOptions": {"extensions": [], "args": []}}}
r_session = requests.post(session_url,json=session_pars)
print(r_session.json())

此時Chrome瀏覽器被打開

image

1.4 查看返回結果

{
    "sessionId": "b2801b5dc58b15e76d0d3295b04d295c",
    "status": 0,
    "value": {
        "acceptInsecureCerts": false,
        "acceptSslCerts": false,
        "applicationCacheEnabled": false,
        "browserConnectionEnabled": false,
        "browserName": "chrome",
        "chrome": {
            "chromedriverVersion": "2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb)",
            "userDataDir": "C:\\Users\\lenovo\\AppData\\Local\\Temp\\scoped_dir1792_5142"
        },
        "cssSelectorsEnabled": true,
        "databaseEnabled": false,
        "handlesAlerts": true,
        "hasTouchScreen": false,
        "javascriptEnabled": true,
        "locationContextEnabled": true,
        "mobileEmulationEnabled": false,
        "nativeEvents": true,
        "networkConnectionEnabled": false,
        "pageLoadStrategy": "normal",
        "platform": "Windows NT",
        "rotatable": false,
        "setWindowRect": true,
        "takesHeapSnapshot": true,
        "takesScreenshot": true,
        "unexpectedAlertBehaviour": "",
        "version": "68.0.3440.106",
        "webStorageEnabled": true
    }
}

2、打開深圳-逸遙的博客園

2.1 構造請求

請求方式 :POST
請求地址 :http://localhost:9515/session/:sessionId/url

注意: 上述地址中的 ":sessionId"
要用啟動瀏覽器的請求返回結果中的sessionId的值
例如:我剛剛發送請求,啟動瀏覽器,返回結果中"sessionId": "b2801b5dc58b15e76d0d3295b04d295c"  
然后我構造 導航到"深圳-逸遙的博客園"的請求地址
請求地址:http://localhost:9515/session/b2801b5dc58b15e76d0d3295b04d295c/url

請求body :{"url": "https://www.cnblogs.com/snailrunning", "sessionId": "b2801b5dc58b15e76d0d3295b04d295c"}

2.2 使用python requests 向 ChromeDriver發送請求

#encoding:utf8
import requests
url = 'http://localhost:9515/session/b2801b5dc58b15e76d0d3295b04d295c/url'
pars = {"url": "https://www.cnblogs.com/snailrunning", "sessionId": "b2801b5dc58b15e76d0d3295b04d295c"}
r = requests.post(url,json=pars)
print(r.json())

瀏覽器打開”深圳-逸遙“的博客園

image

2.3 查看請求返回結果

{'sessionId': 'b2801b5dc58b15e76d0d3295b04d295c', 'status': 0, 'value': None}

3、定位”深圳-逸遙“第一篇博文的標題

3.1 構造請求

請求方式 :POST
請求地址 :http://localhost:9515/session/:sessionId/element

注意: 上述地址中的 ":sessionId"
要用啟動瀏覽器的請求返回結果中的sessionId的值
例如:我剛剛發送請求,啟動瀏覽器,返回結果中"sessionId": "b2801b5dc58b15e76d0d3295b04d295c"  
然后我構造 查找頁面元素的請求地址
請求地址:http://localhost:9515/session/b2801b5dc58b15e76d0d3295b04d295c/element

請求body :{"using": "css selector", "value": ".postTitle a", "sessionId": "b2801b5dc58b15e76d0d3295b04d295c"}

3.2 使用python requests 向 ChromeDriver發送請求

#encoding:utf8
import requests
url = 'http://localhost:9515/session/b2801b5dc58b15e76d0d3295b04d295c/element'
pars = {"using": "css selector", "value": ".postTitle a", "sessionId": "b2801b5dc58b15e76d0d3295b04d295c"}
r = requests.post(url,json=pars)
print(r.json())

3.3 查看請求返回的結果

{'sessionId': 'b2801b5dc58b15e76d0d3295b04d295c', 'status': 0, 'value': {'ELEMENT': '0.11402119390850629-1'}}
  • 返回結果中的{'ELEMENT': '0.11402119390850629-1'}
  • 官方文檔稱為:找到的元素的WebElement JSON對象,表示頁面上的DOM元素,同時服務器分配給ELEMENT的值是不透明的(隨機的) 這個ELEMENT的值會在針對該元素發出的所有后續命令中使用。

### 4、點擊”深圳-逸遙“博客 第一篇博文的標題 4.1 構造請求 ``` 請求方式 :POST 請求地址 :http://localhost:9515/session/:sessionId/element/:id/click

注意: 上述地址中的 ":sessionId"
要用啟動瀏覽器的請求返回結果中的sessionId的值
:id 要用元素定位請求后返回ELEMENT的值

例如:我剛剛發送請求,啟動瀏覽器,返回結果中"sessionId": "b2801b5dc58b15e76d0d3295b04d295c"
元素定位,返回ELEMENT的值"0.11402119390850629-1"

然后我構造 點擊頁面元素的請求地址
請求地址:http://localhost:9515/session/b2801b5dc58b15e76d0d3295b04d295c/element/0.11402119390850629-1/click

請求body :{"id": "0.11402119390850629-1", "sessionId": "b2801b5dc58b15e76d0d3295b04d295c"}

4.2  使用python requests 向 ChromeDriver發送請求 

encoding:utf8

import requests
url = 'http://localhost:9515/session/b2801b5dc58b15e76d0d3295b04d295c/element/0.11402119390850629-1/click'
pars ={"id": "0.5930642995574296-1", "sessionId": "b2801b5dc58b15e76d0d3295b04d295c"}
r = requests.post(url,json=pars)
print(r.json())

<br>

####  瀏覽器導航到“深圳-逸遙”首頁的第一篇博文
![image](https://wx2.sinaimg.cn/mw690/6e01037bgy1fucuuhddl9j20jk0o9abt.jpg)  

4.3  查看請求返回的結果

{'sessionId': 'b2801b5dc58b15e76d0d3295b04d295c', 'status': 0, 'value': None}

<br>
#### 文章末尾再炒一下舊飯
- 對於每個Selenium命令,都會創建一個HTTP請求並將其發送到瀏覽器驅動程序
- 每一個命令的執行結果都會返回給自動化代碼
- 響應狀態代碼 status 等於0 ,即表示命令執行成功
- ChromeDirver創建session時打開了瀏覽器
- Selenium代碼和瀏覽器驅動的交互都根據ChromeDriver創建的sessionId

<br>

#### 附帶上述操作相關的接口文檔——[selenium webdriver JsonWireProtocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol)

[WebDriver JsonWireProtocol 基本術語和概念 ](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#basic-terms-and-concepts)

[請求響應說明](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#messages)

[啟動瀏覽器,創建sessionId](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#session-1)

[導航指定url](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#post-sessionsessionidurl)

[元素定位](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelement)

[元素點擊操作](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelementidclick)

<br>
#### 參考文章
[乙醇 - selenium是如何啟動瀏覽器的](https://www.cnblogs.com/nbkhic/p/9249330.html)

#### 推薦閱讀
[乙醇 - selenium是如何啟動瀏覽器的](https://www.cnblogs.com/nbkhic/p/9249330.html)

[深圳-逸遙 - Selenium WebDriver原理(一):Selenium WebDriver 是怎么工作的?](https://www.cnblogs.com/snailrunning/p/9413446.html)

<br>
<br>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM