4
4
# @ProjectName: browser-use-webui
5
5
# @FileName: browser.py
6
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
+ )
7
17
from browser_use .browser .browser import Browser
8
18
from browser_use .browser .context import BrowserContext , BrowserContextConfig
9
19
from playwright .async_api import BrowserContext as PlaywrightBrowserContext
15
25
logger = logging .getLogger (__name__ )
16
26
17
27
class CustomBrowser (Browser ):
18
- _global_context = None
19
28
20
29
async def new_context (
21
30
self ,
22
- config : BrowserContextConfig = BrowserContextConfig (),
23
- context : PlaywrightBrowserContext = None ,
31
+ config : BrowserContextConfig = BrowserContextConfig ()
24
32
) -> CustomBrowserContext :
25
- """Create a browser context with persistence support"""
26
- persistence_config = BrowserPersistenceConfig .from_env ()
27
-
28
- if persistence_config .persistent_session :
29
- if CustomBrowser ._global_context is not None :
30
- logger .info ("Reusing existing persistent browser context" )
31
- return CustomBrowser ._global_context
32
-
33
- context_instance = CustomBrowserContext (config = config , browser = self , context = context )
34
- CustomBrowser ._global_context = context_instance
35
- logger .info ("Created new persistent browser context" )
36
- return context_instance
37
-
38
- logger .info ("Creating non-persistent browser context" )
39
- return CustomBrowserContext (config = config , browser = self , context = context )
40
-
41
- async def close (self ):
42
- """Override close to respect persistence setting"""
43
- persistence_config = BrowserPersistenceConfig .from_env ()
44
- if not persistence_config .persistent_session :
45
- if CustomBrowser ._global_context is not None :
46
- await CustomBrowser ._global_context .close ()
47
- CustomBrowser ._global_context = None
48
- await super ().close ()
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
+
49
90
else :
50
- logger .info ("Skipping browser close due to persistent session" )
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
0 commit comments