定制app开发【Selenium】Selenium获取Network数据(高级版)

前言

为解决从Selenium中获取Network接口数据,定制app开发潜心研究了一小会儿,遂有此文

定制app开发基本看这篇文章的,定制app开发多多少少都跟spider 沾亲带故。定制app开发所以直接进入正题。

  • 定制app开发只想要代码,定制app开发文章前边自取
  • 定制app开发想看长篇大论,先看这篇

应用场景

-> 开发者工具 -> Network 中所有的数据包,我要全部拿下来。

举个例子🌰

  • 网站通过XHR异步加载数据,然后再渲染到网页上。而通过Selenium去获取渲染后的数据,是同HTML打交道的
  • 异步加载返回数据是json文件的,有时渲染在网页上,不一定是完整的json文件中的数据;最重要的是,json文件解析起来很方便

通过selenium去拿网页数据,往往是两个途径:

  1. selenium.page_source,通过解析HTML
  2. 通过中间人进行数据截获,数据源是啥就是啥

这两种方法各有利弊,但是这篇文章就可以将他们相结合起来了,实在是妙啊!


可能你会有疑惑👀?直接使用requests去请求不就完事了,

请你想一下,我这都使用上selenium了,你觉得我还会去使用requests再多请求一遍吗???

完整代码

Selenium获取Network

这里指定9527端口打开浏览器,也可以不指定,看上一篇文章

代码讲解在下面

# -*- coding: utf-8 -*-# @Time   : 2022-08-27 11:59# @Name   : selenium_cdp.pyimport jsonfrom selenium import webdriverfrom selenium.common.exceptions import WebDriverExceptionfrom selenium.webdriver.chrome.options import Optionscaps = {    "browserName": "chrome",    'goog:loggingPrefs': {'performance': 'ALL'}  # 开启日志性能监听}options = Options()options.add_experimental_option("debuggerAddress", "127.0.0.1:9527")  # 指定端口为9527browser = webdriver.Chrome(desired_capabilities=caps, options=options)  # 启动浏览器browser.get('https://blog.csdn.net/weixin_45081575')  # 访问该urldef filter_type(_type: str):    types = [        'application/javascript', 'application/x-javascript', 'text/css', 'webp', 'image/png', 'image/gif',        'image/jpeg', 'image/x-icon', 'application/octet-stream'    ]    if _type not in types:        return True    return Falseperformance_log = browser.get_log('performance')  # 获取名称为 performance 的日志for packet in performance_log:    message = json.loads(packet.get('message')).get('message')  # 获取message的数据    if message.get('method') != 'Network.responseReceived':  # 如果method 不是 responseReceived 类型就不往下执行        continue    packet_type = message.get('params').get('response').get('mimeType')  # 获取该请求返回的type    if not filter_type(_type=packet_type):  # 过滤type        continue    requestId = message.get('params').get('requestId')  # 唯一的请求标识符。相当于该请求的身份证    url = message.get('params').get('response').get('url')  # 获取 该请求  url    try:        resp = browser.execute_cdp_cmd('Network.getResponseBody', {'requestId': requestId})  # selenium调用 cdp        print(f'type: {packet_type} url: {url}')        print(f'response: {resp}')        print()    except WebDriverException:  # 忽略异常        pass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

运行效果看下面动图,轻松拿到该网页请求中的所有数据包~


知识点📖

允许使用工具来检测、检查、调试和分析 Chromium、Chrome 和其他基于 Blink 的浏览器。

Chrome DevTools Protocol,简称CDP

看以下 ,感兴趣的可以深入去学习了解。这个将另起一篇文章来讲。


再看 ,所以是可以通过CDP协议去操作Selenium打开的Chrome浏览器的。

代码解析

在上一篇文章 中,介绍了链接Chrome浏览器,这里进一步介绍。

以调试模式启动Selenium,打上断点,跟一下源码。来到下面这里,因为咱们指定了端口为9527,否则这个port将是随机的,至于为什么,看源码

site-packages\selenium\webdriver\common\utils.py

回到上面的代码中,

  • 'goog:loggingPrefs': {'performance': 'ALL'} ,这段代码是开启浏览器的性能日志记录
caps = {    "browserName": "chrome",    'goog:loggingPrefs': {'performance': 'ALL'}  # 开启性能日志记录}
  • 1
  • 2
  • 3
  • 4

简单理解为 中的 performance,看下图


以下代码返回的是一个列表,装着该网页请求中所有的数据包

performance_log = browser.get_log('performance') 
  • 1

看下图

  • 因为我们要获取的是 Network中的返回值,所以只取 method =Network.responseReceived


知识补充

使用 browser.log_types 可以查看当前的可用日志类型的列表,
下面两幅图分别是开启性能日志记录不开启性能日志记录 的可用日志类型返回值~


再接下来就是过滤请求包,一般来说,像图片、css&js文件等,往往是不需要的,所以可以对它们过滤~(这一步可以根据自己的需求来过滤)

def filter_type(_type: str):    types = [        'application/javascript', 'application/x-javascript', 'text/css', 'webp', 'image/png', 'image/gif',        'image/jpeg', 'image/x-icon', 'application/octet-stream'    ]    if _type not in types:        return True    return False
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

最后是获取数据包的 requestId,这个是调用 cdp 的关键,它就好比每个网络数据包的身份证。
在Selenium中调用cdp时候,需要传入 requestId,浏览器会验证是否存在该 requestId

  • 如果存在,则响应并返回数据;
  • 如果不存在,则会抛出 WebDriverException 异常。
    在这里的代码中,我对这个异常进行了忽略的处理~
    try:        resp = browser.execute_cdp_cmd('Network.getResponseBody', {'requestId': '123123123'})  # selenium调用 cdp        print(f'type: {packet_type} url: {url}')        print(f'response: {resp}')        print()    except WebDriverException:  # 忽略异常        pass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

后话

简单来说,本文章所能实现的,还算是有用的😎😎
远的不说,起码本文章就帮助我解决了mitmproxy + Selenium 的组合拳(现在只用Selenium就可以完成了~
See you.

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发