selenium是一个web自动化测试的开源框架,它支持多语言:python/java/c#…javascript
前面也有一篇文章说明了,selenium+浏览器的环境搭建。css
selenium支持多语言,是由于selenium与浏览器驱动之间是经过http协议进行通讯的。只关心通讯的数据是否可以正确解读 ,并不关心这个数据是从哪一个客户端来。不管来自python\java,仍是jmeter,postman都没有问题。java
本篇文章中,以requests作为客户端,跳过selenium,直接与谷歌浏览器驱动(chromedriver)进行http通讯,驱动chrome浏览器去执行命令。python
先解释一下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、请求类型如何获取?
三、每个请求的请求数据又如何获取?
要想解决以上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当中是get函数,那么咱们去看get函数的源码:
在上图中的execute函数当中,第二个参数params对应的就是请求数据。因此get命令的请求体为:{"url":调用get函数传进来的url值}
再好比,查找元素命令,在selenium当中是find_element函数,那么咱们去看find_element的源码:
因此find_elment命令的的请求体为:{"using":定位类型,"value":定位表达式}
一、启动本地电脑 上的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)
以上代码运行的结果以下: