commit
33aa8c3905
8
setup.py
8
setup.py
|
@ -46,10 +46,11 @@ setup(
|
||||||
description="""\
|
description="""\
|
||||||
selenium.webdriver.Chrome replacement wiht compatiblity for Brave, and other Chromium baed browsers.
|
selenium.webdriver.Chrome replacement wiht compatiblity for Brave, and other Chromium baed browsers.
|
||||||
not triggered by CloudFlare/Imperva/hCaptcha and such.
|
not triggered by CloudFlare/Imperva/hCaptcha and such.
|
||||||
|
|
||||||
NOTE: results may vary due to many factors. No guarantees are given, except for ongoing efforts in understanding detection algorithms.
|
NOTE: results may vary due to many factors. No guarantees are given, except for ongoing efforts in understanding detection algorithms.
|
||||||
""",
|
""",
|
||||||
long_description=open(os.path.join(dirname, "README.md"),encoding="utf-8").read(),
|
|
||||||
|
long_description=open(os.path.join(dirname, "README.md"), encoding="utf-8").read(),
|
||||||
|
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||||
|
@ -57,6 +58,7 @@ setup(
|
||||||
"Programming Language :: Python :: 3.7",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10"
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
888 888 d8b
|
888 888 d8b
|
||||||
|
@ -16,7 +18,7 @@ by UltrafunkAmsterdam (https://github.com/ultrafunkamsterdam)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "3.1.0"
|
__version__ = "3.1.2"
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
@ -111,6 +113,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
version_main=None,
|
version_main=None,
|
||||||
patcher_force_close=False,
|
patcher_force_close=False,
|
||||||
suppress_welcome=True,
|
suppress_welcome=True,
|
||||||
|
use_subprocess=False,
|
||||||
debug=False,
|
debug=False,
|
||||||
**kw
|
**kw
|
||||||
):
|
):
|
||||||
|
@ -182,6 +185,23 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
now, in case you are nag-fetishist, or a diagnostics data feeder to google, you can set this to False.
|
now, in case you are nag-fetishist, or a diagnostics data feeder to google, you can set this to False.
|
||||||
Note: if you don't handle the nag screen in time, the browser loses it's connection and throws an Exception.
|
Note: if you don't handle the nag screen in time, the browser loses it's connection and throws an Exception.
|
||||||
|
|
||||||
|
use_subprocess: bool, optional , default: False,
|
||||||
|
|
||||||
|
False (the default) makes sure Chrome will get it's own process (so no subprocess of chromedriver.exe or python
|
||||||
|
This fixes a LOT of issues, like multithreaded run, but mst importantly. shutting corectly after
|
||||||
|
program exits or using .quit()
|
||||||
|
|
||||||
|
unfortunately, there is always an edge case in which one would like to write an single script with the only contents being:
|
||||||
|
--start script--
|
||||||
|
import undetected_chromedriver as uc
|
||||||
|
d = uc.Chrome()
|
||||||
|
d.get('https://somesite/')
|
||||||
|
---end script --
|
||||||
|
|
||||||
|
and will be greeted with an error, since the program exists before chrome has a change to launch.
|
||||||
|
in that case you can set this to `True`. The browser will start via subprocess, and will keep running most of times.
|
||||||
|
! setting it to True comes with NO support when being detected. !
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
patcher = Patcher(
|
patcher = Patcher(
|
||||||
|
@ -336,7 +356,19 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
if not desired_capabilities:
|
if not desired_capabilities:
|
||||||
desired_capabilities = options.to_capabilities()
|
desired_capabilities = options.to_capabilities()
|
||||||
|
|
||||||
self.browser_pid = start_detached(options.binary_location, *options.arguments)
|
if not use_subprocess:
|
||||||
|
self.browser_pid = start_detached(options.binary_location, *options.arguments)
|
||||||
|
else:
|
||||||
|
browser = subprocess.Popen(
|
||||||
|
[options.binary_location, *options.arguments],
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
close_fds=IS_POSIX,
|
||||||
|
)
|
||||||
|
self.browser_pid = browser.pid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
super(Chrome, self).__init__(
|
super(Chrome, self).__init__(
|
||||||
executable_path=patcher.executable_path,
|
executable_path=patcher.executable_path,
|
||||||
|
@ -363,6 +395,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
self._configure_headless()
|
self._configure_headless()
|
||||||
|
|
||||||
def __getattribute__(self, item):
|
def __getattribute__(self, item):
|
||||||
|
|
||||||
if not super().__getattribute__("debug"):
|
if not super().__getattribute__("debug"):
|
||||||
return super().__getattribute__(item)
|
return super().__getattribute__(item)
|
||||||
else:
|
else:
|
||||||
|
@ -381,15 +414,6 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
return newfunc
|
return newfunc
|
||||||
return original
|
return original
|
||||||
|
|
||||||
# @property
|
|
||||||
# def switch_to(self):
|
|
||||||
# def callback():
|
|
||||||
# self.get(self.current_url)
|
|
||||||
# try:
|
|
||||||
# return super().switch_to
|
|
||||||
# finally:
|
|
||||||
# threading.Timer(.1, callback).start()
|
|
||||||
|
|
||||||
def _configure_headless(self):
|
def _configure_headless(self):
|
||||||
|
|
||||||
orig_get = self.get
|
orig_get = self.get
|
||||||
|
@ -536,7 +560,8 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
logger.debug("closing webdriver")
|
logger.debug("closing webdriver")
|
||||||
self.service.process.kill()
|
if hasattr(self, 'service') and getattr(self.service, 'process', None):
|
||||||
|
self.service.process.kill()
|
||||||
try:
|
try:
|
||||||
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")
|
||||||
|
@ -546,8 +571,6 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
try:
|
try:
|
||||||
logger.debug("killing browser")
|
logger.debug("killing browser")
|
||||||
os.kill(self.browser_pid, 15)
|
os.kill(self.browser_pid, 15)
|
||||||
# self.browser.terminate()
|
|
||||||
# self.browser.wait(1)
|
|
||||||
|
|
||||||
except TimeoutError as e:
|
except TimeoutError as e:
|
||||||
logger.debug(e, exc_info=True)
|
logger.debug(e, exc_info=True)
|
||||||
|
@ -583,19 +606,9 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
||||||
self.quit()
|
self.quit()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
try:
|
|
||||||
curframe = inspect.currentframe()
|
|
||||||
callframe = inspect.getouterframes(curframe, 2)
|
|
||||||
caller = callframe[1][3]
|
|
||||||
logging.getLogger(__name__).debug("__enter__ caller: %s" % caller)
|
|
||||||
if caller == "get":
|
|
||||||
return
|
|
||||||
except (AttributeError, ValueError, KeyError, OSError) as e:
|
|
||||||
logging.getLogger(__name__).debug(e)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
|
||||||
self.service.stop()
|
self.service.stop()
|
||||||
time.sleep(self._delay)
|
time.sleep(self._delay)
|
||||||
self.service.start()
|
self.service.start()
|
||||||
|
|
Loading…
Reference in New Issue