SeleniumSelenium获取Network数据(高级版)

Posted 是小菜欸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SeleniumSelenium获取Network数据(高级版)相关的知识,希望对你有一定的参考价值。

前言

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

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

应用场景

Chrome浏览器 -> 开发者工具 -> 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.py

import json
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.chrome.options import Options

caps = 
    "browserName": "chrome",
    'goog:loggingPrefs': 'performance': 'ALL'  # 开启日志性能监听

options = Options()
options.add_experimental_option("debuggerAddress", "127.0.0.1:9527")  # 指定端口为9527
browser = webdriver.Chrome(desired_capabilities=caps, options=options)  # 启动浏览器
browser.get('https://blog.csdn.net/weixin_45081575')  # 访问该url


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


performance_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

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


知识点📖

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

Chrome DevTools Protocol,简称CDP

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


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

代码解析

在上一篇文章 【Selenium】控制当前已经打开的 chrome浏览器窗口(高级版) 中,介绍了链接Chrome浏览器,这里进一步介绍。

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

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

回到上面的代码中,

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

简单理解为 开发者工具中的 performance,看下图


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

performance_log = browser.get_log('performance') 

看下图

  • 因为我们要获取的是 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

最后是获取数据包的 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

后话

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

Python爬虫 Selenium -- Selenium简介安装SeleniumSelenium基本使用

1. Selenium简介

1.1 什么是selenium?

  • Selenium是一个用于Web应用程序测试的工具。
  • Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。(这样就可以保证获取到的数据是完整的)

例如:京东秒杀的数据直接爬取是爬取不到的

import urllib.request

url = 'https://www.jd.com/'
headers = 
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'


# 因为urlopen方法中不能存储字典 所以headers不能传递进去

# 请求对象的定制
request = urllib.request.Request(url=url, headers=headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf8')

print(content)

运行结果:

  • 支持通过各种driver(FirfoxDriver,IternetExplorerDriver,OperaDriver,ChromeDriver)驱动 真实浏览器完成测试。
  • selenium也是支持无界面浏览器操作的。

1.2 为什么使用selenium?

模拟浏览器功能,自动执行网页中的js代码,实现动态加载


2. 安装selenium

操作谷歌浏览器驱动下载地址

查看谷歌浏览器版本 谷歌浏览器右上角,帮助,关于:

可以看到我的谷歌游览器版本是:98.0.4758.102(正式版本) (64 位)


下载完后解压,拖到项目目录下(也可以不拖动)

接下来我们给py环境中安装selenium


3. Selenium基本使用

selenium的使用步骤? 
	(1)导入:from selenium import webdriver 
	(2)创建谷歌浏览器操作对象: 
		path = 谷歌浏览器驱动文件路径 
		browser = webdriver.Chrome(path)3)访问网址 url = 要访问的网址 browser.get(url)

我们还是去访问京东的首页:

# (1)导入selenium
from selenium import webdriver

# (2) 创建浏览器操作对象

path = './exe/chromedriver.exe'

browser = webdriver.Chrome(path)

# (3)访问网站
url = 'https://www.jd.com/'

browser.get(url)

# page_source获取网页源码
content = browser.page_source
print(content)

运行结果:



以上是关于SeleniumSelenium获取Network数据(高级版)的主要内容,如果未能解决你的问题,请参考以下文章

SeleniumSelenium2

seleniumselenium find_element()详解

seleniumSelenium基于Python3的Web自动化测试脚本在IE上运行慢的解决方法

获取'未启用提供者| ProviderErrorprovider='network'' 调用'tracker.startListening();'即使启用了 WiFi

Selenium

获取用户的 windows 登录返回 NETWORK SERVICES