Add files via upload

This commit is contained in:
Leon 2019-12-22 13:48:58 +01:00 committed by GitHub
parent 3d3d1aeca8
commit d7a826db47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 271 additions and 0 deletions

271
__init__.py Normal file
View File

@ -0,0 +1,271 @@
#!/usr/bin/env python3
"""
888 888 d8b
888 888 Y8P
888 888
.d8888b 88888b. 888d888 .d88b. 88888b.d88b. .d88b. .d88888 888d888 888 888 888 .d88b. 888d888
d88P" 888 "88b 888P" d88""88b 888 "888 "88b d8P Y8b d88" 888 888P" 888 888 888 d8P Y8b 888P"
888 888 888 888 888 888 888 888 888 88888888 888 888 888 888 Y88 88P 88888888 888
Y88b. 888 888 888 Y88..88P 888 888 888 Y8b. Y88b 888 888 888 Y8bd8P Y8b. 888
"Y8888P 888 888 888 "Y88P" 888 888 888 "Y8888 "Y88888 888 888 Y88P "Y8888 888 88888888
888 d8b 888 888
888 Y8P 888 888
888 888 888
88888b. 888 .d88888 .d88888 .d88b. 88888b.
888 "88b 888 d88" 888 d88" 888 d8P Y8b 888 "88b
888 888 888 888 888 888 888 88888888 888 888
888 888 888 Y88b 888 Y88b 888 Y8b. 888 888
888 888 888 "Y88888 "Y88888 "Y8888 888 888
BY ULTRAFUNKAMSTERDAM (https://github.com/ultrafunkamsterdam)
##################################################################
Optimized Selenium Chromedriver patch which does not trigger anti-bot services like Distill Network.
Automatically downloads the driver binary and patches it.
Not tested on Chrome higher than 79!
#################################################################
USAGE
# 1- by far the easiest
from undetected_chromedriver import Chrome, ChromeOptions
driver = Chrome()
driver.get('https://distilnetworks.com')
# 2- patches current selenium instance (for current session)
import undetected_chromedriver
undetected_chromedriver.install()
from selenium.webdriver import Chrome
driver = Chrome()
driver.get('https://distilnetworks.com')
# 3 - Customized
import undetected_chromedriver
#specify chromedriver version to download and patch
undetected_chromedriver.TARGET_VERSION = 78
# or specify your own chromedriver binary to patch
undetected_chromedriver.install(
executable_path='c:/users/user1/chromedriver.exe',
target_version=78
)
from selenium.webdriver import Chrome, ChromeOptions
opts = ChromeOptions()
opts.add_argument(f'--proxy-server=socks5://127.0.0.1:9050')
driver = Chrome(options=opts)
driver.get('https://distilnetworks.com')
a combination of function(s) from this module :)
"""
import io
import logging
import os
import sys
import zipfile
from urllib.request import urlopen, urlretrieve
from selenium.webdriver import Chrome as _Chrome
from selenium.webdriver import ChromeOptions as _ChromeOptions
_DL_BASE = "https://chromedriver.storage.googleapis.com/"
TARGET_VERSION = 79
__is_patched__ = 0
class Chrome:
def __new__(cls, *args, **kwargs):
if not ChromeDriverManager.installed:
ChromeDriverManager(*args, **kwargs).install()
if not ChromeDriverManager.selenium_patched:
ChromeDriverManager(*args, **kwargs).patch_selenium_webdriver()
instance = object.__new__(_Chrome)
instance.__init__(*args, **kwargs)
instance.execute_cdp_cmd(
"Page.addScriptToEvaluateOnNewDocument",
{
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
},
)
original_user_agent_string = instance.execute_script(
"return navigator.userAgent"
)
instance.execute_cdp_cmd(
"Network.setUserAgentOverride",
{
"userAgent": original_user_agent_string.replace("Headless", ""),
"platform": "Windows",
},
)
print(f"starting webdriver instance Chrome({args}, {kwargs})")
return instance
class ChromeOptions:
def __new__(cls, *args, **kwargs):
if not ChromeDriverManager.installed:
ChromeDriverManager(*args, **kwargs).install()
if not ChromeDriverManager.selenium_patched:
ChromeDriverManager(*args, **kwargs).patch_selenium_webdriver()
instance = object.__new__(_ChromeOptions)
instance.__init__()
print(f"starting options instance ChromeOptions({args}, {kwargs})")
return instance
# return _ChromeOptions()
class ChromeDriverManager(object):
installed = False
selenium_patched = False
def __init__(self, executable_path=None, target_version=None, *args, **kwargs):
self.executable_path = executable_path or "chromedriver.exe"
self.platform = sys.platform
self.target_version = target_version
def patch_selenium_webdriver(self_):
"""
Patches existing webdriver path on <executable_path> OR if executable_path is None, will download
and patch a new webdriver binary for chrome <version_int> (automatically finds latest release of main version)
:param str executable_path: OPTIONAL path to existing chromedriver executable to patch
:param int version_int: OPTIONAL target chrome main version. default 79
:return:
"""
import selenium.webdriver.chrome.service
import selenium.webdriver
# Monkeypatching ChromeDriver Service
if self_.__class__.selenium_patched:
return
Service__init__ = selenium.webdriver.chrome.service.Service.__init__
def patched_Service__init__(self, *a, **k):
logging.warning("Using patched ChromeDriver Service class")
Service__init__(self, self_.executable_path, **k)
selenium.webdriver.chrome.service.Service.__init__ = patched_Service__init__
# monkeypatching ChromeOptions
ChromeOptions__init__ = selenium.webdriver.ChromeOptions.__init__
def patched_ChromeOptions__init__(self):
logging.warning("Using patched ChromeOptions class")
ChromeOptions__init__(self)
self.add_argument("start-maximized")
self.add_experimental_option("excludeSwitches", ["enable-automation"])
self.add_experimental_option("useAutomationExtension", False)
selenium.webdriver.ChromeOptions.__init__ = patched_ChromeOptions__init__
logging.warning(
"Now it is safe to import Chrome and ChromeOptions from selenium"
)
self_.__class__.selenium_patched = True
def install(self, patch_selenium=True):
"""
Initialize the patch
This will:
download chromedriver if not present
patch the downloaded chromedriver
patch selenium package if <patch_selenium> is True (default)
:param patch_selenium: patch selenium webdriver classes for Chrome and ChromeDriver (for current python session)
:return:
"""
if (
not self.__class__.installed
or not __is_patched__
or not os.path.exists(self.executable_path)
):
self.fetch_chromedriver()
self.patch_binary()
self.__class__.installed = True
if patch_selenium:
self.patch_selenium_webdriver()
def get_release_version_number(self):
"""
Gets the latest major version available, or the latest major version of self.target_version if set explicitly.
:return: version string
"""
path = (
"LATEST_RELEASE"
if not self.target_version
else f"LATEST_RELEASE_{self.target_version}"
)
return urlopen(_DL_BASE + path).read().decode()
def fetch_chromedriver(self):
"""
Downloads ChromeDriver from source and unpacks the executable
:return: on success, name of the unpacked executable
"""
base_ = "chromedriver{}"
exe_name = base_.format(".exe")
zip_name = base_.format(".zip")
ver = self.get_release_version_number()
urlretrieve(
f"{_DL_BASE}{ver}/{base_.format(f'_{self.platform}')}.zip",
filename=zip_name,
)
with zipfile.ZipFile(zip_name) as zf:
zf.extract(exe_name)
os.remove(zip_name)
return exe_name
def patch_binary(self):
"""
Patches the ChromeDriver binary
:return: False on failure, binary name on success
"""
if self.__class__.installed:
return
with io.open(self.executable_path, "r+b") as binary:
for line in iter(lambda: binary.readline(), b""):
if b"cdc_" in line:
binary.seek(-len(line), 1)
line = b" var key = '$azc_abcdefghijklmnopQRstuv_';\n"
binary.write(line)
__is_patched__ = 1
break
else:
return False
return True
def install(executable_path=None, target_version=TARGET_VERSION, *args, **kwargs):
ChromeDriverManager(executable_path, target_version, *args, **kwargs).install()