最近搞一个自动化小工具, 主要是控制浏览器干一些事情,最开始使用 Selenium 实现。
其中要用到了一些网络监听相关的功能。期间翻了很多博客,发现这些博客记录的信息都太累赘(使用不再维护的 Selenium-Wire 或者跑一个内置的代理服务器监听之类的)或太古老了(很早的实现方式,新版本 API 作了修改),完全用不了。
最终在仔细研究了几遍官网文档和外网的零星资料之后,终于是吧这个功能实现了。鉴于国内还没有很多这方面的信息,特此记录一下。
PS:后来还要实现通过浏览器下载文件的效果,这个时候发现了行业新秀
Playwright,这玩意对于这个场景太合适了,可以监控文件下载结果,这一点完全碾压Selenium。
环境信息:
- Windows:10
- Python:3.14.0
- Selenium:4.40.0
- Chrome:144.x
演示代码
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.devtools.v144 import network
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.remote import websocket_connection
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 开发者功能 - 开启网络监控
def enabled_network_monitor(connection: websocket_connection.WebSocketConnection) -> int:
connection.execute(network.enable())
connection.execute(network.set_request_interception(
(network.RequestPattern(url_pattern='*', interception_stage=network.InterceptionStage.HEADERS_RECEIVED),),
))
return connection.add_callback(network.RequestIntercepted, _handle_request_intercepted)
# 开发者功能 - 关闭网络监控
def disabled_network_monitor(connection: websocket_connection.WebSocketConnection, intercepted_request_id: int):
connection.remove_callback(network.RequestIntercepted, intercepted_request_id)
connection.execute(network.set_request_interception([]))
connection.execute(network.disable())
# 开发者功能 - 处理请求拦截
def _handle_request_intercepted(event: network.RequestIntercepted):
print(f'请求拦截: {event.request.method} - {event.request.url}, 响应结果: {event.response_status_code}, 是否下载: {event.is_download}')
connection.execute(network.continue_intercepted_request(
interception_id=event.interception_id
))
# 等待元素可见
def wait_until_element_visible(driver, locator, timeout=10):
try:
element = WebDriverWait(driver, timeout).until(
EC.visibility_of_element_located(locator)
)
return element
except:
return None
# 创建浏览器对象
# 组件下载地址: https://developer.chrome.google.cn/docs/chromedriver?hl=zh-cn
options = webdriver.ChromeOptions()
options.add_argument('--start-maximized')
options.binary_location = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
service = ChromeService(executable_path='chromedriver.exe')
driver = webdriver.Chrome(options=options, service=service)
# 开启 DevTools
devtools, connection = driver.start_devtools()
intercepted_request_id = enabled_network_monitor(connection)
# 访问博客
driver.get('https://6xyun.cn')
# 等待文章加载完成
wait_until_element_visible(driver, By.CSS_SELECTOR, 'body > div.container.use-motion > main > div > div.content-wrap > div > article')
# 找到归档按钮
archives_button = driver.find_element(By.CSS_SELECTOR, '#menu > li.menu-item.menu-item-archives > a')
archives_button.click()
# 等待文章加载完成
wait_until_element_visible(driver, By.CSS_SELECTOR, 'body > div.container.use-motion > main > div > div.content-wrap > div > nav')
# 查找当前页面所有文章
articles = driver.find_elements(By.XPATH, '/html/body/div[2]/main/div/div[1]/div/div/div/article')
for article in articles:
date = article.find_element(By.CSS_SELECTOR, 'header > div.post-meta > time').get_attribute('content')
title = article.find_element(By.CSS_SELECTOR, 'header > div.post-title > a > span').get_attribute('textContent').strip()
url = article.find_element(By.CSS_SELECTOR, 'header > div.post-title > a').get_attribute('href')
print(f'时间:{date}, 标题:{title}, 链接:{url}')
time.sleep(10)
# 关闭网络监控
disabled_network_monitor(connection, intercepted_request_id)
# 关闭浏览器
driver.quit()
注意事项
- 驱动版本需要和浏览器匹配,否则启动不了