mirror of
https://github.com/NanmiCoder/MediaCrawler.git
synced 2026-07-24 13:20:36 +08:00
fix: 修复已有浏览器 CDP 连接
This commit is contained in:
95
tests/test_cdp_browser.py
Normal file
95
tests/test_cdp_browser.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
import config
|
||||
from tools.cdp_browser import CDPBrowserManager
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_existing_browser_connects_directly_to_devtools_browser(monkeypatch):
|
||||
monkeypatch.setattr(config, "CDP_CONNECT_EXISTING", True)
|
||||
monkeypatch.setattr(config, "BROWSER_LAUNCH_TIMEOUT", 60)
|
||||
|
||||
manager = CDPBrowserManager()
|
||||
manager.debug_port = 9222
|
||||
manager._get_browser_websocket_url = AsyncMock( # type: ignore[method-assign]
|
||||
side_effect=AssertionError("existing browser mode must not call /json/version")
|
||||
)
|
||||
|
||||
browser = MagicMock()
|
||||
browser.is_connected.return_value = True
|
||||
browser.contexts = []
|
||||
|
||||
playwright = MagicMock()
|
||||
playwright.chromium.connect_over_cdp = AsyncMock(return_value=browser)
|
||||
|
||||
await manager._connect_via_cdp(playwright)
|
||||
|
||||
playwright.chromium.connect_over_cdp.assert_awaited_once_with(
|
||||
"ws://localhost:9222/devtools/browser",
|
||||
timeout=60000,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_existing_browser_falls_back_to_discovered_websocket_url(monkeypatch):
|
||||
monkeypatch.setattr(config, "CDP_CONNECT_EXISTING", True)
|
||||
monkeypatch.setattr(config, "BROWSER_LAUNCH_TIMEOUT", 60)
|
||||
|
||||
manager = CDPBrowserManager()
|
||||
manager.debug_port = 9222
|
||||
manager._get_browser_websocket_url = AsyncMock( # type: ignore[method-assign]
|
||||
return_value="ws://localhost:9222/devtools/browser/generated-id"
|
||||
)
|
||||
|
||||
browser = MagicMock()
|
||||
browser.is_connected.return_value = True
|
||||
browser.contexts = []
|
||||
|
||||
playwright = MagicMock()
|
||||
playwright.chromium.connect_over_cdp = AsyncMock(
|
||||
side_effect=[RuntimeError("direct websocket failed"), browser]
|
||||
)
|
||||
|
||||
await manager._connect_via_cdp(playwright)
|
||||
|
||||
manager._get_browser_websocket_url.assert_awaited_once_with(9222)
|
||||
assert playwright.chromium.connect_over_cdp.await_args_list[0].args == (
|
||||
"ws://localhost:9222/devtools/browser",
|
||||
)
|
||||
assert playwright.chromium.connect_over_cdp.await_args_list[0].kwargs == {
|
||||
"timeout": 60000,
|
||||
}
|
||||
assert playwright.chromium.connect_over_cdp.await_args_list[1].args == (
|
||||
"ws://localhost:9222/devtools/browser/generated-id",
|
||||
)
|
||||
assert playwright.chromium.connect_over_cdp.await_args_list[1].kwargs == {
|
||||
"timeout": 60000,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_launched_browser_uses_discovered_websocket_url(monkeypatch):
|
||||
monkeypatch.setattr(config, "CDP_CONNECT_EXISTING", False)
|
||||
|
||||
manager = CDPBrowserManager()
|
||||
manager.debug_port = 9223
|
||||
manager._get_browser_websocket_url = AsyncMock( # type: ignore[method-assign]
|
||||
return_value="ws://localhost:9223/devtools/browser/generated-id"
|
||||
)
|
||||
|
||||
browser = MagicMock()
|
||||
browser.is_connected.return_value = True
|
||||
browser.contexts = []
|
||||
|
||||
playwright = MagicMock()
|
||||
playwright.chromium.connect_over_cdp = AsyncMock(return_value=browser)
|
||||
|
||||
await manager._connect_via_cdp(playwright)
|
||||
|
||||
manager._get_browser_websocket_url.assert_awaited_once_with(9223)
|
||||
playwright.chromium.connect_over_cdp.assert_awaited_once_with(
|
||||
"ws://localhost:9223/devtools/browser/generated-id"
|
||||
)
|
||||
@@ -316,16 +316,29 @@ class CDPBrowserManager:
|
||||
"""
|
||||
try:
|
||||
if config.CDP_CONNECT_EXISTING:
|
||||
# Existing Chrome exposes the browser websocket URL from /json/version.
|
||||
# Newer Chrome versions return a UUID path instead of plain /devtools/browser.
|
||||
ws_url = await self._get_browser_websocket_url(self.debug_port)
|
||||
# Existing browser remote debugging in Chrome 136+ does not expose
|
||||
# /json/version. Connect directly and wait for user confirmation.
|
||||
ws_url = f"ws://localhost:{self.debug_port}/devtools/browser"
|
||||
utils.logger.info(f"[CDPBrowserManager] Connecting to existing browser via CDP: {ws_url}")
|
||||
utils.logger.info(
|
||||
"[CDPBrowserManager] Please check your browser for a confirmation dialog and accept it"
|
||||
)
|
||||
self.browser = await playwright.chromium.connect_over_cdp(
|
||||
ws_url, timeout=config.BROWSER_LAUNCH_TIMEOUT * 1000
|
||||
)
|
||||
try:
|
||||
self.browser = await playwright.chromium.connect_over_cdp(
|
||||
ws_url, timeout=config.BROWSER_LAUNCH_TIMEOUT * 1000
|
||||
)
|
||||
except Exception as direct_error:
|
||||
utils.logger.warning(
|
||||
"[CDPBrowserManager] Direct existing-browser CDP connection failed: "
|
||||
f"{direct_error}. Trying /json/version discovery..."
|
||||
)
|
||||
ws_url = await self._get_browser_websocket_url(self.debug_port)
|
||||
utils.logger.info(
|
||||
f"[CDPBrowserManager] Connecting to existing browser via discovered CDP: {ws_url}"
|
||||
)
|
||||
self.browser = await playwright.chromium.connect_over_cdp(
|
||||
ws_url, timeout=config.BROWSER_LAUNCH_TIMEOUT * 1000
|
||||
)
|
||||
else:
|
||||
# For launched browser, get WebSocket URL first
|
||||
ws_url = await self._get_browser_websocket_url(self.debug_port)
|
||||
|
||||
Reference in New Issue
Block a user