File size: 5,673 Bytes
e04d1b2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3760d60
 
8a13329
e04d1b2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"""Gets the browser's given the user's input"""
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium.webdriver.safari.options import Options as SafariOptions
from selenium.webdriver.edge.options import Options as EdgeOptions

# Webdriver managers
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.firefox.service import Service as FirefoxService
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium.webdriver.edge.service import Service as EdgeService

from selenium import webdriver

import toml
config = toml.load("./config.toml")
from proxy_auth_extension.proxy_auth_extension import generate_proxy_auth_extension


def get_browser(name: str = 'chrome', options=None, *args, **kwargs) -> webdriver:
    """
    Gets a browser based on the name with the ability to pass in additional arguments
    """

    # get the web driver for the browser
    driver_to_use = get_driver(name=name, *args, **kwargs)

    # gets the options for the browser

    options = options or get_default_options(name=name, *args, **kwargs)

    # combines them together into a completed driver
    service = False#get_service(name=name)
    if service:
        driver = driver_to_use(service=service, options=options)
    else:
        driver = driver_to_use(options=options)

    driver.implicitly_wait(config['implicit_wait'])

    return driver


def get_driver(name: str = 'chrome', *args, **kwargs) -> webdriver:
    """
    Gets the web driver function for the browser
    """
    if _clean_name(name) in drivers:
        return drivers[name]

    raise UnsupportedBrowserException()


def get_service(name: str = 'chrome'):
    """
    Gets a service to install the browser driver per webdriver-manager docs

    https://pypi.org/project/webdriver-manager/
    """
    if _clean_name(name) in services:
        return services[name]()

    return None # Safari doesn't need a service


def get_default_options(name: str, *args, **kwargs):
    """
    Gets the default options for each browser to help remain undetected
    """
    name = _clean_name(name)

    if name in defaults:
        return defaults[name](*args, **kwargs)

    raise UnsupportedBrowserException()


def chrome_defaults(*args, headless: bool = False, proxy: dict = None, **kwargs) -> ChromeOptions:
    """
    Creates Chrome with Options
    """

    options = ChromeOptions()

    ## regular
    options.add_argument('--disable-blink-features=AutomationControlled')
    options.add_argument('--profile-directory=Default')

    ## experimental
    options.add_experimental_option('excludeSwitches', ['enable-automation'])
    options.add_experimental_option('useAutomationExtension', False)

    # headless
    if headless:
        options.add_argument('--headless=new')
    if proxy:
        if 'user' in proxy.keys() and 'pass' in proxy.keys():
            # This can fail if you are executing the function more than once in the same time
            extension_file = 'temp_proxy_auth_extension.zip'
            generate_proxy_auth_extension(proxy['host'], proxy['port'], proxy['user'], proxy['pass'], extension_file)
            options.add_extension(extension_file)
        else:
            options.add_argument(f'--proxy-server={proxy["host"]}:{proxy["port"]}')

    return options


def firefox_defaults(*args, headless: bool = False, proxy: dict = None, **kwargs) -> FirefoxOptions:
    """
    Creates Firefox with default options
    """

    options = FirefoxOptions()

    # default options

    if headless:
        options.add_argument('--headless')
    if proxy:
        raise NotImplementedError('Proxy support is not implemented for this browser')
    return options


def safari_defaults(*args, headless: bool = False, proxy: dict = None, **kwargs) -> SafariOptions:
    """
    Creates Safari with default options
    """
    options = SafariOptions()

    # default options

    if headless:
        options.add_argument('--headless')
    if proxy:
        raise NotImplementedError('Proxy support is not implemented for this browser')
    return options


def edge_defaults(*args, headless: bool = False, proxy: dict = None, **kwargs) -> EdgeOptions:
    """
    Creates Edge with default options
    """
    options = EdgeOptions()

    # default options

    if headless:
        options.add_argument('--headless')
    if proxy:
        raise NotImplementedError('Proxy support is not implemented for this browser')
    return options

# Misc
class UnsupportedBrowserException(Exception):
    """
    Browser is not supported by the library

    Supported browsers are:
        - Chrome
        - Firefox
        - Safari
        - Edge
    """

    def __init__(self, message=None):
        super().__init__(message or self.__doc__)


def _clean_name(name: str) -> str:
    """
    Cleans the name of the browser to make it easier to use
    """
    return name.strip().lower()


drivers = {
    'chrome': webdriver.Chrome,
    'firefox': webdriver.Firefox,
    'safari': webdriver.Safari,
    'edge': webdriver.ChromiumEdge,
}

defaults = {
    'chrome': chrome_defaults,
    'firefox': firefox_defaults,
    'safari': safari_defaults,
    'edge': edge_defaults,
}


services = {
    'chrome': lambda : ChromeService(ChromeDriverManager().install()),
    'firefox': lambda : FirefoxService(GeckoDriverManager().install()),
    'edge': lambda : EdgeService(EdgeChromiumDriverManager().install()),
}