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
Show file tree
Hide file tree
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
Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand Down
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
Expand Up @@ -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
Expand Down
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
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions seleniumbase/plugins/driver_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
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
Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand Down
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
Expand Down
7 changes: 7 additions & 0 deletions seleniumbase/undetected/cdp_driver/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import sys
import tempfile
import zipfile
from seleniumbase.config import settings
from typing import Union, List, Optional

__all__ = [
Expand Down Expand Up @@ -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",
Expand Down
10 changes: 9 additions & 1 deletion seleniumbase/undetected/cdp_driver/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down Expand Up @@ -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(
Expand Down
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
Expand Down
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
Expand Down Expand Up @@ -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"]
Expand Down
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
Expand Down
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
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down