Skip to content

Commit a71c58a

Browse files
committed
Add support for automating A.I. browsers
1 parent d47dac2 commit a71c58a

File tree

5 files changed

+282
-48
lines changed

5 files changed

+282
-48
lines changed

seleniumbase/core/browser_launcher.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2396,6 +2396,19 @@ def _set_chrome_options(
23962396
and not recorder_ext
23972397
and (not extension_zip and not extension_dir)
23982398
):
2399+
if (
2400+
binary_location
2401+
and isinstance(binary_location, str)
2402+
and (
2403+
binary_location.lower().endswith("comet")
2404+
or binary_location.lower().endswith("comet.exe")
2405+
or binary_location.lower().endswith("atlas")
2406+
or binary_location.lower().endswith("atlas.exe")
2407+
)
2408+
):
2409+
# AI browsers don't like Incognito / Guest Mode
2410+
incognito = False
2411+
guest_mode = False
23992412
if incognito:
24002413
# Use Chrome's Incognito Mode
24012414
# Incognito Mode prevents Chrome extensions from loading,

seleniumbase/core/detect_b_ver.py

Lines changed: 214 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ class OSType(object):
4040
class ChromeType(object):
4141
GOOGLE = "google-chrome"
4242
MSEDGE = "edge"
43+
OPERA = "opera"
44+
BRAVE = "brave"
45+
COMET = "comet"
46+
ATLAS = "atlas"
4347

4448

4549
PATTERN = {
@@ -96,7 +100,9 @@ def linux_browser_apps_to_cmd(*apps):
96100
)
97101

98102

99-
def chrome_on_linux_path(chromium_ok=False):
103+
def chrome_on_linux_path(chromium_ok=False, browser_type=None):
104+
if browser_type and browser_type != ChromeType.GOOGLE:
105+
return ""
100106
if os_name() != OSType.LINUX:
101107
return ""
102108
paths = ["/bin/google-chrome", "/bin/google-chrome-stable"]
@@ -126,7 +132,9 @@ def chrome_on_linux_path(chromium_ok=False):
126132
return "/usr/bin/google-chrome"
127133

128134

129-
def edge_on_linux_path():
135+
def edge_on_linux_path(browser_type=None):
136+
if browser_type and browser_type != ChromeType.MSEDGE:
137+
return ""
130138
if os_name() != OSType.LINUX:
131139
return ""
132140
paths = os.environ["PATH"].split(os.pathsep)
@@ -143,7 +151,60 @@ def edge_on_linux_path():
143151
return "/usr/bin/microsoft-edge"
144152

145153

146-
def chrome_on_windows_path():
154+
def opera_on_linux_path(browser_type=None):
155+
if browser_type and browser_type != ChromeType.OPERA:
156+
return ""
157+
if os_name() != OSType.LINUX:
158+
return ""
159+
paths = os.environ["PATH"].split(os.pathsep)
160+
binaries = []
161+
binaries.append("opera")
162+
binaries.append("opera-stable")
163+
for binary in binaries:
164+
for path in paths:
165+
full_path = os.path.join(path, binary)
166+
if os.path.exists(full_path) and os.access(full_path, os.X_OK):
167+
return full_path
168+
return "/usr/bin/opera-stable"
169+
170+
171+
def brave_on_linux_path(browser_type=None):
172+
if browser_type and browser_type != ChromeType.BRAVE:
173+
return ""
174+
if os_name() != OSType.LINUX:
175+
return ""
176+
paths = os.environ["PATH"].split(os.pathsep)
177+
binaries = []
178+
binaries.append("brave-browser")
179+
binaries.append("brave")
180+
binaries.append("brave-browser-stable")
181+
for binary in binaries:
182+
for path in paths:
183+
full_path = os.path.join(path, binary)
184+
if os.path.exists(full_path) and os.access(full_path, os.X_OK):
185+
return full_path
186+
return "/usr/bin/brave-browser"
187+
188+
189+
def comet_on_linux_path(browser_type=None):
190+
if browser_type and browser_type != ChromeType.COMET:
191+
return ""
192+
if os_name() != OSType.LINUX:
193+
return ""
194+
return "" # Comet Browser isn't supported on Linux yet
195+
196+
197+
def atlas_on_linux_path(browser_type=None):
198+
if browser_type and browser_type != ChromeType.ATLAS:
199+
return ""
200+
if os_name() != OSType.LINUX:
201+
return ""
202+
return "" # Atlas Browser isn't supported on Linux yet
203+
204+
205+
def chrome_on_windows_path(browser_type=None):
206+
if browser_type and browser_type != ChromeType.GOOGLE:
207+
return ""
147208
if os_name() != OSType.WIN:
148209
return ""
149210
candidates = []
@@ -171,7 +232,9 @@ def chrome_on_windows_path():
171232
return ""
172233

173234

174-
def edge_on_windows_path():
235+
def edge_on_windows_path(browser_type=None):
236+
if browser_type and browser_type != ChromeType.MSEDGE:
237+
return ""
175238
if os_name() != OSType.WIN:
176239
return ""
177240
candidates = []
@@ -199,6 +262,119 @@ def edge_on_windows_path():
199262
return ""
200263

201264

265+
def opera_on_windows_path(browser_type=None):
266+
if browser_type and browser_type != ChromeType.OPERA:
267+
return ""
268+
if os_name() != OSType.WIN:
269+
return ""
270+
candidates = []
271+
for item in map(
272+
os.environ.get,
273+
(
274+
"PROGRAMFILES",
275+
"PROGRAMFILES(X86)",
276+
"LOCALAPPDATA",
277+
"PROGRAMW6432",
278+
),
279+
):
280+
for subitem in (
281+
"Opera",
282+
"Opera/Application",
283+
):
284+
try:
285+
candidates.append(os.sep.join((item, subitem, "launcher.exe")))
286+
except TypeError:
287+
pass
288+
for candidate in candidates:
289+
if os.path.exists(candidate) and os.access(candidate, os.X_OK):
290+
return os.path.normpath(candidate)
291+
return ""
292+
293+
294+
def brave_on_windows_path(browser_type=None):
295+
if browser_type and browser_type != ChromeType.BRAVE:
296+
return ""
297+
if os_name() != OSType.WIN:
298+
return ""
299+
candidates = []
300+
for item in map(
301+
os.environ.get,
302+
(
303+
"PROGRAMFILES",
304+
"PROGRAMFILES(X86)",
305+
"LOCALAPPDATA",
306+
"PROGRAMW6432",
307+
),
308+
):
309+
for subitem in (
310+
"BraveSoftware/Brave-Browser/Application",
311+
):
312+
try:
313+
candidates.append(os.sep.join((item, subitem, "brave.exe")))
314+
except TypeError:
315+
pass
316+
for candidate in candidates:
317+
if os.path.exists(candidate) and os.access(candidate, os.X_OK):
318+
return os.path.normpath(candidate)
319+
return ""
320+
321+
322+
def comet_on_windows_path(browser_type=None):
323+
if browser_type and browser_type != ChromeType.COMET:
324+
return ""
325+
if os_name() != OSType.WIN:
326+
return ""
327+
candidates = []
328+
for item in map(
329+
os.environ.get,
330+
(
331+
"PROGRAMFILES",
332+
"PROGRAMFILES(X86)",
333+
"LOCALAPPDATA",
334+
"PROGRAMW6432",
335+
),
336+
):
337+
for subitem in (
338+
"Comet/Application",
339+
):
340+
try:
341+
candidates.append(os.sep.join((item, subitem, "Comet.exe")))
342+
except TypeError:
343+
pass
344+
for candidate in candidates:
345+
if os.path.exists(candidate) and os.access(candidate, os.X_OK):
346+
return os.path.normpath(candidate)
347+
return ""
348+
349+
350+
def atlas_on_windows_path(browser_type=None):
351+
if browser_type and browser_type != ChromeType.ATLAS:
352+
return ""
353+
if os_name() != OSType.WIN:
354+
return ""
355+
candidates = []
356+
for item in map(
357+
os.environ.get,
358+
(
359+
"PROGRAMFILES",
360+
"PROGRAMFILES(X86)",
361+
"LOCALAPPDATA",
362+
"PROGRAMW6432",
363+
),
364+
):
365+
for subitem in (
366+
"Atlas/Application",
367+
):
368+
try:
369+
candidates.append(os.sep.join((item, subitem, "Atlas.exe")))
370+
except TypeError:
371+
pass
372+
for candidate in candidates:
373+
if os.path.exists(candidate) and os.access(candidate, os.X_OK):
374+
return os.path.normpath(candidate)
375+
return ""
376+
377+
202378
def windows_browser_apps_to_cmd(*apps):
203379
"""Create analogue of browser --version command for windows."""
204380
powershell = determine_powershell()
@@ -211,18 +387,48 @@ def windows_browser_apps_to_cmd(*apps):
211387

212388
def get_binary_location(browser_type, chromium_ok=False):
213389
"""Return the full path of the browser binary."""
390+
if browser_type.lower() == "chrome":
391+
browser_type = "google-chrome"
392+
elif browser_type.lower() == "msedge":
393+
browser_type = "edge"
394+
else:
395+
browser_type = browser_type.lower()
214396
cmd_mapping = {
215397
ChromeType.GOOGLE: {
216-
OSType.LINUX: chrome_on_linux_path(chromium_ok),
398+
OSType.LINUX: chrome_on_linux_path(chromium_ok, browser_type),
217399
OSType.MAC: r"/Applications/Google Chrome.app"
218400
r"/Contents/MacOS/Google Chrome",
219-
OSType.WIN: chrome_on_windows_path(),
401+
OSType.WIN: chrome_on_windows_path(browser_type),
220402
},
221403
ChromeType.MSEDGE: {
222-
OSType.LINUX: edge_on_linux_path(),
404+
OSType.LINUX: edge_on_linux_path(browser_type),
223405
OSType.MAC: r"/Applications/Microsoft Edge.app"
224406
r"/Contents/MacOS/Microsoft Edge",
225-
OSType.WIN: edge_on_windows_path(),
407+
OSType.WIN: edge_on_windows_path(browser_type),
408+
},
409+
ChromeType.OPERA: {
410+
OSType.LINUX: opera_on_linux_path(browser_type),
411+
OSType.MAC: r"/Applications/Opera.app"
412+
r"/Contents/MacOS/Opera",
413+
OSType.WIN: opera_on_windows_path(browser_type),
414+
},
415+
ChromeType.BRAVE: {
416+
OSType.LINUX: brave_on_linux_path(browser_type),
417+
OSType.MAC: r"/Applications/Brave Browser.app"
418+
r"/Contents/MacOS/Brave Browser",
419+
OSType.WIN: brave_on_windows_path(browser_type),
420+
},
421+
ChromeType.COMET: {
422+
OSType.LINUX: comet_on_linux_path(browser_type),
423+
OSType.MAC: r"/Applications/Comet.app"
424+
r"/Contents/MacOS/Comet",
425+
OSType.WIN: comet_on_windows_path(browser_type),
426+
},
427+
ChromeType.ATLAS: {
428+
OSType.LINUX: atlas_on_linux_path(browser_type),
429+
OSType.MAC: r"/Applications/Atlas.app"
430+
r"/Contents/MacOS/Atlas",
431+
OSType.WIN: atlas_on_windows_path(browser_type),
226432
},
227433
}
228434
return cmd_mapping[browser_type][os_name()]

seleniumbase/fixtures/constants.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,14 @@ class ValidBinaries:
406406
"brave",
407407
"opera",
408408
"opera-stable",
409+
"comet",
410+
"comet-browser",
411+
"comet-stable",
412+
"atlas",
413+
"atlas-browser",
414+
"atlas-stable",
409415
"chrome.exe", # WSL (Windows Subsystem for Linux)
416+
"chromium.exe", # WSL (Windows Subsystem for Linux)
410417
]
411418
valid_edge_binaries_on_linux = [
412419
"microsoft-edge",
@@ -424,6 +431,8 @@ class ValidBinaries:
424431
"Google Chrome Dev",
425432
"Brave Browser",
426433
"Opera",
434+
"Comet",
435+
"Atlas",
427436
]
428437
valid_edge_binaries_on_macos = [
429438
"Microsoft Edge",
@@ -434,6 +443,8 @@ class ValidBinaries:
434443
"chrome-headless-shell.exe",
435444
"brave.exe",
436445
"opera.exe",
446+
"comet.exe",
447+
"atlas.exe",
437448
]
438449
valid_edge_binaries_on_windows = [
439450
"msedge.exe",

seleniumbase/fixtures/page_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ def looks_like_a_page_url(url):
109109
navigate to the page if a URL is detected, but will instead call
110110
self.get_element(URL_AS_A_SELECTOR) if the input is not a URL."""
111111
return url.startswith((
112-
"http:", "https:", "://", "about:", "blob:", "chrome:",
112+
"http:", "https:", "://", "about:", "blob:", "chrome:", "opera:",
113113
"data:", "edge:", "file:", "view-source:", "chrome-search:",
114114
"chrome-extension:", "chrome-untrusted:", "isolated-app:",
115-
"chrome-devtools:", "devtools:"
115+
"chrome-devtools:", "devtools:", "brave:", "comet:", "atlas:"
116116
))
117117

118118

0 commit comments

Comments
 (0)