利用Requests模拟Selenium驱动浏览器

发表于:2021-3-04 09:42

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:小菜锦啊    来源:博客园

  前言
  Selenium是一个web自动化测试的开源框架,它支持多语言:python/java/c#…
  前面也有一篇文章说明了,selenium+浏览器的环境搭建。
  selenium支持多语言,是因为selenium与浏览器驱动之间是通过http协议进行通信的。只关心通信的数据是否能够正确解读 ,并不关心这个数据是从哪个客户端来。无论来自python\java,还是jmeter,postman都没有问题。
  本篇文章中,以requests做为客户端,跳过selenium,直接与谷歌浏览器驱动(chromedriver)进行http通信,驱动chrome浏览器去执行命令。
  Requests库
  先解释一下requests库:一个python的第三方库,是目前最好用的http请求库。
  直接封装了get请求、post请求。
  只需要提供 请求url、请求方法、请求内容即可。
  以下为request库使用的简单示例(request的详细使用可参看其它博主其它的博文):
  import requests

  s = requests.session()
  response = s.get("http://www.baidu.com")  # 发起get请求
  print(response.text)  # 获取响应结果的  响应数据
  res = response.json()  # 将  响应数据  转换成python数据对象。
  如果我要利用requests库,去向chromedriver发送请求。那么我必须得了解请求的类型、请求的数据、请求的内容是什么。
  基于此,我们需要了解在selenium库当中,会有哪些请求?
  需要解决的问题
  1、selenium有哪些请求?
  2、每一个请求的请求url、请求类型如何获取?
  3、每一个请求的请求数据又如何获取?
  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 - 开启浏览器会话、访问百度首页、搜索柠檬班
  1、启动本地电脑 上的chromedriver程序。双击即可。默认的服务端口为9515
  2、通过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 # 1、base_url从哪里来的?如何确定?
   8 # 2、命令的请求类型从哪里来的?请求地址从哪里来的?
   9 # 3、请求参数从何获取。
  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)
  以上代码运行的结果如下:

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号