selenium 原理应用 - 利用 requests 模拟 selenium 驱动浏览器

news/2024/7/4 13:25:09 标签: selenium, python, java

前言

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


请求的参数如下(启动什么类型的浏览器、有什么配置参数):

  params = {'capabilities': {
            'firstMatch': [{}],
            'alwaysMatch': {'browserName': 'chrome',
                            'platformName': 'any',
                            'goog:chromeOptions': {'extensions': [], 'args': []}
                            }},
          'desiredCapabilities': {'browserName': 'chrome',
                                  'version': '',
                                  'platform': 'ANY',
                                  'goog:chromeOptions': {'extensions': [], 'args': []}}
          }


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发起会话、并打开百度首页的代码如下:

  #!/usr/bin/python3
# -*- coding: utf-8 -*-
# Name: use_request_send_http_chromedriver
# Author: liyuan
# Time: 15:52

# 1、base_url从哪里来的?如何确定?
# 2、命令的请求类型从哪里来的?请求地址从哪里来的?
# 3、请求参数从何获取。

import requests

# chromedriver服务的base地址。
base_url = "http://127.0.0.1:9515"   
# 创建会话
s = requests.Session() 


# **************************向chromedriver发送的命令1:建立会话**************************

# 创建与chromedriver会话的请求数据
params = {'capabilities': {
            'firstMatch': [{}],
            'alwaysMatch': {'browserName': 'chrome',
                            'platformName': 'any',
                            'goog:chromeOptions': {'extensions': [], 'args': []}
                            }},
          'desiredCapabilities': {'browserName': 'chrome',
                                  'version': '',
                                  'platform': 'ANY',
                                  'goog:chromeOptions': {'extensions': [], 'args': []}}
          }

# 创建与chromedriver的会话。注意请求数据格式是application/json
res = s.request("POST",base_url+'/session',json=params) 
# 获取sessionId值
sessionid = res.json()["sessionId"]  


# **************************向chromedriver发送的命令2:打开网址**************************

# 请求数据
datas = {'url': "http://www.baidu.com"}
# 请求地址拼接
url = base_url + "/session/{}/url".format(sessionid)
# 发送打开百度首页的请求,注意请求数据格式是application/json
res = s.request("post",url,json=datas)


# # **************************向chromedriver发送的命令3:找到搜索输入框**************************
# 请求数据
datas3 = {'using':"id","value":"kw"}
# 请求地址拼接
url3 = base_url + "/session/{}/element".format(sessionid)
# 发送打开百度首页的请求
res3 = s.request("post",url3,json=datas3)
# 返回结果类似:{"sessionId":"2dae661546b28cd481d84048310fb196","status":0,"value"{"ELEMENT":"0.899392980463724-1"}}
# 获取元素的id 
ele_id = res3.json()["value"]["ELEMENT"]


# *****************向chromedriver发送的命令4:在搜索框当中输入 柠檬班******************
# /session/$sessionId/element/$id/value
# 请求数据
datas4 = {'text': '柠檬班', 'value': ['柠', '檬', '班']}
# 请求地址拼接
url4 = base_url + "/session/{}/element/{}/value".format(sessionid,ele_id)
# 发送打开百度首页的请求
res4 = s.request("post",url4,json=datas4)


以上代码运行的结果如下:


http://www.niftyadmin.cn/n/1665944.html

相关文章

区块链与Git版本工具的比较

区块链与Git版本工具的比较 来源:http://www.jianshu.com/p/b96b98983df6作者: 梁波林 相同点: 1. 分布式存储方案 2. 链式数据 3. 去中心化 4. 支持离线访问 5. 交易量较小 6. 参与方多,网络规模大 不同: 1. 数据内容…

RubyMine 2018.3.5 发布,流行的 Ruby 开发工具

开发四年只会写业务代码,分布式高并发都不会还做程序员? >>> RubyMine 2018.3.5 (build 183.5912.16) 发布了,带来了一些平台上的改进。RubyMine 是一个为 Ruby 和 Rails 开发者准备的 IDE。 新版本的更新亮点有: Ruby…

六个开源软件开发的“潜规则”

你想成为开源项目中得意满满、功成名就的那个人吗,那就要遵守下面的“潜规则”。 正如体育界不成文的规定一样,这些规则基本上不会出现在官方文档和正式记录上。比如说,在棒球运动中,从比分领先时不要盗垒,到跑垒员跑了…

C++进阶篇二:C++标准模版库之算法

为什么80%的码农都做不了架构师&#xff1f;>>> 写在<algorithm>头文件之前 在CSTL的头文件<algorithm>中&#xff0c;各式算法函数往往会对支持该算法的最低迭代级别作出要求。任何算法作用的容器或迭代&#xff0c;只有支持的权限等于或高于算法要求…

cookie 与 SSO 的两三事

前言 前面的文章记录了proxy代理后端接口&#xff0c;其实践过程中也不乏踩坑之处。 SSO单点登录 这里有一篇文章写得不错&#xff0c;分析了淘宝、天猫的登录场景(漫谈单点登录)。 COOKIE 关于cookie的知识自己搜&#xff0c;我这就不废话了。关键看请求的response headers &a…

Katalon Studio 自动化测试工具介绍

前言 在软件测试这条道路上&#xff0c;大部分的职业技能发展道路都会是功能测试-> 自动化测试-> 性能测试-> 安全测试/测试开发。 但是却有着一部分人起初进入软件测试这一行看重的就是软件测试属于 IT 行业&#xff0c;门槛比较低&#xff0c;不需要代码基础。这就…

优秀的产品经理,必须翻越这三座大山

作为一个资深产品经理&#xff0c;这几年工作中遇到的挫折和收获&#xff0c;数也数不清。看到用户数的不断增长和好评我会犹如打了鸡血&#xff0c;听到伙伴的质疑和用户的指责我也会在回家地铁上默默掉眼泪&#xff0c;后悔当初的选择。对于新入行的童鞋&#xff0c;我这个老…

《深入理解计算机系统》使用指南

转自&#xff1a;https://book.douban.com/review/5627139/#comments Chapter 1 A Tour of Computer System 一个对计算机系统总体的介绍&#xff0c;简单明了。 应试 ★★★&#xff1a;可能在笔试中会有一些整体上的概念题。 修炼 ★: 属于计算机最基本的概念。 chapter 2 …