selenium原理應用 - 利用requests模擬selenium驅動瀏覽器

前言

selenium是一個web自動化測試的開源框架,它支持多語言:python/java/c#…javascript

前面也有一篇文章說明了,selenium+瀏覽器的環境搭建。css

selenium支持多語言,是由於selenium與瀏覽器驅動之間是經過http協議進行通訊的。只關心通訊的數據是否可以正確解讀 ,並不關心這個數據是從哪一個客戶端來。不管來自python\java,仍是jmeter,postman都沒有問題。java

本篇文章中,以requests作爲客戶端,跳過selenium,直接與谷歌瀏覽器驅動(chromedriver)進行http通訊,驅動chrome瀏覽器去執行命令。python

 

requests庫

先解釋一下requests庫:一個python的第三方庫,是目前最好用的http請求庫。git

直接封裝了get請求、post請求。github

只須要提供 請求url、請求方法、請求內容便可。web

如下爲request庫使用的簡單示例(request的詳細使用可參看其它博主其它的博文):chrome

import requests
​
s = requests.session()
response = s.get("http://www.baidu.com")  # 發起get請求
print(response.text)  # 獲取響應結果的  響應數據
res = response.json()  # 將  響應數據  轉換成python數據對象。

若是我要利用requests庫,去向chromedriver發送請求。那麼我必須得了解請求的類型、請求的數據、請求的內容是什麼。json

基於此,咱們須要瞭解在selenium庫當中,會有哪些請求?c#

 

須要解決的問題

一、selenium有哪些請求?

二、每個請求的請求url、請求類型如何獲取?

三、每個請求的請求數據又如何獲取?

 

selenium - json wire protocol - 獲取請求url和類型

要想解決以上3個問題,咱們須要瞭解selenium的部分原理。

在selenium與驅動進行http通訊的協議全稱叫作:json wire protocol.

咱們在使用selenium庫驅動瀏覽器的時候,咱們的操做有一部分大概是如下這樣的:

1)打開chrome瀏覽器;

2)訪問某一個網址;

3)查找該網址中的某一個元素;

4)操做3)中查找到的元素。

在selenium庫看來,以上每一步操做都是一個http請求,也叫作命令(Command)。

chromedriver在收到這個請求以後,再去驅動對chrome瀏覽器執行對應的動做。

 

 

因此,在selenium庫當中,存儲了全部命令(Command)名稱、命令對應的http請求類型、命令對應的請求url。

首先,來看看Command的名稱(選取幾個你們熟知的操做):

 

 

 

訪問網站命令(GET)對應的請求類型和請求url爲:

 

 

從上圖能夠看出,GET命令是post請求,請求地址只有一部分。

url中有3個問題:

1)請求的url並不完整。

url中,缺失中base地址。base地址爲,chromedriver的ip+端口號。由於,命令是發給chromedriver去執行的。

 

2)url當中的$sessionId是什麼?

在selenium當中,每開啓一次與chromedriver的會話,都會生成一個會話ID。sessionId就是這個會話ID。在不少的命令請求當中,在請求地址中,經過sessionId都綁定了當前的會話。

換句話說,咱們要用requests與chromedriver進行通訊,那麼咱們首先,得生成會話ID,並獲得這個ID值,纔可以進一步的去訪問網頁,去發送更多的瀏覽器操做命令。

 

3)sessionId從何而來?如何獲取?

在selenium當中,經過NEW_SESSION請求來開啓會話,chromedriver在收到請求後,在響應數據中,返回本次會話的sessionId

 

 

 

請求的參數以下(啓動什麼類型的瀏覽器、有什麼配置參數):

 1 params = {'capabilities': {
 2             'firstMatch': [{}],
 3             'alwaysMatch': {'browserName': 'chrome',
 4                             'platformName': 'any',
 5                             'goog:chromeOptions': {'extensions': [], 'args': []}
 6                             }},
 7           'desiredCapabilities': {'browserName': 'chrome',
 8                                   'version': '',
 9                                   'platform': 'ANY',
10                                   'goog:chromeOptions': {'extensions': [], 'args': []}}
11           }

 

chromedriver在正常收到請求以後,響應的數據以下(主要爲sessionId):

{
    "sessionId": "ed76b48661b6fe58b9be6f56716531b7",   # 本次會話的sessionId
    "status": 0,
    "value": {
        "acceptInsecureCerts": false,
        "acceptSslCerts": false,
        "applicationCacheEnabled": false,
        "browserConnectionEnabled": false,
        "browserName": "chrome",
        "chrome": {
            "chromedriverVersion": "74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29})",
            "userDataDir": "/var/folders/gm/k4pj0kf50vz9f3gznsp4cn340000gn/T/.com.google.Chrome.OPZURo"
        },
        "cssSelectorsEnabled": true,
        "databaseEnabled": false,
        "goog:chromeOptions": {
            "debuggerAddress": "localhost:63649"
        },
        "handlesAlerts": true,
        "hasTouchScreen": false,
        "javascriptEnabled": true,
        "locationContextEnabled": true,
        "mobileEmulationEnabled": false,
        "nativeEvents": true,
        "networkConnectionEnabled": false,
        "pageLoadStrategy": "normal",
        "platform": "Mac OS X",
        "proxy": {},
        "rotatable": false,
        "setWindowRect": true,
        "strictFileInteractability": false,
        "takesHeapSnapshot": true,
        "takesScreenshot": true,
        "timeouts": {
            "implicit": 0,
            "pageLoad": 300000,
            "script": 30000
        },
        "unexpectedAlertBehaviour": "ignore",
        "version": "75.0.3770.100",
        "webStorageEnabled": true
    }
}

ps: 可訪問此網站了解詳情:https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol

 

selenium - 每個命令函數 - 設置請求數據

以上咱們獲取到了每個命令的請求地址和請求類型。那麼請求數據從哪裏獲取 呢?

每個命令的功能不同,請求的數據也就不同。在selenium當中,都是在命令對應的函數當中去設置請求數據的。

好比,訪問網址操做命令,在selenium當中是get函數,那麼咱們去看get函數的源碼:

在上圖中的execute函數當中,第二個參數params對應的就是請求數據。因此get命令的請求體爲:{"url":調用get函數傳進來的url值}

再好比,查找元素命令,在selenium當中是find_element函數,那麼咱們去看find_element的源碼:

因此find_elment命令的的請求體爲:{"using":定位類型,"value":定位表達式}

 

 

 

利用requests - 開啓瀏覽器會話、訪問百度首頁、搜索檸檬班

一、啓動本地電腦 上的chromedriver程序。雙擊便可。默認的服務端口爲9515

 

 

 

二、經過requests庫向chromedriver發起會話、並打開百度首頁的代碼以下:

 1 #!/usr/bin/python3
 2 # -*- coding: utf-8 -*-
 3 # Name: use_request_send_http_chromedriver
 4 # Author: liyuan
 5 # Time: 15:52
 6  7 # 一、base_url從哪裏來的?如何肯定?
 8 # 二、命令的請求類型從哪裏來的?請求地址從哪裏來的?
 9 # 三、請求參數從何獲取。
10 11 import requests
12 13 # chromedriver服務的base地址。
14 base_url = "http://127.0.0.1:9515"   
15 # 建立會話
16 s = requests.Session() 
17 18 19 # **************************向chromedriver發送的命令1:創建會話**************************
20 21 # 建立與chromedriver會話的請求數據
22 params = {'capabilities': {
23             'firstMatch': [{}],
24             'alwaysMatch': {'browserName': 'chrome',
25                             'platformName': 'any',
26                             'goog:chromeOptions': {'extensions': [], 'args': []}
27                             }},
28           'desiredCapabilities': {'browserName': 'chrome',
29                                   'version': '',
30                                   'platform': 'ANY',
31                                   'goog:chromeOptions': {'extensions': [], 'args': []}}
32           }
33 34 # 建立與chromedriver的會話。注意請求數據格式是application/json
35 res = s.request("POST",base_url+'/session',json=params) 
36 # 獲取sessionId值
37 sessionid = res.json()["sessionId"]  
38 39 40 # **************************向chromedriver發送的命令2:打開網址**************************
41 42 # 請求數據
43 datas = {'url': "http://www.baidu.com"}
44 # 請求地址拼接
45 url = base_url + "/session/{}/url".format(sessionid)
46 # 發送打開百度首頁的請求,注意請求數據格式是application/json
47 res = s.request("post",url,json=datas)
48 49 50 # # **************************向chromedriver發送的命令3:找到搜索輸入框**************************
51 # 請求數據
52 datas3 = {'using':"id","value":"kw"}
53 # 請求地址拼接
54 url3 = base_url + "/session/{}/element".format(sessionid)
55 # 發送打開百度首頁的請求
56 res3 = s.request("post",url3,json=datas3)
57 # 返回結果相似:{"sessionId":"2dae661546b28cd481d84048310fb196","status":0,"value"{"ELEMENT":"0.899392980463724-1"}}
58 # 獲取元素的id 
59 ele_id = res3.json()["value"]["ELEMENT"]
60 61 62 # *****************向chromedriver發送的命令4:在搜索框當中輸入 檸檬班******************
63 # /session/$sessionId/element/$id/value
64 # 請求數據
65 datas4 = {'text': '檸檬班', 'value': ['', '', '']}
66 # 請求地址拼接
67 url4 = base_url + "/session/{}/element/{}/value".format(sessionid,ele_id)
68 # 發送打開百度首頁的請求
69 res4 = s.request("post",url4,json=datas4)

 

以上代碼運行的結果以下:

 

相關文章
相關標籤/搜索