fengmiguoji commited on
Commit
3d3ddbc
·
verified ·
1 Parent(s): 59e1052

Upload 4 files

Browse files
src/browser/__init__.py CHANGED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # @Time : 2025/1/1
3
+ # @Author : wenshao
4
+ # @Email : wenshaoguo1026@gmail.com
5
+ # @Project : browser-use-webui
6
+ # @FileName: __init__.py.py
src/browser/config.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # @Time : 2025/1/6
3
+ # @Author : wenshao
4
+ # @ProjectName: browser-use-webui
5
+ # @FileName: config.py
6
+
7
+ import os
8
+ from dataclasses import dataclass
9
+ from typing import Optional
10
+
11
+
12
+ @dataclass
13
+ class BrowserPersistenceConfig:
14
+ """Configuration for browser persistence"""
15
+
16
+ persistent_session: bool = False
17
+ user_data_dir: Optional[str] = None
18
+ debugging_port: Optional[int] = None
19
+ debugging_host: Optional[str] = None
20
+
21
+ @classmethod
22
+ def from_env(cls) -> "BrowserPersistenceConfig":
23
+ """Create config from environment variables"""
24
+ return cls(
25
+ persistent_session=os.getenv("CHROME_PERSISTENT_SESSION", "").lower()
26
+ == "true",
27
+ user_data_dir=os.getenv("CHROME_USER_DATA"),
28
+ debugging_port=int(os.getenv("CHROME_DEBUGGING_PORT", "9222")),
29
+ debugging_host=os.getenv("CHROME_DEBUGGING_HOST", "localhost"),
30
+ )
src/browser/custom_browser.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # @Time : 2025/1/2
3
+ # @Author : wenshao
4
+ # @ProjectName: browser-use-webui
5
+ # @FileName: browser.py
6
+
7
+ import asyncio
8
+
9
+ from playwright.async_api import Browser as PlaywrightBrowser
10
+ from playwright.async_api import (
11
+ BrowserContext as PlaywrightBrowserContext,
12
+ )
13
+ from playwright.async_api import (
14
+ Playwright,
15
+ async_playwright,
16
+ )
17
+ from browser_use.browser.browser import Browser
18
+ from browser_use.browser.context import BrowserContext, BrowserContextConfig
19
+ from playwright.async_api import BrowserContext as PlaywrightBrowserContext
20
+ import logging
21
+
22
+ from .config import BrowserPersistenceConfig
23
+ from .custom_context import CustomBrowserContext
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ class CustomBrowser(Browser):
28
+
29
+ async def new_context(
30
+ self,
31
+ config: BrowserContextConfig = BrowserContextConfig()
32
+ ) -> CustomBrowserContext:
33
+ return CustomBrowserContext(config=config, browser=self)
34
+
35
+ async def _setup_browser(self, playwright: Playwright) -> PlaywrightBrowser:
36
+ """Sets up and returns a Playwright Browser instance with anti-detection measures."""
37
+ if self.config.wss_url:
38
+ browser = await playwright.chromium.connect(self.config.wss_url)
39
+ return browser
40
+ elif self.config.chrome_instance_path:
41
+ import subprocess
42
+
43
+ import requests
44
+
45
+ try:
46
+ # Check if browser is already running
47
+ response = requests.get('http://localhost:9222/json/version', timeout=2)
48
+ if response.status_code == 200:
49
+ logger.info('Reusing existing Chrome instance')
50
+ browser = await playwright.chromium.connect_over_cdp(
51
+ endpoint_url='http://localhost:9222',
52
+ timeout=20000, # 20 second timeout for connection
53
+ )
54
+ return browser
55
+ except requests.ConnectionError:
56
+ logger.debug('No existing Chrome instance found, starting a new one')
57
+
58
+ # Start a new Chrome instance
59
+ subprocess.Popen(
60
+ [
61
+ self.config.chrome_instance_path,
62
+ '--remote-debugging-port=9222',
63
+ ],
64
+ stdout=subprocess.DEVNULL,
65
+ stderr=subprocess.DEVNULL,
66
+ )
67
+
68
+ # Attempt to connect again after starting a new instance
69
+ for _ in range(10):
70
+ try:
71
+ response = requests.get('http://localhost:9222/json/version', timeout=2)
72
+ if response.status_code == 200:
73
+ break
74
+ except requests.ConnectionError:
75
+ pass
76
+ await asyncio.sleep(1)
77
+
78
+ try:
79
+ browser = await playwright.chromium.connect_over_cdp(
80
+ endpoint_url='http://localhost:9222',
81
+ timeout=20000, # 20 second timeout for connection
82
+ )
83
+ return browser
84
+ except Exception as e:
85
+ logger.error(f'Failed to start a new Chrome instance.: {str(e)}')
86
+ raise RuntimeError(
87
+ ' To start chrome in Debug mode, you need to close all existing Chrome instances and try again otherwise we can not connect to the instance.'
88
+ )
89
+
90
+ else:
91
+ try:
92
+ disable_security_args = []
93
+ if self.config.disable_security:
94
+ disable_security_args = [
95
+ '--disable-web-security',
96
+ '--disable-site-isolation-trials',
97
+ '--disable-features=IsolateOrigins,site-per-process',
98
+ ]
99
+
100
+ browser = await playwright.chromium.launch(
101
+ headless=self.config.headless,
102
+ args=[
103
+ '--no-sandbox',
104
+ '--disable-blink-features=AutomationControlled',
105
+ '--disable-infobars',
106
+ '--disable-background-timer-throttling',
107
+ '--disable-popup-blocking',
108
+ '--disable-backgrounding-occluded-windows',
109
+ '--disable-renderer-backgrounding',
110
+ '--disable-window-activation',
111
+ '--disable-focus-on-load',
112
+ '--no-first-run',
113
+ '--no-default-browser-check',
114
+ '--no-startup-window',
115
+ '--window-position=0,0',
116
+ # '--window-size=1280,1000',
117
+ ]
118
+ + disable_security_args
119
+ + self.config.extra_chromium_args,
120
+ proxy=self.config.proxy,
121
+ )
122
+
123
+ return browser
124
+ except Exception as e:
125
+ logger.error(f'Failed to initialize Playwright browser: {str(e)}')
126
+ raise
src/browser/custom_context.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # @Time : 2025/1/1
3
+ # @Author : wenshao
4
+ # @Email : wenshaoguo1026@gmail.com
5
+ # @Project : browser-use-webui
6
+ # @FileName: context.py
7
+
8
+ import json
9
+ import logging
10
+ import os
11
+
12
+ from browser_use.browser.browser import Browser
13
+ from browser_use.browser.context import BrowserContext, BrowserContextConfig
14
+ from playwright.async_api import Browser as PlaywrightBrowser
15
+ from playwright.async_api import BrowserContext as PlaywrightBrowserContext
16
+
17
+ from .config import BrowserPersistenceConfig
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class CustomBrowserContext(BrowserContext):
22
+ def __init__(
23
+ self,
24
+ browser: "Browser",
25
+ config: BrowserContextConfig = BrowserContextConfig()
26
+ ):
27
+ super(CustomBrowserContext, self).__init__(browser=browser, config=config)
28
+
29
+ async def _create_context(self, browser: PlaywrightBrowser) -> PlaywrightBrowserContext:
30
+ """Creates a new browser context with anti-detection measures and loads cookies if available."""
31
+ # If we have a context, return it directly
32
+
33
+ # Check if we should use existing context for persistence
34
+ if self.browser.config.chrome_instance_path and len(browser.contexts) > 0:
35
+ # Connect to existing Chrome instance instead of creating new one
36
+ context = browser.contexts[0]
37
+ else:
38
+ # Original code for creating new context
39
+ context = await browser.new_context(
40
+ viewport=self.config.browser_window_size,
41
+ no_viewport=False,
42
+ user_agent=(
43
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
44
+ "(KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"
45
+ ),
46
+ java_script_enabled=True,
47
+ bypass_csp=self.config.disable_security,
48
+ ignore_https_errors=self.config.disable_security,
49
+ record_video_dir=self.config.save_recording_path,
50
+ record_video_size=self.config.browser_window_size,
51
+ )
52
+
53
+ if self.config.trace_path:
54
+ await context.tracing.start(screenshots=True, snapshots=True, sources=True)
55
+
56
+ # Load cookies if they exist
57
+ if self.config.cookies_file and os.path.exists(self.config.cookies_file):
58
+ with open(self.config.cookies_file, "r") as f:
59
+ cookies = json.load(f)
60
+ logger.info(
61
+ f"Loaded {len(cookies)} cookies from {self.config.cookies_file}"
62
+ )
63
+ await context.add_cookies(cookies)
64
+
65
+ # Expose anti-detection scripts
66
+ await context.add_init_script(
67
+ """
68
+ // Webdriver property
69
+ Object.defineProperty(navigator, 'webdriver', {
70
+ get: () => undefined
71
+ });
72
+
73
+ // Languages
74
+ Object.defineProperty(navigator, 'languages', {
75
+ get: () => ['en-US', 'en']
76
+ });
77
+
78
+ // Plugins
79
+ Object.defineProperty(navigator, 'plugins', {
80
+ get: () => [1, 2, 3, 4, 5]
81
+ });
82
+
83
+ // Chrome runtime
84
+ window.chrome = { runtime: {} };
85
+
86
+ // Permissions
87
+ const originalQuery = window.navigator.permissions.query;
88
+ window.navigator.permissions.query = (parameters) => (
89
+ parameters.name === 'notifications' ?
90
+ Promise.resolve({ state: Notification.permission }) :
91
+ originalQuery(parameters)
92
+ );
93
+ """
94
+ )
95
+
96
+ return context