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" 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">
|
<p align="center">
|
||||||
<a href="#python_installation">🚀 Start</a> |
|
<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://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://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://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><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>
|
<div align="left"></div>
|
||||||
|
|
|
@ -465,8 +465,9 @@ sb.cdp.gui_press_keys(keys)
|
||||||
sb.cdp.gui_write(text)
|
sb.cdp.gui_write(text)
|
||||||
sb.cdp.gui_click_x_y(x, y)
|
sb.cdp.gui_click_x_y(x, y)
|
||||||
sb.cdp.gui_click_element(selector)
|
sb.cdp.gui_click_element(selector)
|
||||||
sb.cdp.gui_drag_drop_points(x1, y1, x2, y2)
|
sb.cdp.gui_drag_drop_points(x1, y1, x2, y2, timeframe=0.35)
|
||||||
sb.cdp.gui_drag_and_drop(drag_selector, drop_selector)
|
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_x_y(x, y)
|
||||||
sb.cdp.gui_hover_element(selector)
|
sb.cdp.gui_hover_element(selector)
|
||||||
sb.cdp.gui_hover_and_click(hover_selector, click_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.sleep(1)
|
||||||
sb.cdp.gui_press_keys("\b" * 10 + formatted_date + "\n")
|
sb.cdp.gui_press_keys("\b" * 10 + formatted_date + "\n")
|
||||||
sb.sleep(1)
|
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.cdp.click('button[data-att="done"]')
|
||||||
sb.sleep(1)
|
sb.sleep(1)
|
||||||
sb.cdp.click('button[data-att="search"]')
|
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:
|
with SB(uc=True, test=True, ad_block=True) as sb:
|
||||||
url = "https://www.glassdoor.com/Reviews/index.htm"
|
url = "https://www.glassdoor.com/Reviews/index.htm"
|
||||||
sb.activate_cdp_mode(url)
|
sb.activate_cdp_mode(url)
|
||||||
|
sb.sleep(2)
|
||||||
sb.uc_gui_click_captcha()
|
sb.uc_gui_click_captcha()
|
||||||
sb.highlight('[data-test="global-nav-glassdoor-logo"]')
|
sb.highlight('[data-test="global-nav-glassdoor-logo"]')
|
||||||
sb.highlight('[data-test="site-header-companies"]')
|
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.uc_gui_click_captcha()
|
||||||
sb.sleep(0.5)
|
sb.sleep(0.5)
|
||||||
channel_name = "michaelmintz"
|
channel_name = "michaelmintz"
|
||||||
sb.cdp.press_keys('input[name="query"]', channel_name)
|
channel_title = "Michael Mintz"
|
||||||
sb.cdp.click('form[action*="/search"] button')
|
sb.cdp.press_keys('input[placeholder*="Search"]', channel_name)
|
||||||
sb.sleep(2)
|
|
||||||
sb.cdp.click('a[title="%s"] h2' % channel_name)
|
|
||||||
sb.sleep(1.5)
|
sb.sleep(1.5)
|
||||||
|
sb.cdp.click('a:contains("%s")' % channel_title)
|
||||||
|
sb.sleep(2)
|
||||||
sb.cdp.remove_elements("#lngtd-top-sticky")
|
sb.cdp.remove_elements("#lngtd-top-sticky")
|
||||||
sb.sleep(1.5)
|
sb.sleep(1.5)
|
||||||
name = sb.cdp.get_text("h1")
|
name = sb.cdp.get_text("h1")
|
||||||
link = sb.cdp.get_attribute("#YouTubeUserTopInfoBlockTop h4 a", "href")
|
source = sb.get_page_source()
|
||||||
subscribers = sb.cdp.get_text("#youtube-stats-header-subs")
|
base = "https://www.youtube.com/c/"
|
||||||
video_views = sb.cdp.get_text("#youtube-stats-header-views")
|
base2 = 'href="/youtube/c/'
|
||||||
rankings = sb.cdp.get_text(
|
start = source.find(base2) + len(base2)
|
||||||
'#socialblade-user-content [style*="border-bottom"]'
|
end = source.find('"', start)
|
||||||
).replace("\xa0", "").replace(" ", " ").replace(" ", " ")
|
link = base + source[start:end]
|
||||||
print("********** SocialBlade Stats for %s: **********" % name)
|
print("********** SocialBlade Stats for %s: **********" % name)
|
||||||
print(">>> (Link: %s) <<<" % link)
|
print(">>> (Link: %s) <<<" % link)
|
||||||
print("* YouTube Subscribers: %s" % subscribers)
|
print(sb.get_text('[class*="grid lg:hidden"]'))
|
||||||
print("* YouTube Video Views: %s" % video_views)
|
|
||||||
print("********** SocialBlade Ranks: **********")
|
print("********** SocialBlade Ranks: **********")
|
||||||
for row in rankings.split("\n"):
|
print(sb.get_text('[class*="gap-3 flex-1"]'))
|
||||||
if len(row.strip()) > 8:
|
|
||||||
print("--> " + row.strip())
|
|
||||||
for i in range(17):
|
for i in range(17):
|
||||||
sb.cdp.scroll_down(6)
|
sb.cdp.scroll_down(6)
|
||||||
sb.sleep(0.1)
|
sb.sleep(0.1)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from contextlib import suppress
|
||||||
from seleniumbase import BaseCase
|
from seleniumbase import BaseCase
|
||||||
BaseCase.main(__name__, __file__)
|
BaseCase.main(__name__, __file__)
|
||||||
|
|
||||||
|
@ -7,6 +8,54 @@ class UCPresentationClass(BaseCase):
|
||||||
self.open("data:,")
|
self.open("data:,")
|
||||||
self.set_window_position(4, 40)
|
self.set_window_position(4, 40)
|
||||||
self._output_file_saves = False
|
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.create_presentation(theme="serif", transition="none")
|
||||||
self.add_slide("<h2>Press SPACE to begin!</h2>\n")
|
self.add_slide("<h2>Press SPACE to begin!</h2>\n")
|
||||||
self.add_slide(
|
self.add_slide(
|
||||||
|
@ -244,4 +293,9 @@ class UCPresentationClass(BaseCase):
|
||||||
'<img src="https://seleniumbase.io/other/hackers_at_comp.jpg"'
|
'<img src="https://seleniumbase.io/other/hackers_at_comp.jpg"'
|
||||||
' width="70%">'
|
' 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")
|
self.begin_presentation(filename="uc_presentation.html")
|
||||||
|
|
|
@ -14,7 +14,7 @@ pathspec==0.12.1
|
||||||
Babel==2.17.0
|
Babel==2.17.0
|
||||||
paginate==0.5.7
|
paginate==0.5.7
|
||||||
mkdocs==1.6.1
|
mkdocs==1.6.1
|
||||||
mkdocs-material==9.6.9
|
mkdocs-material==9.6.11
|
||||||
mkdocs-exclude-search==0.6.6
|
mkdocs-exclude-search==0.6.6
|
||||||
mkdocs-simple-hooks==0.1.5
|
mkdocs-simple-hooks==0.1.5
|
||||||
mkdocs-material-extensions==1.3.1
|
mkdocs-material-extensions==1.3.1
|
||||||
|
|
|
@ -15,7 +15,7 @@ mycdp>=1.1.1
|
||||||
pynose>=1.5.4
|
pynose>=1.5.4
|
||||||
platformdirs>=4.3.6;python_version<"3.9"
|
platformdirs>=4.3.6;python_version<"3.9"
|
||||||
platformdirs>=4.3.7;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
|
sbvirtualdisplay>=1.4.0
|
||||||
MarkupSafe==2.1.5;python_version<"3.9"
|
MarkupSafe==2.1.5;python_version<"3.9"
|
||||||
MarkupSafe>=3.0.2;python_version>="3.9"
|
MarkupSafe>=3.0.2;python_version>="3.9"
|
||||||
|
@ -33,7 +33,7 @@ idna==3.10
|
||||||
chardet==5.2.0
|
chardet==5.2.0
|
||||||
charset-normalizer==3.4.1
|
charset-normalizer==3.4.1
|
||||||
urllib3>=1.26.20,<2;python_version<"3.10"
|
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
|
requests==2.32.3
|
||||||
sniffio==1.3.1
|
sniffio==1.3.1
|
||||||
h11==0.14.0
|
h11==0.14.0
|
||||||
|
@ -44,7 +44,7 @@ trio-websocket==0.12.2
|
||||||
wsproto==1.2.0
|
wsproto==1.2.0
|
||||||
websocket-client==1.8.0
|
websocket-client==1.8.0
|
||||||
selenium==4.27.1;python_version<"3.9"
|
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.2.0;python_version<"3.9"
|
||||||
cssselect==1.3.0;python_version>="3.9"
|
cssselect==1.3.0;python_version>="3.9"
|
||||||
sortedcontainers==2.4.0
|
sortedcontainers==2.4.0
|
||||||
|
@ -66,19 +66,19 @@ pyotp==2.9.0
|
||||||
python-xlib==0.33;platform_system=="Linux"
|
python-xlib==0.33;platform_system=="Linux"
|
||||||
markdown-it-py==3.0.0
|
markdown-it-py==3.0.0
|
||||||
mdurl==0.1.2
|
mdurl==0.1.2
|
||||||
rich==13.9.4
|
rich>=14.0.0,<15
|
||||||
|
|
||||||
# --- Testing Requirements --- #
|
# --- Testing Requirements --- #
|
||||||
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
|
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
|
||||||
|
|
||||||
coverage>=7.6.1;python_version<"3.9"
|
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>=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==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
|
mccabe==0.7.0
|
||||||
pyflakes==2.5.0;python_version<"3.9"
|
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.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
|
# 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_click_element = CDPM.gui_click_element
|
||||||
cdp.gui_drag_drop_points = CDPM.gui_drag_drop_points
|
cdp.gui_drag_drop_points = CDPM.gui_drag_drop_points
|
||||||
cdp.gui_drag_and_drop = CDPM.gui_drag_and_drop
|
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_x_y = CDPM.gui_hover_x_y
|
||||||
cdp.gui_hover_element = CDPM.gui_hover_element
|
cdp.gui_hover_element = CDPM.gui_hover_element
|
||||||
cdp.gui_hover_and_click = CDPM.gui_hover_and_click
|
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.
|
"""Keep a record of all file names that have been uploaded.
|
||||||
Upload log files related to each test after its execution.
|
Upload log files related to each test after its execution.
|
||||||
Once done, use already_uploaded_files to create an index file."""
|
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)
|
already_uploaded_files.extend(files)
|
||||||
|
|
|
@ -1227,15 +1227,23 @@ class CDPMethods():
|
||||||
if not timeout:
|
if not timeout:
|
||||||
timeout = settings.SMALL_TIMEOUT
|
timeout = settings.SMALL_TIMEOUT
|
||||||
selector = self.__convert_to_css_if_xpath(selector)
|
selector = self.__convert_to_css_if_xpath(selector)
|
||||||
self.select(selector, timeout=timeout)
|
element = self.select(selector, timeout=timeout)
|
||||||
self.__add_light_pause()
|
self.__add_light_pause()
|
||||||
coordinates = self.loop.run_until_complete(
|
coordinates = None
|
||||||
self.page.js_dumps(
|
if ":contains(" in selector:
|
||||||
"""document.querySelector"""
|
position = element.get_position()
|
||||||
"""('%s').getBoundingClientRect()"""
|
x = position.x
|
||||||
% js_utils.escape_quotes_if_needed(re.escape(selector))
|
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
|
return coordinates
|
||||||
|
|
||||||
def get_element_size(self, selector, timeout=None):
|
def get_element_size(self, selector, timeout=None):
|
||||||
|
@ -1614,6 +1622,8 @@ class CDPMethods():
|
||||||
pyautogui.dragTo(x2, y2, button="left", duration=timeframe)
|
pyautogui.dragTo(x2, y2, button="left", duration=timeframe)
|
||||||
|
|
||||||
def gui_drag_drop_points(self, x1, y1, x2, y2, timeframe=0.35):
|
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(
|
gui_lock = fasteners.InterProcessLock(
|
||||||
constants.MultiBrowser.PYAUTOGUILOCK
|
constants.MultiBrowser.PYAUTOGUILOCK
|
||||||
)
|
)
|
||||||
|
@ -1653,6 +1663,8 @@ class CDPMethods():
|
||||||
self.loop.run_until_complete(self.page.wait())
|
self.loop.run_until_complete(self.page.wait())
|
||||||
|
|
||||||
def gui_drag_and_drop(self, drag_selector, drop_selector, timeframe=0.35):
|
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.__slow_mode_pause_if_set()
|
||||||
self.bring_active_window_to_front()
|
self.bring_active_window_to_front()
|
||||||
x1, y1 = self.get_gui_element_center(drag_selector)
|
x1, y1 = self.get_gui_element_center(drag_selector)
|
||||||
|
@ -1661,6 +1673,14 @@ class CDPMethods():
|
||||||
self.__add_light_pause()
|
self.__add_light_pause()
|
||||||
self.gui_drag_drop_points(x1, y1, x2, y2, timeframe=timeframe)
|
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):
|
def __gui_hover_x_y(self, x, y, timeframe=0.25, uc_lock=False):
|
||||||
self.__install_pyautogui_if_missing()
|
self.__install_pyautogui_if_missing()
|
||||||
import pyautogui
|
import pyautogui
|
||||||
|
|
|
@ -4871,6 +4871,13 @@ class BaseCase(unittest.TestCase):
|
||||||
|
|
||||||
def activate_cdp_mode(self, url=None):
|
def activate_cdp_mode(self, url=None):
|
||||||
if hasattr(self.driver, "_is_using_uc") and self.driver._is_using_uc:
|
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)
|
self.driver.uc_open_with_cdp_mode(url)
|
||||||
else:
|
else:
|
||||||
self.get_new_driver(undetectable=True)
|
self.get_new_driver(undetectable=True)
|
||||||
|
|
|
@ -441,7 +441,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
if self.service.is_connectable():
|
if self.service.is_connectable():
|
||||||
self.stop_client()
|
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 isinstance(timeout, str):
|
||||||
if timeout.lower() == "breakpoint":
|
if timeout.lower() == "breakpoint":
|
||||||
breakpoint() # To continue:
|
breakpoint() # To continue:
|
||||||
|
@ -466,7 +472,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
self.close()
|
self.close()
|
||||||
if self.service.is_connectable():
|
if self.service.is_connectable():
|
||||||
self.stop_client()
|
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.service.start()
|
||||||
self.start_session()
|
self.start_session()
|
||||||
time.sleep(0.003)
|
time.sleep(0.003)
|
||||||
|
@ -482,7 +494,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
if self.service.is_connectable():
|
if self.service.is_connectable():
|
||||||
self.stop_client()
|
self.stop_client()
|
||||||
time.sleep(0.003)
|
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
|
self._is_connected = False
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
|
@ -507,7 +525,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
self.close()
|
self.close()
|
||||||
if self.service.is_connectable():
|
if self.service.is_connectable():
|
||||||
self.stop_client()
|
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.service.start()
|
||||||
self.start_session()
|
self.start_session()
|
||||||
time.sleep(0.003)
|
time.sleep(0.003)
|
||||||
|
@ -539,7 +563,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
logger.debug("Stopping webdriver service")
|
logger.debug("Stopping webdriver service")
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
self.stop_client()
|
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):
|
with suppress(Exception):
|
||||||
if self.reactor and isinstance(self.reactor, Reactor):
|
if self.reactor and isinstance(self.reactor, Reactor):
|
||||||
logger.debug("Shutting down Reactor")
|
logger.debug("Shutting down Reactor")
|
||||||
|
|
|
@ -406,7 +406,13 @@ async def create_from_driver(driver) -> Browser:
|
||||||
browser = await start(conf)
|
browser = await start(conf)
|
||||||
browser._process_pid = driver.browser_pid
|
browser._process_pid = driver.browser_pid
|
||||||
# Stop chromedriver binary
|
# 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.browser_pid = -1
|
||||||
driver.user_data_dir = None
|
driver.user_data_dir = None
|
||||||
return browser
|
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")
|
print("\nERROR! Publishing to PyPI requires Python>=3.9")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
print("\n*** Checking code health with flake8:\n")
|
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")
|
flake8_status = os.system("flake8 --exclude=recordings,temp")
|
||||||
if flake8_status != 0:
|
if flake8_status != 0:
|
||||||
print("\nERROR! Fix flake8 issues before publishing to PyPI!\n")
|
print("\nERROR! Fix flake8 issues before publishing to PyPI!\n")
|
||||||
|
@ -164,7 +164,7 @@ setup(
|
||||||
"pynose>=1.5.4",
|
"pynose>=1.5.4",
|
||||||
'platformdirs>=4.3.6;python_version<"3.9"',
|
'platformdirs>=4.3.6;python_version<"3.9"',
|
||||||
'platformdirs>=4.3.7;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",
|
"sbvirtualdisplay>=1.4.0",
|
||||||
'MarkupSafe==2.1.5;python_version<"3.9"',
|
'MarkupSafe==2.1.5;python_version<"3.9"',
|
||||||
'MarkupSafe>=3.0.2;python_version>="3.9"',
|
'MarkupSafe>=3.0.2;python_version>="3.9"',
|
||||||
|
@ -182,7 +182,7 @@ setup(
|
||||||
'chardet==5.2.0',
|
'chardet==5.2.0',
|
||||||
'charset-normalizer==3.4.1',
|
'charset-normalizer==3.4.1',
|
||||||
'urllib3>=1.26.20,<2;python_version<"3.10"',
|
'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',
|
'requests==2.32.3',
|
||||||
'sniffio==1.3.1',
|
'sniffio==1.3.1',
|
||||||
'h11==0.14.0',
|
'h11==0.14.0',
|
||||||
|
@ -193,7 +193,7 @@ setup(
|
||||||
'wsproto==1.2.0',
|
'wsproto==1.2.0',
|
||||||
'websocket-client==1.8.0',
|
'websocket-client==1.8.0',
|
||||||
'selenium==4.27.1;python_version<"3.9"',
|
'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.2.0;python_version<"3.9"',
|
||||||
'cssselect==1.3.0;python_version>="3.9"',
|
'cssselect==1.3.0;python_version>="3.9"',
|
||||||
"sortedcontainers==2.4.0",
|
"sortedcontainers==2.4.0",
|
||||||
|
@ -215,7 +215,7 @@ setup(
|
||||||
'python-xlib==0.33;platform_system=="Linux"',
|
'python-xlib==0.33;platform_system=="Linux"',
|
||||||
'markdown-it-py==3.0.0',
|
'markdown-it-py==3.0.0',
|
||||||
'mdurl==0.1.2',
|
'mdurl==0.1.2',
|
||||||
'rich==13.9.4',
|
'rich>=14.0.0,<15',
|
||||||
],
|
],
|
||||||
extras_require={
|
extras_require={
|
||||||
# pip install -e .[allure]
|
# pip install -e .[allure]
|
||||||
|
@ -230,20 +230,20 @@ setup(
|
||||||
# Usage: coverage run -m pytest; coverage html; coverage report
|
# Usage: coverage run -m pytest; coverage html; coverage report
|
||||||
"coverage": [
|
"coverage": [
|
||||||
'coverage>=7.6.1;python_version<"3.9"',
|
'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>=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]
|
# pip install -e .[flake8]
|
||||||
# Usage: flake8
|
# Usage: flake8
|
||||||
"flake8": [
|
"flake8": [
|
||||||
'flake8==5.0.4;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",
|
"mccabe==0.7.0",
|
||||||
'pyflakes==2.5.0;python_version<"3.9"',
|
'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.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]
|
# pip install -e .[ipdb]
|
||||||
# (Not needed for debugging anymore. SeleniumBase now includes "pdbp".)
|
# (Not needed for debugging anymore. SeleniumBase now includes "pdbp".)
|
||||||
|
@ -271,7 +271,7 @@ setup(
|
||||||
# (An optional library for image-processing.)
|
# (An optional library for image-processing.)
|
||||||
"pillow": [
|
"pillow": [
|
||||||
'Pillow>=10.4.0;python_version<"3.9"',
|
'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]
|
# pip install -e .[pip-system-certs]
|
||||||
# (If you see [SSL: CERTIFICATE_VERIFY_FAILED], then get this.)
|
# (If you see [SSL: CERTIFICATE_VERIFY_FAILED], then get this.)
|
||||||
|
|
Loading…
Reference in New Issue