Skip to content
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

Fix kit #1655

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Fix kit #1655

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 17 additions & 4 deletions undetected_chromedriver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def __init__(
if no_sandbox:
options.arguments.extend(["--no-sandbox", "--test-type"])

if headless or options.headless:
if headless or (hasattr(options, 'headless') and options.headless):
#workaround until a better checking is found
try:
if self.patcher.version_main < 108:
Expand All @@ -406,6 +406,8 @@ def __init__(
logger.warning("could not detect version_main."
"therefore, we are assuming it is chrome 108 or higher")
options.add_argument("--headless=new")
else:
options.headless = False

options.add_argument("--window-size=1920,1080")
options.add_argument("--start-maximized")
Expand Down Expand Up @@ -485,7 +487,7 @@ def __init__(
else:
self._web_element_cls = WebElement

if options.headless:
if hasattr(options, 'headless') and options.headless:
self._configure_headless()

def _configure_headless(self):
Expand Down Expand Up @@ -764,8 +766,9 @@ def search_frame(f=None):
def quit(self):
try:
self.service.process.kill()
os.waitpid(self.service.process.pid, 0)
logger.debug("webdriver process ended")
except (AttributeError, RuntimeError, OSError):
except (AttributeError, ChildProcessError, RuntimeError, OSError):
pass
try:
self.reactor.event.set()
Expand All @@ -774,6 +777,7 @@ def quit(self):
pass
try:
os.kill(self.browser_pid, 15)
os.waitpid(self.browser_pid, 0)
logger.debug("gracefully closed browser")
except Exception as e: # noqa
pass
Expand All @@ -795,7 +799,10 @@ def quit(self):
else:
logger.debug("successfully removed %s" % self.user_data_dir)
break
time.sleep(0.1)
try:
time.sleep(1)
except OSError:
pass

# dereference patcher, so patcher can start cleaning up as well.
# this must come last, otherwise it will throw 'in use' errors
Expand Down Expand Up @@ -852,6 +859,12 @@ def _ensure_close(cls, self):
and hasattr(self.service.process, "kill")
):
self.service.process.kill()

try:
# Prevent zombie processes
os.waitpid(self.service.process.pid, 0)
except ChildProcessError:
pass


def find_chrome_executable():
Expand Down
54 changes: 37 additions & 17 deletions undetected_chromedriver/patcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
import sys
import time
from urllib.request import urlopen
from urllib.request import urlretrieve
import zipfile
from multiprocessing import Lock
import requests

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -45,7 +45,7 @@ def __init__(
self,
executable_path=None,
force=False,
version_main: int = 0,
version_main=None,
user_multi_procs=False,
):
"""
Expand All @@ -61,8 +61,17 @@ def __init__(
self._custom_exe_path = False
prefix = "undetected"
self.user_multi_procs = user_multi_procs

self.is_old_chromedriver = version_main and version_main <= 114

if version_main is not None:
if isinstance(version_main, (float, int, str)):
version_main = int(version_main)
self.is_old_chromedriver = version_main <= 114
else:
raise ValueError("version_main must be an integer or string")
else:
version_main = 0
self.is_old_chromedriver = False

# Needs to be called before self.exe_name is accessed
self._set_platform_name()

Expand Down Expand Up @@ -129,16 +138,6 @@ def auto(self, executable_path=None, force=False, version_main=None, _=None):
Returns:

"""
p = pathlib.Path(self.data_path)
if self.user_multi_procs:
with Lock():
files = list(p.rglob("*chromedriver*"))
most_recent = max(files, key=lambda f: f.stat().st_mtime)
files.remove(most_recent)
list(map(lambda f: f.unlink(), files))
if self.is_binary_patched(most_recent):
self.executable_path = str(most_recent)
return True

if executable_path:
self.executable_path = executable_path
Expand All @@ -151,6 +150,17 @@ def auto(self, executable_path=None, force=False, version_main=None, _=None):
else:
return

p = pathlib.Path(self.data_path)
if self.user_multi_procs:
with Lock():
files = list(p.rglob("*chromedriver*"))
most_recent = max(files, key=lambda f: f.stat().st_mtime)
files.remove(most_recent)
list(map(lambda f: f.unlink(), files))
if self.is_binary_patched(most_recent):
self.executable_path = str(most_recent)
return True

if version_main:
self.version_main = version_main
if force is True:
Expand Down Expand Up @@ -269,6 +279,15 @@ def parse_exe_version(self):
if match:
return LooseVersion(match[1].decode())

def download_file(self, url):
local_filename = url.split('/')[-1]
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
return local_filename

def fetch_package(self):
"""
Downloads ChromeDriver from source
Expand All @@ -283,9 +302,10 @@ def fetch_package(self):
download_url = "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/%s/%s/%s"
download_url %= (self.version_full.vstring, self.platform_name, zip_name)

logger.debug("downloading from %s" % download_url)
return urlretrieve(download_url)[0]

# Download the file with someone more reliable than urlretrieve
# https://stackoverflow.com/a/39217788/9263761
return self.download_file(download_url)

def unzip_package(self, fp):
"""
Does what it says
Expand Down