Compare commits
23 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
b9a89f7a26 | |
![]() |
4fa959b718 | |
![]() |
c80b256e34 | |
![]() |
dba82c0bda | |
![]() |
990701d9ee | |
![]() |
79e38de0b1 | |
![]() |
a68f33ce0d | |
![]() |
004f22ffbd | |
![]() |
94fd008a2a | |
![]() |
0f3b0e9fe5 | |
![]() |
74b57669ff | |
![]() |
9c96a8ca83 | |
![]() |
ce43535a53 | |
![]() |
0da7d0fbca | |
![]() |
9c48161ef1 | |
![]() |
30815fe879 | |
![]() |
d18bbf1c0d | |
![]() |
05b8385994 | |
![]() |
e5558c4c8a | |
![]() |
f30325e575 | |
![]() |
808b252f47 | |
![]() |
ab9d898d56 | |
![]() |
a2817abcd8 |
|
@ -13,7 +13,7 @@
|
|||
|
||||
<p align="center" class="hero__title"><b>All-in-one Browser Automation Framework:<br />Web Crawling / Testing / Scraping / Stealth</b></p>
|
||||
|
||||
<p align="center"><a href="https://pypi.python.org/pypi/seleniumbase" target="_blank"><img src="https://img.shields.io/pypi/v/seleniumbase.svg?color=3399EE" alt="PyPI version" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/releases" target="_blank"><img src="https://img.shields.io/github/v/release/seleniumbase/SeleniumBase.svg?color=22AAEE" alt="GitHub version" /></a> <a href="https://seleniumbase.io"><img src="https://img.shields.io/badge/docs-seleniumbase.io-11BBAA.svg" alt="SeleniumBase Docs" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/actions" target="_blank"><img src="https://github.com/seleniumbase/SeleniumBase/workflows/CI%20build/badge.svg" alt="SeleniumBase GitHub Actions" /></a> <a href="https://discord.gg/EdhQTn3EyE" target="_blank"><img src="https://img.shields.io/badge/join-discord-infomational" alt="Join the SeleniumBase chat on Discord"/></a></p>
|
||||
<p align="center"><a href="https://pypi.python.org/pypi/seleniumbase" target="_blank"><img src="https://img.shields.io/pypi/v/seleniumbase.svg?color=3399EE" alt="PyPI version" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/releases" target="_blank"><img src="https://img.shields.io/github/v/release/seleniumbase/SeleniumBase.svg?color=22AAEE" alt="GitHub version" /></a> <a href="https://seleniumbase.io"><img src="https://img.shields.io/badge/docs-seleniumbase.io-11BBAA.svg" alt="SeleniumBase Docs" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/actions" target="_blank"><img src="https://github.com/seleniumbase/SeleniumBase/workflows/CI%20build/badge.svg" alt="SeleniumBase GitHub Actions" /></a> <a href="https://discord.gg/EdhQTn3EyE" target="_blank"><img src="https://img.shields.io/discord/727927627830001734?color=7289DA&label=Discord&logo=discord&logoColor=white"/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#python_installation">🚀 Start</a> |
|
||||
|
@ -1391,6 +1391,6 @@ pytest --reruns=1 --reruns-delay=1
|
|||
<div><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/cdn/img/super_logo_sb3.png" title="SeleniumBase" width="274" /></a></div>
|
||||
<div><a href="https://seleniumbase.io"><img src="https://img.shields.io/badge/docs-seleniumbase.io-11BBAA.svg" alt="SeleniumBase Docs" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-22BBCC.svg" title="SeleniumBase" /></a></div>
|
||||
<div><a href="https://github.com/seleniumbase/SeleniumBase"><img src="https://img.shields.io/badge/tested%20with-SeleniumBase-04C38E.svg" alt="Tested with SeleniumBase" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/stargazers"><img src="https://img.shields.io/github/stars/seleniumbase/seleniumbase.svg?color=19A57B" title="Stargazers" /></a></div>
|
||||
<div><a href="https://hellogithub.com/repository/c6be2d0f1969448697683d11a4ff915e" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=c6be2d0f1969448697683d11a4ff915e&claim_uid=xcrm4p9j3d6JCO5&theme=small" alt="Featured|HelloGitHub" /></a> <a href="https://discord.gg/EdhQTn3EyE" target="_blank"><img src="https://img.shields.io/badge/join-discord-infomational" alt="Join the SeleniumBase chat on Discord"/></a> <a href="https://gitter.im/seleniumbase/SeleniumBase" target="_blank"><img src="https://img.shields.io/gitter/room/seleniumbase/SeleniumBase.svg" alt="Gitter chat"/></a></div>
|
||||
<div><a href="https://hellogithub.com/repository/c6be2d0f1969448697683d11a4ff915e" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=c6be2d0f1969448697683d11a4ff915e&claim_uid=xcrm4p9j3d6JCO5&theme=small" alt="Featured|HelloGitHub" /></a> <a href="https://discord.gg/EdhQTn3EyE" target="_blank"><img src="https://img.shields.io/discord/727927627830001734?color=7289DA&label=Discord&logo=discord&logoColor=white"/></a></div>
|
||||
<div><a href="https://pepy.tech/projects/seleniumbase?timeRange=threeMonths&category=version&includeCIDownloads=true&granularity=daily&viewType=line&versions=*" target="_blank"><img src="https://static.pepy.tech/badge/seleniumbase" alt="SeleniumBase PyPI downloads" /></a> <img src="https://views.whatilearened.today/views/github/seleniumbase/SeleniumBase.svg" width="98px" height="20px" alt="Views" /></div>
|
||||
<div align="left"></div>
|
||||
|
|
|
@ -465,8 +465,9 @@ sb.cdp.gui_press_keys(keys)
|
|||
sb.cdp.gui_write(text)
|
||||
sb.cdp.gui_click_x_y(x, y)
|
||||
sb.cdp.gui_click_element(selector)
|
||||
sb.cdp.gui_drag_drop_points(x1, y1, x2, y2)
|
||||
sb.cdp.gui_drag_and_drop(drag_selector, drop_selector)
|
||||
sb.cdp.gui_drag_drop_points(x1, y1, x2, y2, timeframe=0.35)
|
||||
sb.cdp.gui_drag_and_drop(drag_selector, drop_selector, timeframe=0.35)
|
||||
sb.cdp.gui_click_and_hold(selector, timeframe=0.35)
|
||||
sb.cdp.gui_hover_x_y(x, y)
|
||||
sb.cdp.gui_hover_element(selector)
|
||||
sb.cdp.gui_hover_and_click(hover_selector, click_selector)
|
||||
|
|
|
@ -16,6 +16,15 @@ with SB(uc=True, test=True, locale="en") as sb:
|
|||
sb.sleep(1)
|
||||
sb.cdp.gui_press_keys("\b" * 10 + formatted_date + "\n")
|
||||
sb.sleep(1)
|
||||
days_ahead = (4 - today.weekday() + 8) % 14
|
||||
following_saturday = today + datetime.timedelta(days=days_ahead)
|
||||
formatted_date = following_saturday.strftime("%m/%d/%Y")
|
||||
sb.cdp.gui_click_element(
|
||||
'[data-att="end-date-toggler"] [aria-describedby*="date-input"]'
|
||||
)
|
||||
sb.sleep(1)
|
||||
sb.cdp.gui_press_keys("\b" * 10 + formatted_date + "\n")
|
||||
sb.sleep(1)
|
||||
sb.cdp.click('button[data-att="done"]')
|
||||
sb.sleep(1)
|
||||
sb.cdp.click('button[data-att="search"]')
|
||||
|
|
|
@ -3,6 +3,7 @@ from seleniumbase import SB
|
|||
with SB(uc=True, test=True, ad_block=True) as sb:
|
||||
url = "https://www.glassdoor.com/Reviews/index.htm"
|
||||
sb.activate_cdp_mode(url)
|
||||
sb.sleep(2)
|
||||
sb.uc_gui_click_captcha()
|
||||
sb.highlight('[data-test="global-nav-glassdoor-logo"]')
|
||||
sb.highlight('[data-test="site-header-companies"]')
|
||||
|
|
|
@ -8,28 +8,25 @@ with SB(uc=True, test=True, ad_block=True, pls="none") as sb:
|
|||
sb.uc_gui_click_captcha()
|
||||
sb.sleep(0.5)
|
||||
channel_name = "michaelmintz"
|
||||
sb.cdp.press_keys('input[name="query"]', channel_name)
|
||||
sb.cdp.click('form[action*="/search"] button')
|
||||
sb.sleep(2)
|
||||
sb.cdp.click('a[title="%s"] h2' % channel_name)
|
||||
channel_title = "Michael Mintz"
|
||||
sb.cdp.press_keys('input[placeholder*="Search"]', channel_name)
|
||||
sb.sleep(1.5)
|
||||
sb.cdp.click('a:contains("%s")' % channel_title)
|
||||
sb.sleep(2)
|
||||
sb.cdp.remove_elements("#lngtd-top-sticky")
|
||||
sb.sleep(1.5)
|
||||
name = sb.cdp.get_text("h1")
|
||||
link = sb.cdp.get_attribute("#YouTubeUserTopInfoBlockTop h4 a", "href")
|
||||
subscribers = sb.cdp.get_text("#youtube-stats-header-subs")
|
||||
video_views = sb.cdp.get_text("#youtube-stats-header-views")
|
||||
rankings = sb.cdp.get_text(
|
||||
'#socialblade-user-content [style*="border-bottom"]'
|
||||
).replace("\xa0", "").replace(" ", " ").replace(" ", " ")
|
||||
source = sb.get_page_source()
|
||||
base = "https://www.youtube.com/c/"
|
||||
base2 = 'href="/youtube/c/'
|
||||
start = source.find(base2) + len(base2)
|
||||
end = source.find('"', start)
|
||||
link = base + source[start:end]
|
||||
print("********** SocialBlade Stats for %s: **********" % name)
|
||||
print(">>> (Link: %s) <<<" % link)
|
||||
print("* YouTube Subscribers: %s" % subscribers)
|
||||
print("* YouTube Video Views: %s" % video_views)
|
||||
print(sb.get_text('[class*="grid lg:hidden"]'))
|
||||
print("********** SocialBlade Ranks: **********")
|
||||
for row in rankings.split("\n"):
|
||||
if len(row.strip()) > 8:
|
||||
print("--> " + row.strip())
|
||||
print(sb.get_text('[class*="gap-3 flex-1"]'))
|
||||
for i in range(17):
|
||||
sb.cdp.scroll_down(6)
|
||||
sb.sleep(0.1)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from contextlib import suppress
|
||||
from seleniumbase import BaseCase
|
||||
BaseCase.main(__name__, __file__)
|
||||
|
||||
|
@ -7,6 +8,54 @@ class UCPresentationClass(BaseCase):
|
|||
self.open("data:,")
|
||||
self.set_window_position(4, 40)
|
||||
self._output_file_saves = False
|
||||
self.create_presentation(theme="serif", transition="none")
|
||||
self.add_slide("<h2>Press SPACE to continue!</h2>\n")
|
||||
self.add_slide(
|
||||
"<h3><b>Before we begin</b></h3><hr />"
|
||||
"<p><b>(Here's the GitHub page)</b></p>",
|
||||
image="https://seleniumbase.io/other/sbase_qr_code.png",
|
||||
)
|
||||
self.begin_presentation(filename="uc_presentation.html")
|
||||
|
||||
with suppress(Exception):
|
||||
self.open("https://www.bostoncodecamp.com/CC38/info")
|
||||
self.create_tour(theme="hopscotch")
|
||||
self.add_tour_step(
|
||||
"<h2>Good Afternoon and Welcome!</h2>", 'h1.wow'
|
||||
)
|
||||
self.add_tour_step(
|
||||
"<h4>PSA: Visit our sponsors later.</h4>",
|
||||
'[href*="/Sponsors"]',
|
||||
)
|
||||
self.add_tour_step(
|
||||
"<h4>Let's check out the schedule...</h4>",
|
||||
'[href*="/Schedule/SessionGrid"]'
|
||||
)
|
||||
self.play_tour()
|
||||
|
||||
with suppress(Exception):
|
||||
self.open(
|
||||
"https://www.bostoncodecamp.com/CC38/Schedule/SessionGrid"
|
||||
)
|
||||
self.highlight("h2", loops=8)
|
||||
if self.is_element_visible('[data-sessionid="869465"]'):
|
||||
self.highlight(
|
||||
'div[data-sessionid="869465"]', loops=10, scroll=False
|
||||
)
|
||||
self.create_tour(theme="driverjs")
|
||||
self.add_tour_step(
|
||||
"<h2>Here we are</h2>", '[data-sessionid="869465"]'
|
||||
)
|
||||
self.play_tour()
|
||||
self.click('a[onclick*="869465"]')
|
||||
self.create_tour(theme="hopscotch")
|
||||
self.add_tour_step(
|
||||
"<h2>What to expect</h2>",
|
||||
"div.sz-modal-session",
|
||||
alignment="left",
|
||||
)
|
||||
self.play_tour()
|
||||
|
||||
self.create_presentation(theme="serif", transition="none")
|
||||
self.add_slide("<h2>Press SPACE to begin!</h2>\n")
|
||||
self.add_slide(
|
||||
|
@ -244,4 +293,9 @@ class UCPresentationClass(BaseCase):
|
|||
'<img src="https://seleniumbase.io/other/hackers_at_comp.jpg"'
|
||||
' width="70%">'
|
||||
)
|
||||
self.add_slide(
|
||||
"<h3><b>Live Demo Time!</b></h3><hr />"
|
||||
"<h3>(Let's head over to GitHub...)</h3>",
|
||||
image="https://seleniumbase.io/other/sbase_qr_code.png",
|
||||
)
|
||||
self.begin_presentation(filename="uc_presentation.html")
|
||||
|
|
|
@ -14,7 +14,7 @@ pathspec==0.12.1
|
|||
Babel==2.17.0
|
||||
paginate==0.5.7
|
||||
mkdocs==1.6.1
|
||||
mkdocs-material==9.6.9
|
||||
mkdocs-material==9.6.11
|
||||
mkdocs-exclude-search==0.6.6
|
||||
mkdocs-simple-hooks==0.1.5
|
||||
mkdocs-material-extensions==1.3.1
|
||||
|
|
|
@ -15,7 +15,7 @@ mycdp>=1.1.1
|
|||
pynose>=1.5.4
|
||||
platformdirs>=4.3.6;python_version<"3.9"
|
||||
platformdirs>=4.3.7;python_version>="3.9"
|
||||
typing-extensions>=4.13.0
|
||||
typing-extensions>=4.13.2
|
||||
sbvirtualdisplay>=1.4.0
|
||||
MarkupSafe==2.1.5;python_version<"3.9"
|
||||
MarkupSafe>=3.0.2;python_version>="3.9"
|
||||
|
@ -33,7 +33,7 @@ idna==3.10
|
|||
chardet==5.2.0
|
||||
charset-normalizer==3.4.1
|
||||
urllib3>=1.26.20,<2;python_version<"3.10"
|
||||
urllib3>=1.26.20,<2.4.0;python_version>="3.10"
|
||||
urllib3>=1.26.20,<2.5.0;python_version>="3.10"
|
||||
requests==2.32.3
|
||||
sniffio==1.3.1
|
||||
h11==0.14.0
|
||||
|
@ -44,7 +44,7 @@ trio-websocket==0.12.2
|
|||
wsproto==1.2.0
|
||||
websocket-client==1.8.0
|
||||
selenium==4.27.1;python_version<"3.9"
|
||||
selenium==4.30.0;python_version>="3.9"
|
||||
selenium==4.31.0;python_version>="3.9"
|
||||
cssselect==1.2.0;python_version<"3.9"
|
||||
cssselect==1.3.0;python_version>="3.9"
|
||||
sortedcontainers==2.4.0
|
||||
|
@ -66,19 +66,19 @@ pyotp==2.9.0
|
|||
python-xlib==0.33;platform_system=="Linux"
|
||||
markdown-it-py==3.0.0
|
||||
mdurl==0.1.2
|
||||
rich==13.9.4
|
||||
rich>=14.0.0,<15
|
||||
|
||||
# --- Testing Requirements --- #
|
||||
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
|
||||
|
||||
coverage>=7.6.1;python_version<"3.9"
|
||||
coverage>=7.7.1;python_version>="3.9"
|
||||
coverage>=7.8.0;python_version>="3.9"
|
||||
pytest-cov>=5.0.0;python_version<"3.9"
|
||||
pytest-cov>=6.0.0;python_version>="3.9"
|
||||
pytest-cov>=6.1.1;python_version>="3.9"
|
||||
flake8==5.0.4;python_version<"3.9"
|
||||
flake8==7.1.2;python_version>="3.9"
|
||||
flake8==7.2.0;python_version>="3.9"
|
||||
mccabe==0.7.0
|
||||
pyflakes==2.5.0;python_version<"3.9"
|
||||
pyflakes==3.2.0;python_version>="3.9"
|
||||
pyflakes==3.3.2;python_version>="3.9"
|
||||
pycodestyle==2.9.1;python_version<"3.9"
|
||||
pycodestyle==2.12.1;python_version>="3.9"
|
||||
pycodestyle==2.13.0;python_version>="3.9"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# seleniumbase package
|
||||
__version__ = "4.36.4"
|
||||
__version__ = "4.37.2"
|
||||
|
|
|
@ -682,6 +682,7 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|||
cdp.gui_click_element = CDPM.gui_click_element
|
||||
cdp.gui_drag_drop_points = CDPM.gui_drag_drop_points
|
||||
cdp.gui_drag_and_drop = CDPM.gui_drag_and_drop
|
||||
cdp.gui_click_and_hold = CDPM.gui_click_and_hold
|
||||
cdp.gui_hover_x_y = CDPM.gui_hover_x_y
|
||||
cdp.gui_hover_element = CDPM.gui_hover_element
|
||||
cdp.gui_hover_and_click = CDPM.gui_hover_and_click
|
||||
|
|
|
@ -92,5 +92,5 @@ class S3LoggingBucket(object):
|
|||
"""Keep a record of all file names that have been uploaded.
|
||||
Upload log files related to each test after its execution.
|
||||
Once done, use already_uploaded_files to create an index file."""
|
||||
global already_uploaded_files
|
||||
global already_uploaded_files # noqa
|
||||
already_uploaded_files.extend(files)
|
||||
|
|
|
@ -1227,15 +1227,23 @@ class CDPMethods():
|
|||
if not timeout:
|
||||
timeout = settings.SMALL_TIMEOUT
|
||||
selector = self.__convert_to_css_if_xpath(selector)
|
||||
self.select(selector, timeout=timeout)
|
||||
element = self.select(selector, timeout=timeout)
|
||||
self.__add_light_pause()
|
||||
coordinates = self.loop.run_until_complete(
|
||||
self.page.js_dumps(
|
||||
"""document.querySelector"""
|
||||
"""('%s').getBoundingClientRect()"""
|
||||
% js_utils.escape_quotes_if_needed(re.escape(selector))
|
||||
coordinates = None
|
||||
if ":contains(" in selector:
|
||||
position = element.get_position()
|
||||
x = position.x
|
||||
y = position.y
|
||||
width = position.width
|
||||
height = position.height
|
||||
coordinates = {"x": x, "y": y, "width": width, "height": height}
|
||||
else:
|
||||
coordinates = self.loop.run_until_complete(
|
||||
self.page.js_dumps(
|
||||
"""document.querySelector('%s').getBoundingClientRect()"""
|
||||
% js_utils.escape_quotes_if_needed(re.escape(selector))
|
||||
)
|
||||
)
|
||||
)
|
||||
return coordinates
|
||||
|
||||
def get_element_size(self, selector, timeout=None):
|
||||
|
@ -1614,6 +1622,8 @@ class CDPMethods():
|
|||
pyautogui.dragTo(x2, y2, button="left", duration=timeframe)
|
||||
|
||||
def gui_drag_drop_points(self, x1, y1, x2, y2, timeframe=0.35):
|
||||
"""Use PyAutoGUI to drag-and-drop from one point to another.
|
||||
Can simulate click-and-hold when using the same point twice."""
|
||||
gui_lock = fasteners.InterProcessLock(
|
||||
constants.MultiBrowser.PYAUTOGUILOCK
|
||||
)
|
||||
|
@ -1653,6 +1663,8 @@ class CDPMethods():
|
|||
self.loop.run_until_complete(self.page.wait())
|
||||
|
||||
def gui_drag_and_drop(self, drag_selector, drop_selector, timeframe=0.35):
|
||||
"""Use PyAutoGUI to drag-and-drop from one selector to another.
|
||||
Can simulate click-and-hold when using the same selector twice."""
|
||||
self.__slow_mode_pause_if_set()
|
||||
self.bring_active_window_to_front()
|
||||
x1, y1 = self.get_gui_element_center(drag_selector)
|
||||
|
@ -1661,6 +1673,14 @@ class CDPMethods():
|
|||
self.__add_light_pause()
|
||||
self.gui_drag_drop_points(x1, y1, x2, y2, timeframe=timeframe)
|
||||
|
||||
def gui_click_and_hold(self, selector, timeframe=0.35):
|
||||
"""Use PyAutoGUI to click-and-hold a selector."""
|
||||
self.__slow_mode_pause_if_set()
|
||||
self.bring_active_window_to_front()
|
||||
x, y = self.get_gui_element_center(selector)
|
||||
self.__add_light_pause()
|
||||
self.gui_drag_drop_points(x, y, x, y, timeframe=timeframe)
|
||||
|
||||
def __gui_hover_x_y(self, x, y, timeframe=0.25, uc_lock=False):
|
||||
self.__install_pyautogui_if_missing()
|
||||
import pyautogui
|
||||
|
|
|
@ -4871,6 +4871,13 @@ class BaseCase(unittest.TestCase):
|
|||
|
||||
def activate_cdp_mode(self, url=None):
|
||||
if hasattr(self.driver, "_is_using_uc") and self.driver._is_using_uc:
|
||||
if self.__is_cdp_swap_needed():
|
||||
return # CDP Mode is already active
|
||||
if not self.is_connected():
|
||||
self.driver.connect()
|
||||
current_url = self.get_current_url()
|
||||
if not current_url.startswith(("about", "data", "chrome")):
|
||||
self.get_new_driver(undetectable=True)
|
||||
self.driver.uc_open_with_cdp_mode(url)
|
||||
else:
|
||||
self.get_new_driver(undetectable=True)
|
||||
|
|
|
@ -441,7 +441,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|||
with suppress(Exception):
|
||||
if self.service.is_connectable():
|
||||
self.stop_client()
|
||||
self.service.stop()
|
||||
try:
|
||||
self.service.send_remote_shutdown_command()
|
||||
except TypeError:
|
||||
pass
|
||||
finally:
|
||||
with suppress(Exception):
|
||||
self.service._terminate_process()
|
||||
if isinstance(timeout, str):
|
||||
if timeout.lower() == "breakpoint":
|
||||
breakpoint() # To continue:
|
||||
|
@ -466,7 +472,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|||
self.close()
|
||||
if self.service.is_connectable():
|
||||
self.stop_client()
|
||||
self.service.stop()
|
||||
try:
|
||||
self.service.send_remote_shutdown_command()
|
||||
except TypeError:
|
||||
pass
|
||||
finally:
|
||||
with suppress(Exception):
|
||||
self.service._terminate_process()
|
||||
self.service.start()
|
||||
self.start_session()
|
||||
time.sleep(0.003)
|
||||
|
@ -482,7 +494,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|||
if self.service.is_connectable():
|
||||
self.stop_client()
|
||||
time.sleep(0.003)
|
||||
self.service.stop()
|
||||
try:
|
||||
self.service.send_remote_shutdown_command()
|
||||
except TypeError:
|
||||
pass
|
||||
finally:
|
||||
with suppress(Exception):
|
||||
self.service._terminate_process()
|
||||
self._is_connected = False
|
||||
|
||||
def connect(self):
|
||||
|
@ -507,7 +525,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|||
self.close()
|
||||
if self.service.is_connectable():
|
||||
self.stop_client()
|
||||
self.service.stop()
|
||||
try:
|
||||
self.service.send_remote_shutdown_command()
|
||||
except TypeError:
|
||||
pass
|
||||
finally:
|
||||
with suppress(Exception):
|
||||
self.service._terminate_process()
|
||||
self.service.start()
|
||||
self.start_session()
|
||||
time.sleep(0.003)
|
||||
|
@ -539,7 +563,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|||
logger.debug("Stopping webdriver service")
|
||||
with suppress(Exception):
|
||||
self.stop_client()
|
||||
self.service.stop()
|
||||
try:
|
||||
self.service.send_remote_shutdown_command()
|
||||
except TypeError:
|
||||
pass
|
||||
finally:
|
||||
with suppress(Exception):
|
||||
self.service._terminate_process()
|
||||
with suppress(Exception):
|
||||
if self.reactor and isinstance(self.reactor, Reactor):
|
||||
logger.debug("Shutting down Reactor")
|
||||
|
|
|
@ -406,7 +406,13 @@ async def create_from_driver(driver) -> Browser:
|
|||
browser = await start(conf)
|
||||
browser._process_pid = driver.browser_pid
|
||||
# Stop chromedriver binary
|
||||
driver.service.stop()
|
||||
try:
|
||||
driver.service.send_remote_shutdown_command()
|
||||
except TypeError:
|
||||
pass
|
||||
finally:
|
||||
with suppress(Exception):
|
||||
driver.service._terminate_process()
|
||||
driver.browser_pid = -1
|
||||
driver.user_data_dir = None
|
||||
return browser
|
||||
|
|
22
setup.py
22
setup.py
|
@ -34,7 +34,7 @@ if sys.argv[-1] == "publish":
|
|||
print("\nERROR! Publishing to PyPI requires Python>=3.9")
|
||||
sys.exit()
|
||||
print("\n*** Checking code health with flake8:\n")
|
||||
os.system("python -m pip install 'flake8==7.1.2'")
|
||||
os.system("python -m pip install 'flake8==7.2.0'")
|
||||
flake8_status = os.system("flake8 --exclude=recordings,temp")
|
||||
if flake8_status != 0:
|
||||
print("\nERROR! Fix flake8 issues before publishing to PyPI!\n")
|
||||
|
@ -164,7 +164,7 @@ setup(
|
|||
"pynose>=1.5.4",
|
||||
'platformdirs>=4.3.6;python_version<"3.9"',
|
||||
'platformdirs>=4.3.7;python_version>="3.9"',
|
||||
'typing-extensions>=4.13.0',
|
||||
'typing-extensions>=4.13.2',
|
||||
"sbvirtualdisplay>=1.4.0",
|
||||
'MarkupSafe==2.1.5;python_version<"3.9"',
|
||||
'MarkupSafe>=3.0.2;python_version>="3.9"',
|
||||
|
@ -182,7 +182,7 @@ setup(
|
|||
'chardet==5.2.0',
|
||||
'charset-normalizer==3.4.1',
|
||||
'urllib3>=1.26.20,<2;python_version<"3.10"',
|
||||
'urllib3>=1.26.20,<2.4.0;python_version>="3.10"',
|
||||
'urllib3>=1.26.20,<2.5.0;python_version>="3.10"',
|
||||
'requests==2.32.3',
|
||||
'sniffio==1.3.1',
|
||||
'h11==0.14.0',
|
||||
|
@ -193,7 +193,7 @@ setup(
|
|||
'wsproto==1.2.0',
|
||||
'websocket-client==1.8.0',
|
||||
'selenium==4.27.1;python_version<"3.9"',
|
||||
'selenium==4.30.0;python_version>="3.9"',
|
||||
'selenium==4.31.0;python_version>="3.9"',
|
||||
'cssselect==1.2.0;python_version<"3.9"',
|
||||
'cssselect==1.3.0;python_version>="3.9"',
|
||||
"sortedcontainers==2.4.0",
|
||||
|
@ -215,7 +215,7 @@ setup(
|
|||
'python-xlib==0.33;platform_system=="Linux"',
|
||||
'markdown-it-py==3.0.0',
|
||||
'mdurl==0.1.2',
|
||||
'rich==13.9.4',
|
||||
'rich>=14.0.0,<15',
|
||||
],
|
||||
extras_require={
|
||||
# pip install -e .[allure]
|
||||
|
@ -230,20 +230,20 @@ setup(
|
|||
# Usage: coverage run -m pytest; coverage html; coverage report
|
||||
"coverage": [
|
||||
'coverage>=7.6.1;python_version<"3.9"',
|
||||
'coverage>=7.7.1;python_version>="3.9"',
|
||||
'coverage>=7.8.0;python_version>="3.9"',
|
||||
'pytest-cov>=5.0.0;python_version<"3.9"',
|
||||
'pytest-cov>=6.0.0;python_version>="3.9"',
|
||||
'pytest-cov>=6.1.1;python_version>="3.9"',
|
||||
],
|
||||
# pip install -e .[flake8]
|
||||
# Usage: flake8
|
||||
"flake8": [
|
||||
'flake8==5.0.4;python_version<"3.9"',
|
||||
'flake8==7.1.2;python_version>="3.9"',
|
||||
'flake8==7.2.0;python_version>="3.9"',
|
||||
"mccabe==0.7.0",
|
||||
'pyflakes==2.5.0;python_version<"3.9"',
|
||||
'pyflakes==3.2.0;python_version>="3.9"',
|
||||
'pyflakes==3.3.2;python_version>="3.9"',
|
||||
'pycodestyle==2.9.1;python_version<"3.9"',
|
||||
'pycodestyle==2.12.1;python_version>="3.9"',
|
||||
'pycodestyle==2.13.0;python_version>="3.9"',
|
||||
],
|
||||
# pip install -e .[ipdb]
|
||||
# (Not needed for debugging anymore. SeleniumBase now includes "pdbp".)
|
||||
|
@ -271,7 +271,7 @@ setup(
|
|||
# (An optional library for image-processing.)
|
||||
"pillow": [
|
||||
'Pillow>=10.4.0;python_version<"3.9"',
|
||||
'Pillow>=11.1.0;python_version>="3.9"',
|
||||
'Pillow>=11.2.0;python_version>="3.9"',
|
||||
],
|
||||
# pip install -e .[pip-system-certs]
|
||||
# (If you see [SSL: CERTIFICATE_VERIFY_FAILED], then get this.)
|
||||
|
|
Loading…
Reference in New Issue