From 7eb6efe87e742efdcd5c1a97242724a313102573 Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Fri, 27 Oct 2023 03:24:30 -0400
Subject: [PATCH 01/14] Add way to generate multiple Presenter slides from one
---
seleniumbase/fixtures/base_case.py | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py
index ba42cea0264..ab18a5f0c2d 100644
--- a/seleniumbase/fixtures/base_case.py
+++ b/seleniumbase/fixtures/base_case.py
@@ -10892,7 +10892,31 @@ def add_slide(
html += "%s%s" % (add_line, content2)
html += '\n' % notes
html += "\n\n"
- self._presentation_slides[name].append(html)
+ if "" not in html and "" not in html:
+ self._presentation_slides[name].append(html)
+ else:
+ # Generate multiple slides with and
+ replacements = False
+ for num in range(32):
+ if "" % num in html and "" % num in html:
+ replacements = True
+ new_html = html
+ new_html = new_html.replace("" % num, "")
+ new_html = new_html.replace("" % num, "")
+ for num2 in range(32):
+ if num2 == num:
+ continue
+ if "" % num2 not in new_html and num2 >= 2:
+ break
+ new_html = new_html.replace("" % num2, "")
+ new_html = new_html.replace("" % num2, "")
+ self._presentation_slides[name].append(new_html)
+ else:
+ if num >= 2:
+ break
+ if not replacements:
+ # A is missing a closing tag. Do one.
+ self._presentation_slides[name].append(html)
def save_presentation(
self, name=None, filename=None, show_notes=False, interval=0
From f3e8e45521700cad900c39bb8d3e6b408dbeb154 Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Fri, 27 Oct 2023 03:25:38 -0400
Subject: [PATCH 02/14] driver.uc_click(selector) needs a backup JS option
---
seleniumbase/core/browser_launcher.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py
index 86ef44967d9..750b465a122 100644
--- a/seleniumbase/core/browser_launcher.py
+++ b/seleniumbase/core/browser_launcher.py
@@ -10,6 +10,7 @@
import urllib3
import warnings
from selenium import webdriver
+from selenium.common.exceptions import ElementClickInterceptedException
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.common.options import ArgOptions
from selenium.webdriver.common.service import utils as service_utils
@@ -429,7 +430,10 @@ def uc_click(
driver, selector, by="css selector", timeout=settings.SMALL_TIMEOUT
):
element = driver.wait_for_element(selector, by=by, timeout=timeout)
- element.uc_click()
+ try:
+ element.uc_click()
+ except ElementClickInterceptedException:
+ driver.js_click(selector, by=by, timeout=timeout)
def edgedriver_on_path():
From c44dea2d8102f3075e4649e68e2387c4bf3a80dd Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Fri, 27 Oct 2023 03:26:59 -0400
Subject: [PATCH 03/14] Refactor code for better compatibility with Appium
---
seleniumbase/fixtures/base_case.py | 109 +++++++++++++++++++++++------
1 file changed, 89 insertions(+), 20 deletions(-)
diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py
index ab18a5f0c2d..02d937701ee 100644
--- a/seleniumbase/fixtures/base_case.py
+++ b/seleniumbase/fixtures/base_case.py
@@ -406,7 +406,11 @@ def click(
self.__demo_mode_highlight_if_active(original_selector, original_by)
if scroll and not self.demo_mode and not self.slow_mode:
self.__scroll_to_element(element, selector, by)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
try:
if (
@@ -707,7 +711,11 @@ def double_click(self, selector, by="css selector", timeout=None):
timeout=timeout,
original_selector=original_selector,
)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
try:
if self.browser == "safari":
# Jump to the "except" block where the other script should work
@@ -788,7 +796,11 @@ def context_click(self, selector, by="css selector", timeout=None):
timeout=timeout,
original_selector=original_selector,
)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
try:
if self.browser == "safari":
# Jump to the "except" block where the other script should work
@@ -913,7 +925,12 @@ def update_text(
except Exception:
pass # Clearing the text field first might not be necessary
self.__demo_mode_pause_if_active(tiny=True)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ if self.demo_mode:
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
text = self.__get_type_checked_text(text)
try:
if not text.endswith("\n"):
@@ -1011,7 +1028,12 @@ def add_text(self, selector, text, by="css selector", timeout=None):
self.__demo_mode_highlight_if_active(selector, by)
if not self.demo_mode and not self.slow_mode:
self.__scroll_to_element(element, selector, by)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ if self.demo_mode:
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
text = self.__get_type_checked_text(text)
try:
if not text.endswith("\n"):
@@ -1266,11 +1288,18 @@ def go_back(self):
self.__check_scope()
if hasattr(self, "recorder_mode") and self.recorder_mode:
self.save_recorded_actions()
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
self.__last_page_load_url = None
self.driver.back()
- if pre_action_url == self.driver.current_url:
- self.driver.back() # Again because the page was redirected
+ try:
+ if pre_action_url == self.driver.current_url:
+ self.driver.back() # Again because the page was redirected
+ except Exception:
+ pass
if self.recorder_mode:
time_stamp = self.execute_script("return Date.now();")
origin = self.get_origin()
@@ -1529,8 +1558,6 @@ def click_link_text(self, link_text, timeout=None):
timeout = settings.SMALL_TIMEOUT
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
timeout = self.__get_new_timeout(timeout)
- pre_action_url = self.driver.current_url
- pre_window_count = len(self.driver.window_handles)
link_text = self.__get_type_checked_text(link_text)
if self.browser == "safari":
if self.demo_mode:
@@ -1558,7 +1585,12 @@ def click_link_text(self, link_text, timeout=None):
return
if not self.is_link_text_present(link_text):
self.wait_for_link_text_present(link_text, timeout=timeout)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
+ pre_window_count = len(self.driver.window_handles)
try:
element = self.wait_for_link_text_visible(link_text, timeout=0.2)
self.__demo_mode_highlight_if_active(link_text, by="link text")
@@ -1654,7 +1686,11 @@ def click_partial_link_text(self, partial_link_text, timeout=None):
self.wait_for_partial_link_text_present(
partial_link_text, timeout=timeout
)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
try:
element = self.wait_for_partial_link_text(
@@ -2125,7 +2161,11 @@ def click_visible_elements(
except Exception:
pass
elements = self.find_elements(selector, by=by)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
click_count = 0
for element in elements:
@@ -2207,7 +2247,11 @@ def click_nth_visible_element(
if number < 0:
number = 0
element = elements[number]
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
try:
self.__scroll_to_element(element)
@@ -2261,7 +2305,11 @@ def click_if_visible(self, selector, by="css selector", timeout=0):
def click_active_element(self):
self.wait_for_ready_state_complete()
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
if self.recorder_mode:
selector = js_utils.get_active_element_css(self.driver)
@@ -2593,7 +2641,11 @@ def hover_and_click(
)
self.__demo_mode_highlight_if_active(original_selector, original_by)
self.scroll_to(hover_selector, by=hover_by)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
if self.recorder_mode and self.__current_url_is_recordable():
if self.get_session_storage_item("pause_recorder") == "no":
@@ -2719,7 +2771,11 @@ def hover_and_double_click(
)
self.__demo_mode_highlight_if_active(original_selector, original_by)
self.scroll_to(hover_selector, by=hover_by)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
outdated_driver = False
element = None
@@ -2906,7 +2962,11 @@ def __select_option(
self.__demo_mode_highlight_if_active(
dropdown_selector, dropdown_by
)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
try:
if option_by == "index":
@@ -5802,7 +5862,11 @@ def js_click(
css_selector = self.__escape_quotes_if_needed(css_selector)
time_stamp = 0
action = ["", "", "", time_stamp]
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
pre_window_count = len(self.driver.window_handles)
if self.recorder_mode and not self.__dont_record_js_click:
time_stamp = self.execute_script("return Date.now();")
@@ -6684,7 +6748,12 @@ def choose_file(
self.__demo_mode_highlight_if_active(selector, by)
if not self.demo_mode and not self.slow_mode:
self.__scroll_to_element(element, selector, by)
- pre_action_url = self.driver.current_url
+ pre_action_url = None
+ if self.demo_mode:
+ try:
+ pre_action_url = self.driver.current_url
+ except Exception:
+ pass
if self.recorder_mode and self.__current_url_is_recordable():
if self.get_session_storage_item("pause_recorder") == "no":
time_stamp = self.execute_script("return Date.now();")
From b16cf5e6ec3041e7e2f9a6b401b9ea9e76efc1ed Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Fri, 27 Oct 2023 03:27:54 -0400
Subject: [PATCH 04/14] Update the default UC Mode reconnect time
---
seleniumbase/fixtures/constants.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/seleniumbase/fixtures/constants.py b/seleniumbase/fixtures/constants.py
index ee9c41b00b6..ee25c7dd16a 100644
--- a/seleniumbase/fixtures/constants.py
+++ b/seleniumbase/fixtures/constants.py
@@ -360,7 +360,7 @@ class Mobile:
class UC:
- RECONNECT_TIME = 2.15 # Seconds
+ RECONNECT_TIME = 2.27 # Seconds
class ValidBrowsers:
From e80fb37fbf20cad00667192746b59f8118b8e0bf Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Fri, 27 Oct 2023 03:29:24 -0400
Subject: [PATCH 05/14] Update the sample proxy list
---
seleniumbase/config/proxy_list.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/seleniumbase/config/proxy_list.py b/seleniumbase/config/proxy_list.py
index e8b5cfa269f..cdc7d923329 100644
--- a/seleniumbase/config/proxy_list.py
+++ b/seleniumbase/config/proxy_list.py
@@ -23,9 +23,9 @@
"""
PROXY_LIST = {
- "example1": "138.199.48.1:8443", # (Example) - set your own proxy here
- "example2": "socks4://167.71.100.140:55229", # (Example)
- "example3": "socks5://167.172.159.43:49633", # (Example)
+ "example1": "37.19.220.129:8443", # (Example) - set your own proxy here
+ "example2": "socks4://104.236.32.53:8915", # (Example)
+ "example3": "socks5://142.44.212.57:30439", # (Example)
"proxy1": None,
"proxy2": None,
"proxy3": None,
From c2eb2df43803af76c567c0286d449cdeecdef66d Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Fri, 27 Oct 2023 03:31:51 -0400
Subject: [PATCH 06/14] Update the documentation
---
examples/presenter/ReadMe.md | 2 --
help_docs/desired_capabilities.md | 7 +++----
help_docs/happy_customers.md | 1 +
help_docs/mysql_installation.md | 2 +-
help_docs/syntax_formats.md | 16 ++++++++--------
help_docs/using_safari_driver.md | 2 +-
help_docs/verify_webdriver.md | 1 -
7 files changed, 14 insertions(+), 17 deletions(-)
diff --git a/examples/presenter/ReadMe.md b/examples/presenter/ReadMe.md
index 16d7783d805..71ba8a7c619 100644
--- a/examples/presenter/ReadMe.md
+++ b/examples/presenter/ReadMe.md
@@ -36,7 +36,6 @@ cd examples/presenter
pytest core_presentation.py
```
-
Creating a new presentation:
```python
@@ -59,7 +58,6 @@ If creating multiple presentations at the same time, you can pass the ``name`` p
Notes are disabled by default. You can enable notes by specifying:
``show_notes=True``
-
Adding a slide to a presentation:
```python
diff --git a/help_docs/desired_capabilities.md b/help_docs/desired_capabilities.md
index 7f69f038e20..3f3f8dc1dea 100644
--- a/help_docs/desired_capabilities.md
+++ b/help_docs/desired_capabilities.md
@@ -41,7 +41,7 @@ capabilities = {
}
```
-(Note that the browser is now being specified in the capabilities file, rather than with ``--browser=BROWSER`` when using a **remote** Selenium Grid. If using a **local** Selenium Grid, specify the browser, eg: ``--browser=chrome`` or ``--browser=firefox``.)
+(Note that the browser is now being specified in the capabilities file, rather than with ``--BROWSER`` when using a **remote** Selenium Grid. If using a **local** Selenium Grid, specify the browser, eg: ``--firefox``.)
You can generate specific desired capabilities using:
@@ -65,7 +65,7 @@ caps['KEY'] = False
(Each pair must be on a separate line. You can interchange single and double quotes.)
-You can also swap ``--browser=remote`` with an actual browser, eg ``--browser=chrome``, which will combine the default SeleniumBase desired capabilities with those that were specified in the capabilities file when using ``--cap_file=FILE.py``. Capabilities will override other parameters, so if you set the browser to one thing and the capabilities browser to another, SeleniumBase will use the capabilities browser as the browser.
+You can also swap ``--browser=remote`` with an actual browser, eg ``--browser=chrome``, which will combine the default SeleniumBase desired capabilities with those that were specified in the capabilities file when using ``--cap_file=FILE.py``. Capabilities will override other parameters, so if you set the browser to one thing and the capabilities browser to another, SeleniumBase will use the capabilities browser.
You'll need default SeleniumBase capabilities for:
* Using a proxy server (not the same as a Selenium Grid server)
@@ -74,8 +74,7 @@ You'll need default SeleniumBase capabilities for:
* Overriding a website's Content Security Policy on Chrome
* Other possible reasons
-You can also set browser desired capabilities from a command line string:
-Example:
+You can also set browser desired capabilities from a command-line string. Eg:
```bash
pytest test_swag_labs.py --cap-string='{"browserName":"chrome","name":"test1"}' --server="127.0.0.1" --browser=remote
diff --git a/help_docs/happy_customers.md b/help_docs/happy_customers.md
index dbbb6acff76..b46ea3b9e1e 100644
--- a/help_docs/happy_customers.md
+++ b/help_docs/happy_customers.md
@@ -6,6 +6,7 @@
* [MIT](https://web.mit.edu/)
* [Sony](https://www.sony.com/)
+* [Tesla](https://www.tesla.com/)
* [iboss](https://www.iboss.com/)
* [Apple](https://www.apple.com/)
* [Akamai](https://www.akamai.com/)
diff --git a/help_docs/mysql_installation.md b/help_docs/mysql_installation.md
index 70ec7eea7ef..143b8465f41 100644
--- a/help_docs/mysql_installation.md
+++ b/help_docs/mysql_installation.md
@@ -87,7 +87,7 @@ Update your [settings.py](https://github.com/seleniumbase/SeleniumBase/blob/mast
### Have SeleniumBase tests write to your MySQL DB:
-Add the ``--with-db_reporting`` argument on the command line when you want tests to write to your MySQL database. Example:
+Add the ``--with-db_reporting`` argument on the command-line when you want tests to write to your MySQL database. Example:
```bash
pytest --with-db_reporting
diff --git a/help_docs/syntax_formats.md b/help_docs/syntax_formats.md
index 190645d1a92..ea04283d0c8 100644
--- a/help_docs/syntax_formats.md
+++ b/help_docs/syntax_formats.md
@@ -118,10 +118,10 @@ The pytest framework comes with a unique system called fixtures, which replaces
```python
def test_sb_fixture_with_no_class(sb):
- sb.open("https://google.com/ncr")
- sb.type('[title="Search"]', 'SeleniumBase\n')
- sb.click('a[href*="github.com/seleniumbase/SeleniumBase"]')
- sb.click('a[title="seleniumbase"]')
+ sb.open("seleniumbase.io/help_docs/install/")
+ sb.type('input[aria-label="Search"]', "GUI Commander")
+ sb.click('mark:contains("Commander")')
+ sb.assert_title_contains("GUI / Commander")
```
(See the top of examples/test_sb_fixture.py for the test.)
@@ -134,10 +134,10 @@ The sb pytest fixture can also be used inside of a c
```python
class Test_SB_Fixture:
def test_sb_fixture_inside_class(self, sb):
- sb.open("https://google.com/ncr")
- sb.type('[title="Search"]', 'SeleniumBase\n')
- sb.click('a[href*="github.com/seleniumbase/SeleniumBase"]')
- sb.click('a[title="examples"]')
+ sb.open("seleniumbase.io/help_docs/install/")
+ sb.type('input[aria-label="Search"]', "GUI Commander")
+ sb.click('mark:contains("Commander")')
+ sb.assert_title_contains("GUI / Commander")
```
(See the bottom of examples/test_sb_fixture.py for the test.)
diff --git a/help_docs/using_safari_driver.md b/help_docs/using_safari_driver.md
index df2cf282e6b..e2e77be56dd 100644
--- a/help_docs/using_safari_driver.md
+++ b/help_docs/using_safari_driver.md
@@ -8,4 +8,4 @@ You can find the official Apple documentation regarding "Testing with WebDriver
Run ``safaridriver --enable`` once in a terminal to enable Safari's WebDriver. (If youβre upgrading from a previous macOS release, you may need to prefix the command with ``sudo``.)
-Now you can use ``--browser=safari`` to run your **SeleniumBase** tests on Safari.
+Now you can use ``--safari`` to run your **SeleniumBase** tests on Safari.
diff --git a/help_docs/verify_webdriver.md b/help_docs/verify_webdriver.md
index c8abc02c761..083e5d4b6e1 100644
--- a/help_docs/verify_webdriver.md
+++ b/help_docs/verify_webdriver.md
@@ -8,7 +8,6 @@ Drivers can be manually downloaded to the ``seleniumbase/drivers`` folder with c
```bash
sbase get chromedriver
-sbase get chromedriver latest
sbase get geckodriver
sbase get edgedriver
```
From 7678d8ea20e9e2005840ffc6aab4c8c2319942eb Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Fri, 27 Oct 2023 03:33:13 -0400
Subject: [PATCH 07/14] Update existing presentations
---
examples/presenter/edge_presentation.py | 158 ++++--------------------
examples/presenter/fundamentals.py | 151 ++++------------------
2 files changed, 52 insertions(+), 257 deletions(-)
diff --git a/examples/presenter/edge_presentation.py b/examples/presenter/edge_presentation.py
index c90eb375c7c..80df3ff1ee3 100644
--- a/examples/presenter/edge_presentation.py
+++ b/examples/presenter/edge_presentation.py
@@ -134,8 +134,12 @@ def test_presentation(self):
self.highlight(
'img[srcset*="logo"] + div span:nth-of-type(2)', loops=16
)
- self.highlight('span[aria-live="assertive"]', loops=8)
+ if self.is_element_visible('span[aria-live="assertive"]'):
+ self.highlight('span[aria-live="assertive"]', loops=8)
+ elif self.is_element_visible('a[href*="fwlink"]'):
+ self.highlight('a[href*="fwlink"]', loops=8)
self.highlight('a[href*="chromium"]')
+ self.highlight('a[href*="credits"]')
self.quit_extra_driver()
self.switch_to_default_driver()
@@ -231,96 +235,16 @@ def test_presentation(self):
"
+
+If you want to highlight multiple lines at different times in the same slide with the `` / `` tags, you can use the new ``-``, ``-`` tags, which will generate multiple HTML slides from one Python slide.
+
+Example:
+
+```python
+self.add_slide(
+ code=(
+
Highlight this on the 1st generated slide
+
Highlight this on the 2nd generated slide
+
Highlight this on the 3rd generated slide
+
Highlight this on the 4th generated slide
+ )
+)
+```
+
+Those should automatically get converted to `` ... `` on their turn:
+
+Eg. First generated slide:
+
+```html
+
Not just an army of bots, but an army of bots "
+ "that look just like humans using web browsers.
"
+ "
(That's how they weren't detected!)
"
+ )
+ self.begin_presentation(filename="uc_presentation.html")
+
+ self.create_presentation(theme="serif", transition="fade")
+ self.add_slide(
+ "If this is what you came here for, stick around to"
+ " learn how to do the things you just saw. "
+ "
You may find it easier to build a Selenium "
+ "bot than to navigate an obstacle course.
Here's me with the creators "
+ "of Selenium / WebDriver:
",
+ image="https://seleniumbase.io/other/selenium_builders.jpg",
+ )
+ self.add_slide(
+ "SeleniumBase Fun Fact:"
+ "The 1st SB GitHub issue was from a Tesla engineer:",
+ image="https://seleniumbase.io/other/first_issue.png",
+ )
+ self.add_slide(
+ "
Now, let me explain how we got here...
"
+ "
And by here, I mean a time when lots of companies"
+ " have been building services to detect and block bots:
Most of those things are already done automatically"
+ " when using UC Mode with default settings.
\n"
+ "
The part that's your responsibility, (if setting a"
+ " custom user_data_dir), is making sure that"
+ " the u_d_d is only used by UC Mode Chrome instances. If you"
+ ' "cross the streams", UC Mode can be detected.
'
+ "
(UC Mode takes care of the other requirements.)"
+ "
"
+ )
+ self.add_slide(
+ "
With those things done, your bot can appear human.
\n"
+ "
But if anyone looks too closely at what your bot does, "
+ 'it may raise suspicion, even if already marked "not a bot".
There are additional methods that you can use"
+ " to have a better experience when using UC Mode:
"
+ "
Since driver.get(url) has"
+ " been modified, driver.default_get(url)"
+ " exists to do a regular get(url),"
+ " which may be useful if revisiting a website.
There are additional methods that you can use"
+ " to have a better experience when using UC Mode:
\n"
+ "
driver.uc_open_with_tab(url) opens"
+ " a URL in a new tab with a disconnect. Similar to the new"
+ " driver.get(url), but without the pre-check."
+ "
\n"
+ "
As a reminder, the driver.get(url)"
+ " pre-check checks to see if a URL has bot-detection software"
+ " on it before opening the URL in a new tab with a disconnect."
+ "
\n"
+ "
This pre-check is done using"
+ " requests.get(URL) before opening"
+ " a URL in the UC Mode web browser.
"
+ "
If the response code is a"
+ ' "403" (Forbidden), '
+ "then the URL is opened with a disconnect."
+ "
"
+ )
+ self.add_slide(
+ "
Customizing the default disconnect/reconnect time
"
+ "\n"
+ "
Here's a method for a custom reconnect time "
+ "when opening a page that tries to detect bots:
If your bot needs to click a button on a website that has"
+ " anti-bot services, you might be able to do it with this special"
+ " method, which forces a short disconnect: