Skip to content

CDP Mode - Patch 4 #3232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 45 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -62,6 +62,8 @@

👤 Note that <span translate="no">SeleniumBase</span> <a translate="no" href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/uc_mode.md"><b>UC Mode</b> (Stealth Mode) has its own ReadMe</a>.

🐙 Also note that Seleniumbase <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md"><b>CDP Mode</b> has its own separate ReadMe</a>.

ℹ️ Scripts can be called via <code translate="no"><b>python</b></code>, although some <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md">Syntax Formats</a> expect <a href="https://docs.pytest.org/en/latest/how-to/usage.html" translate="no"><b>pytest</b></a> (a Python unit-testing framework included with SeleniumBase that can discover, collect, and run tests automatically).

<p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py">my_first_test.py</a>, which tests login, shopping, and checkout:</p>
@@ -315,48 +317,49 @@ pip install -e .
🔵 **Type ``seleniumbase`` or ``sbase`` to verify that SeleniumBase was installed successfully:**

```bash
______ __ _ ____
/ ____/__ / /__ ____ (_)_ ______ ___ / _ \____ ________
\__ \/ _ \/ / _ \/ __ \/ / / / / __ `__ \ / /_) / __ \/ ___/ _ \
___/ / __/ / __/ / / / / /_/ / / / / / // /_) / (_/ /__ / __/
/____/\___/_/\___/_/ /_/_/\__,_/_/ /_/ /_//_____/\__,_/____/\___/
------------------------------------------------------------------

* USAGE: "seleniumbase [COMMAND] [PARAMETERS]"
* OR: "sbase [COMMAND] [PARAMETERS]"

COMMANDS:
get / install [DRIVER] [OPTIONS]
methods (List common Python methods)
options (List common pytest options)
behave-options (List common behave options)
gui / commander [OPTIONAL PATH or TEST FILE]
behave-gui (SBase Commander for Behave)
caseplans [OPTIONAL PATH or TEST FILE]
mkdir [DIRECTORY] [OPTIONS]
mkfile [FILE.py] [OPTIONS]
mkrec / codegen [FILE.py] [OPTIONS]
recorder (Open Recorder Desktop App.)
record (If args: mkrec. Else: App.)
mkpres [FILE.py] [LANG]
mkchart [FILE.py] [LANG]
print [FILE] [OPTIONS]
translate [SB_FILE.py] [LANG] [ACTION]
convert [WEBDRIVER_UNITTEST_FILE.py]
extract-objects [SB_FILE.py]
inject-objects [SB_FILE.py] [OPTIONS]
objectify [SB_FILE.py] [OPTIONS]
revert-objects [SB_FILE.py] [OPTIONS]
encrypt / obfuscate
decrypt / unobfuscate
download server (Get Selenium Grid JAR file)
grid-hub [start|stop] [OPTIONS]
grid-node [start|stop] --hub=[HOST/IP]
* (EXAMPLE: "sbase get chromedriver latest") *

Type "sbase help [COMMAND]" for specific command info.
For info on all commands, type: "seleniumbase --help".
Use "pytest" for running tests.
___ _ _ ___
/ __| ___| |___ _ _ (_)_ _ _ __ | _ ) __ _ ______
\__ \/ -_) / -_) ' \| | \| | ' \ | _ \/ _` (_-< -_)
|___/\___|_\___|_||_|_|\_,_|_|_|_\|___/\__,_/__|___|
----------------------------------------------------

╭──────────────────────────────────────────────────╮
│ * USAGE: "seleniumbase [COMMAND] [PARAMETERS]" │
│ * OR: "sbase [COMMAND] [PARAMETERS]" │
│ │
│ COMMANDS: PARAMETERS / DESCRIPTIONS: │
│ get / install [DRIVER_NAME] [OPTIONS] │
│ methods (List common Python methods) │
│ options (List common pytest options) │
│ behave-options (List common behave options) │
│ gui / commander [OPTIONAL PATH or TEST FILE] │
│ behave-gui (SBase Commander for Behave) │
│ caseplans [OPTIONAL PATH or TEST FILE] │
│ mkdir [DIRECTORY] [OPTIONS] │
│ mkfile [FILE.py] [OPTIONS] │
│ mkrec / codegen [FILE.py] [OPTIONS] │
│ recorder (Open Recorder Desktop App.) │
│ record (If args: mkrec. Else: App.) │
│ mkpres [FILE.py] [LANG] │
│ mkchart [FILE.py] [LANG] │
│ print [FILE] [OPTIONS] │
│ translate [SB_FILE.py] [LANG] [ACTION] │
│ convert [WEBDRIVER_UNITTEST_FILE.py] │
│ extract-objects [SB_FILE.py] │
│ inject-objects [SB_FILE.py] [OPTIONS] │
│ objectify [SB_FILE.py] [OPTIONS] │
│ revert-objects [SB_FILE.py] [OPTIONS] │
│ encrypt / obfuscate │
│ decrypt / unobfuscate │
│ proxy (Start a basic proxy server) │
│ download server (Get Selenium Grid JAR file) │
│ grid-hub [start|stop] [OPTIONS] │
│ grid-node [start|stop] --hub=[HOST/IP] │
│ │
│ * EXAMPLE => "sbase get chromedriver stable" │
│ * For command info => "sbase help [COMMAND]" │
│ * For info on all commands => "sbase --help" │
╰──────────────────────────────────────────────────╯
```

<h3>🔵 Downloading webdrivers:</h3>
@@ -1375,7 +1378,6 @@ pytest --reruns=1 --reruns-delay=1
<span><a href="https://github.com/seleniumbase/SeleniumBase"><img src="https://seleniumbase.github.io/img/social/share_github.svg" title="SeleniumBase on GitHub" alt="SeleniumBase on GitHub" width="64" /></a></span>
<span><a href="https://discord.gg/EdhQTn3EyE"><img src="https://seleniumbase.github.io/other/discord_icon.png" title="SeleniumBase on Discord" alt="SeleniumBase on Discord" width="66" /></a></span>
<span><a href="https://www.facebook.com/SeleniumBase"><img src="https://seleniumbase.io/img/social/share_facebook.svg" title="SeleniumBase on Facebook" alt="SeleniumBase on Facebook" width="62" /></a></span>
<span><a href="https://gitter.im/seleniumbase/SeleniumBase" target="_blank"><img src="https://seleniumbase.github.io/img/social/share_gitter.svg" title="SeleniumBase on Gitter" alt="SeleniumBase on Gitter" width="48" /></a></span>
</div></p>

<p><div><b><a href="https://github.com/mdmintz">https://github.com/mdmintz</a></b></div></p>
16 changes: 16 additions & 0 deletions examples/cdp_mode/raw_antibot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from seleniumbase import SB

with SB(uc=True, test=True) as sb:
url = "https://seleniumbase.io/antibot/login"
sb.activate_cdp_mode(url)
sb.press_keys("input#username", "demo_user")
sb.press_keys("input#password", "secret_pass")
x, y = sb.cdp.get_gui_element_center("button#myButton")
sb.uc_gui_click_x_y(x, y)
sb.sleep(1.5)
x, y = sb.cdp.get_gui_element_center("a#log-in")
sb.uc_gui_click_x_y(x, y)
sb.assert_text("Welcome!", "h1")
sb.set_messenger_theme(location="bottom_center")
sb.post_message("SeleniumBase wasn't detected!")
sb.sleep(1.5)
11 changes: 11 additions & 0 deletions examples/cdp_mode/raw_gitlab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from seleniumbase import SB

with SB(uc=True, test=True, locale_code="en") as sb:
url = "https://gitlab.com/users/sign_in"
sb.activate_cdp_mode(url)
sb.uc_gui_click_captcha()
sb.assert_text("Username", '[for="user_login"]', timeout=3)
sb.assert_element('label[for="user_login"]')
sb.highlight('button:contains("Sign in")')
sb.highlight('h1:contains("GitLab.com")')
sb.post_message("SeleniumBase wasn't detected", duration=4)
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -21,8 +21,8 @@ colorama>=0.4.6
pyyaml>=6.0.2
pygments>=2.18.0
pyreadline3>=3.5.3;platform_system=="Windows"
tabcompleter>=1.3.3
pdbp>=1.5.4
tabcompleter>=1.4.0
pdbp>=1.6.0
idna==3.10
chardet==5.2.0
charset-normalizer==3.4.0
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.32.3"
__version__ = "4.32.4"
1 change: 1 addition & 0 deletions seleniumbase/core/browser_launcher.py
Original file line number Diff line number Diff line change
@@ -542,6 +542,7 @@ def uc_open_with_cdp_mode(driver, url=None):
driver.cdp_base = loop.run_until_complete(
cdp_util.start(host=cdp_host, port=cdp_port)
)

page = loop.run_until_complete(driver.cdp_base.get(url))
loop.run_until_complete(page.activate())
if not safe_url:
4 changes: 2 additions & 2 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
@@ -4167,13 +4167,13 @@ def get_new_driver(
device_pixel_ratio=d_p_r,
browser=browser_name,
)
time.sleep(0.2)
time.sleep(0.16)
except Exception:
pass
finally:
with suppress(Exception):
decoy_driver.quit()
time.sleep(0.1)
time.sleep(0.08)
# Launch a web browser
new_driver = browser_launcher.get_driver(
browser_name=browser_name,
4 changes: 2 additions & 2 deletions seleniumbase/plugins/driver_manager.py
Original file line number Diff line number Diff line change
@@ -870,13 +870,13 @@ def Driver(
device_pixel_ratio=d_p_r,
browser=browser_name,
)
time.sleep(0.2)
time.sleep(0.16)
except Exception:
pass
finally:
with suppress(Exception):
decoy_driver.quit()
time.sleep(0.1)
time.sleep(0.08)

driver = browser_launcher.get_driver(
browser_name=browser_name,
19 changes: 13 additions & 6 deletions seleniumbase/undetected/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
import logging
import os
import re
@@ -433,10 +432,15 @@ def reconnect(self, timeout=0.1):
time.sleep(timeout)
with suppress(Exception):
self.service.start()
time.sleep(0.012)
with suppress(Exception):
self.start_session()
time.sleep(0.012)
with suppress(Exception):
if self.current_url.startswith("chrome-extension://"):
self.close()
self.service.stop()
self.service.start()
self.start_session()
self._is_connected = True

def disconnect(self):
"""Stops the chromedriver service that runs in the background.
@@ -445,19 +449,22 @@ def disconnect(self):
with suppress(Exception):
self.service.stop()
self._is_connected = False
time.sleep(0.012)

def connect(self):
"""Starts the chromedriver service that runs in the background
and recreates the session."""
if hasattr(self, "service"):
with suppress(Exception):
self.service.start()
time.sleep(0.012)
with suppress(Exception):
self.start_session()
with suppress(Exception):
if self.current_url.startswith("chrome-extension://"):
self.close()
self.service.stop()
self.service.start()
self.start_session()
self._is_connected = True
time.sleep(0.012)

def start_session(self, capabilities=None):
if not capabilities:
1 change: 0 additions & 1 deletion seleniumbase/undetected/cdp.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
import fasteners
import json
import logging
7 changes: 7 additions & 0 deletions seleniumbase/undetected/cdp_driver/config.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
import sys
import tempfile
import zipfile
from seleniumbase.config import settings
from typing import Union, List, Optional

__all__ = [
@@ -101,7 +102,13 @@ def __init__(
# Other keyword args will be accessible by attribute
self.__dict__.update(kwargs)
super().__init__()
start_width = settings.CHROME_START_WIDTH
start_height = settings.CHROME_START_HEIGHT
start_x = settings.WINDOW_START_X
start_y = settings.WINDOW_START_Y
self._default_browser_args = [
"--window-size=%s,%s" % (start_width, start_height),
"--window-position=%s,%s" % (start_x, start_y),
"--remote-allow-origins=*",
"--no-first-run",
"--no-service-autorun",
10 changes: 9 additions & 1 deletion seleniumbase/undetected/cdp_driver/connection.py
Original file line number Diff line number Diff line change
@@ -292,7 +292,14 @@ async def aclose(self):
if self.listener and self.listener.running:
self.listener.cancel()
self.enabled_domains.clear()
await self.websocket.close()
await asyncio.sleep(0.015)
try:
await self.websocket.close()
except Exception:
logger.debug(
"\n❌ Error closing websocket connection to %s",
self.websocket_url
)
logger.debug(
"\n❌ Closed websocket connection to %s", self.websocket_url
)
@@ -540,6 +547,7 @@ async def listener_loop(self):
self.idle.set()
# Pause for a moment.
# await asyncio.sleep(self.time_before_considered_idle / 10)
await asyncio.sleep(0.015)
continue
except (Exception,) as e:
logger.debug(
1 change: 0 additions & 1 deletion seleniumbase/undetected/dprocess.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os
import sys
import atexit
5 changes: 3 additions & 2 deletions seleniumbase/undetected/options.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
import json
import os
from contextlib import suppress
@@ -59,7 +58,9 @@ def handle_prefs(self, user_data_dir):
json.load(f), undot_prefs
)
with suppress(Exception):
with open(prefs_file, encoding="utf-8", mode="w") as f:
with open(
prefs_file, encoding="utf-8", mode="w", errors="ignore"
) as f:
json.dump(undot_prefs, f)
# Remove experimental_options to avoid errors
del self._experimental_options["prefs"]
1 change: 0 additions & 1 deletion seleniumbase/undetected/patcher.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
import io
import logging
import os
1 change: 0 additions & 1 deletion seleniumbase/undetected/reactor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
import asyncio
import json
import logging
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -170,8 +170,8 @@
'pyyaml>=6.0.2',
'pygments>=2.18.0',
'pyreadline3>=3.5.3;platform_system=="Windows"',
"tabcompleter>=1.3.3",
"pdbp>=1.5.4",
"tabcompleter>=1.4.0",
"pdbp>=1.6.0",
"idna==3.10",
'chardet==5.2.0',
'charset-normalizer==3.4.0',