首页 > 编程语言 >[Python] Selenium监控网络请求

[Python] Selenium监控网络请求

时间:2024-10-22 17:47:35浏览次数:1  
标签:请求 Python Selenium self request 监控 import interceptor driver

  Selenium监控网络有两种方式,第一种使用代理,第二张是使用CDP(Chrome DevTools Protocol)协议,下面直接进入主题分别介绍如何使用代理和CDP协议监控网络请求。

  一、使用Selenium-Wire设置代理拦截处理请求。

  Selenium-Wire是基于Selenium开发的抓包工具,基本使用方式如下:

from selenium import webdriver
from seleniumwire import webdriver as webdriverwire
from seleniumwire.request import Request, Response


def request_interceptor(request: Request):
    """处理请求"""
    print("request_interceptor", request.method, request.url)


def response_interceptor(request: Request, response: Response):
    """处理请求响应"""
    print("response_interceptor", request.method, request.url, response.status_code)

options = webdriver.ChromeOptions()
options.add_argument("--ignore-certificate-errors")

# url正则表达式集合
scopes = set()
scopes.add("https?://.+/confirm")
ignore_http_methods = [
    "OPTIONS",
    "HEAD",
    "CONNECT",
    "TRACE",
    "PATCH",
]
seleniumwire_options = {
    # 过滤域名
    "exclude_hosts": ["www.exclude.com"],
    # 过滤请求方法
    "ignore_http_methods": ignore_http_methods,
    "verify_ssl": False,  # 不验证证书
    "enable_logging": True,
    "request_storage": "memory",  # 缓存到内存
    # "request_storage_base_dir": request_storage_base_dir,  # 设置请求缓存的目录
    "request_storage_max_size": 100,  # Store no more than 100 requests in memory
}

driver = webdriverwire.Chrome(
    options=options,
    seleniumwire_options=seleniumwire_options,
)
driver.request_interceptor = request_interceptor
driver.response_interceptor = response_interceptor
driver.scopes = list(scopes)

driver.get('https://www.baidu.com')

  解释:

  scopes:通过正则表达式过滤网络请求,过滤后的请求更方便查找,注意不符合正则表达式的URL依然使用代理。

  exclude_hosts:过滤不使用代理的域名。

  request_interceptor:拦截处理请求。

  response_interceptor:拦截处理请求响应结果。

  注意:

  (1)要把https证书放程序目录的seleniumwire文件夹,若网页提示https不安全,需要导入seleniumwire https证书到受信任的根目录。

  (2)部分网站无法使用seleniumwire打开,会提示502,需要设置代理,下面示范使用Fiddler代理。

  使用Fiddler代理抓包:

  1. 安装并运行Fiddler Classic,设置开启HTTPS抓包,保证软件开启就行,不需要实时抓包,Fiddler默认使用8888端口代理。

  2. 设置seleniumwire_options使用Fiddler代理:

# 设置代理
seleniumwire_options["proxy"] = {
    "https": "https://127.0.0.1:8888",
    "http": "http://127.0.0.1:8888",
    "no_proxy": "localhost,127.0.0.1",  # 不使用代理的地址
}

 

  二、使用CDP协议监控网络请求。

"""CDP监控网络请求"""

import json
import re
import time
from typing import Dict, List, TypeVar
from selenium import webdriver
from selenium.webdriver.chrome.webdriver import WebDriver

from log import log


class CdpNetworkMonitor:
    """CDP监控网络请求"""

    _S = TypeVar("_S", bound="CdpNetworkMonitor")

    static_monitor: _S = None

    def __init__(self, driver: WebDriver, url_patterns: List[str]):
        """
        :param url_patterns url正则表达式集合
        """
        self.driver = driver
        self.url_patterns = url_patterns
        """url正则表达式集合"""
        self.last_log_timestamp = 0
        """最新日志时间戳"""
        self.requests: Dict[str, dict] = {}
        """请求集合"""
        self.last_flush_time: float = 0
        """上次读取性能日志时间"""
        CdpNetworkMonitor.static_monitor = self

    def start(self):
        """启用网络监控"""
        try:
            self.driver.execute_cdp_cmd("Network.enable", {})
        except Exception as ex:
            log("启用网络监控", type(ex), ex)

    def stop(self):
        """禁用网络监控"""
        try:
            self.driver.execute_cdp_cmd("Network.disable", {})
        except Exception as ex:
            log("禁用网络监控", type(ex), ex)

    def flush(self):
        """CDP读取性能日志"""
        timestamp = time.time()
        if timestamp - self.last_flush_time < 3:
            return
        self.last_flush_time = timestamp
        # 获取性能日志
        try:
            cdp_logs: List[dict] = self.driver.get_log("performance")
            for cdp_log in cdp_logs:
                log_timestamp: int = cdp_log.get("timestamp")
                if log_timestamp <= self.last_log_timestamp:
                    # 日志已读取
                    continue
                self.last_log_timestamp = log_timestamp
                log_json: dict = json.loads(cdp_log["message"])
                message: dict = log_json.get("message")
                if not message:
                    log("CDP性能日志无法获取message")
                    continue
                method: str = message.get("method")
                if not method:
                    log("CDP性能日志无法获取method")
                    continue
                if method == "Network.requestWillBeSent":
                    # 发起请求
                    request: dict = message["params"]["request"]
                    url = request.get("url")
                    if any(
                        re.search(url_pattern, url) for url_pattern in self.url_patterns
                    ):
                        # 符合url正则表达式
                        request_id = message["params"]["requestId"]
                        log(request_id, request)
                        self.requests[request_id] = request
                elif message.get("method") == "Network.responseReceived":
                    # 响应请求
                    request_id = message["params"]["requestId"]
                    if request_id in self.requests:
                        response: dict = message["params"]["response"]
                        # 获取响应内容
                        response_body = self.driver.execute_cdp_cmd(
                            "Network.getResponseBody", {"requestId": request_id}
                        )
                        response["body"] = response_body
                        log(request_id, response)
                        self.requests[request_id]["response"] = response
        except Exception as ex:
            log("CDP读取性能日志", type(ex), ex)

    def clear(self):
        """清理请求缓存"""
        try:
            self.requests.clear()
            self.driver.execute_cdp_cmd("Log.clear", {})
        except Exception as ex:
            log("清理请求缓存", type(ex), ex)


options = webdriver.ChromeOptions()
options.set_capability("goog:loggingPrefs", {"performance": "ALL"})  # 启用性能日志
driver = webdriver.Chrome(options=options)
scopes = ["https?://www.baidu.com"]
monitor = CdpNetworkMonitor(driver, scopes)
monitor.start()

driver.get('https://www.baidu.com')

time.sleep(10)
monitor.flush()

for request_id in monitor.requests:
    print(monitor.requests[request_id])

   解释:

  Python版本的CDP网络请求事件无法通过事件回调机制监听,只能轮询性能日志,这里我封装了CdpNetworkMonitor工具类过滤要监控的请求。

  CDP也可以拦截修改请求,但需要轮询性能日志并通过execute_cdp_cmd处理请求,若不及时处理拦截的请求会导致请求失败,这与driver.get()打开页面有冲突,所以得出结论Python的CDP无法拦截处理请求,但可以仅查看。

标签:请求,Python,Selenium,self,request,监控,import,interceptor,driver
From: https://www.cnblogs.com/pumbaa/p/18493411

相关文章

  • python第六章课后习题
    点击查看代码print("学号:2023310143028")点击查看代码defprim(graph,start):num_nodes=len(graph)visited=[False]*num_nodesmin_heap=[(0,start,-1)]mst_cost=0mst_edges=[]whilemin_heap:......
  • Python 数据分析与可视化有什么区别
    在当今的数据驱动时代,Python已成为数据分析和数据可视化的重要工具。尽管这两个领域经常在数据科学项目中相互交织,但它们在功能和目的上存在本质区别。本文旨在详细探讨Python在数据分析和数据可视化方面的差异,包括它们的定义、使用的主要库、应用场景以及在实际项目中的作用。通......
  • python第四章课后习题
    点击查看代码importnumpyasnpimportcvxpyascpx=cp.Variable(6,pos=True)obj=cp.Minimize(x[5])a1=np.array([0.025,0.015,0.055,0.026])a2=np.array([0.05,0.27,0.19,0.185,0.185])a3=np.array([1,1.01,1.02,1.045,1.065])k=0.05;kk=[];qq=[]whil......
  • Python教程:Python父类方法重写
    在Python中,子类可以通过定义与父类同名的方法来重写(Override)父类的方法。这种机制允许子类提供特定的实现,以替代从父类继承的通用实现。重写父类方法时,子类方法将覆盖父类方法的行为,但子类仍然可以访问父类方法的原始实现(如果需要的话)。以下是一个简单的示例,展示了如何在Py......
  • python3 class的使用
     1.class的使用和定义#!/usr/bin/python3classJustCounter:__secretCount=0#私有变量publicCount=0#公开变量defcount(self):self.__secretCount+=1self.publicCount+=1print(self.__secretCount)coun......
  • Python中的时间戳转换
    在Python中,可以使用time模块来进行时间与时间戳的转换。具体如下:1.时间转时间戳:使用time.mktime()函数,将时间元组作为参数传入即可。importtimedate_tuple=(2022,1,1,12,0,0,0,0,0)timestamp=time.mktime(date_tuple)print(timestamp) #输出:1641052800.......
  • 应对复杂架构下的监控挑战?统一运维可观测能力是关键!
    在全球数字化变革背景下,企业需适应数字经济与市场变化,进行系统性数字化转型。在“十四五”规划指导下,企业纷纷探求数字化应用之路,大数据、云计算、人工智能、区块链等技术成了热门话题,其中云运维备受瞩目。企业在数字化转型中难免会碰到云上系统规划、运维体系建设、云上安全等挑......
  • Mirascope: 优雅简洁的Python LLM库
    Mirascope简介Mirascope是一个为Python开发者设计的优雅简洁的大语言模型(LLM)库。它的目标是为LLMAPI提供类似于requests库对http的开发体验。Mirascope的核心理念是提供恰到好处的抽象,让开发者能够以自己的方式构建LLM应用,同时保持模块化、可扩展和可靠性。MirascopeLogo......
  • Python 学生管理系统实现与详解
            在当今数字化的时代,学生管理系统对于学校和教育机构来说至关重要。它可以帮助管理人员高效地处理学生信息,提高工作效率。本文将详细介绍一个使用Python实现的学生管理系统,并对其代码进行深入分析。一、项目背景与需求        学生管理系统是为了......
  • 两句话讲清楚wsl+docker+python开发环境配置
    两句话讲清楚wsl+docker+python开发环境配置目录两句话讲清楚wsl+docker+python开发环境配置写在前面解决方案写在前面背景:win10下wsl+docker整好了之后,还要做什么,windows下载的东西怎么到docker容器里面?win->wsl->容器怎么传好使?准备先配置:wsl+docker,教程我独立出来了doc......