From 511b43a9f14c648f3e6a55fe13b983b32b92b378 Mon Sep 17 00:00:00 2001 From: esir Date: Sat, 9 Nov 2019 09:50:50 +0300 Subject: [PATCH 1/4] Automatically downloads chrome driver for users according the their os platform --- deletefb/tools/chrome_driver.py | 111 ++++++++++++++++++++++++++++++++ deletefb/tools/common.py | 10 +-- deletefb/tools/login.py | 17 ++--- 3 files changed, 122 insertions(+), 16 deletions(-) create mode 100644 deletefb/tools/chrome_driver.py diff --git a/deletefb/tools/chrome_driver.py b/deletefb/tools/chrome_driver.py new file mode 100644 index 0000000..ddd8fc1 --- /dev/null +++ b/deletefb/tools/chrome_driver.py @@ -0,0 +1,111 @@ +import re +import zipfile +import os, sys, stat, platform +from urllib.request import urlretrieve + +from clint.textui import puts, colored +import progressbar + +from selenium import webdriver +from selenium.webdriver.chrome.options import Options + +from .common import NO_CHROME_DRIVER + + +def extract_zip(filename): + """ + Uses zipfile package to extract a single zipfile + :param filename: + :return: new filename + """ + try: + file = zipfile.ZipFile(filename, 'r') + except FileNotFoundError: + puts(colored.red(f"{filename} Does not exist")) + sys.exit() + + # Save the name of the new file + new_file_name = file.namelist()[0] + + # Extract the file and make it executable + file.extractall() + + driver_stat = os.stat(new_file_name) + os.chmod(new_file_name, driver_stat.st_mode | stat.S_IEXEC) + + file.close() + os.remove(filename) + return new_file_name + + +def setup_selenium(driver_path, options): + # Configures selenium to use a custom path + driver = webdriver.Chrome(executable_path=driver_path, options=options) + return driver + + +def get_webdriver(): + """ + Ensure a webdriver is available + If Not, Download it. + """ + cwd = os.listdir(os.getcwd()) + webdriver_regex = re.compile('chromedriver') + web_driver = list(filter(webdriver_regex.match, cwd)) + + if web_driver: + # check if a extracted copy already exists + if not os.path.isfile('chromedriver'): + # Extract file + extract_zip(web_driver[0]) + + return os.getcwd() + '/chromedriver' + + else: + # Download it according to the current machine + webdrivers = ['https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_mac64.zip', + 'https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_linux64.zip', + 'https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_win32.zip' + ] + os_platform = platform.system() + if os_platform == 'Darwin': + chrome_webdriver = webdrivers[0] + elif os_platform == 'Linux': + chrome_webdriver = webdrivers[1] + elif os_platform == 'Windows': + chrome_webdriver = webdrivers[2] + else: + raise Exception("Unknown Operating system platform") + + global total_size + + def show_progress(*res): + global total_size + pbar = None + downloaded = 0 + block_num, block_size, total_size = res + + if not pbar: + pbar = progressbar.ProgressBar(maxval=total_size) + pbar.start() + downloaded += block_num * block_size + + if downloaded < total_size: + pbar.update(downloaded) + else: + pbar.finish() + + puts(colored.yellow("Downloading Chrome Webdriver")) + file_name = chrome_webdriver.split('/')[-1] + response = urlretrieve(chrome_webdriver, file_name, show_progress) + + if int(response[1].get('Content-Length')) == total_size: + puts(colored.green(f"DONE!")) + + return os.getcwd() + '/' + extract_zip(file_name) + else: + puts(colored.red("An error Occurred While trying to download the driver.")) + # remove the downloaded file and exit + os.remove(file_name) + sys.stderr.write(NO_CHROME_DRIVER) + sys.exit(1) diff --git a/deletefb/tools/common.py b/deletefb/tools/common.py index de0d679..bb24989 100644 --- a/deletefb/tools/common.py +++ b/deletefb/tools/common.py @@ -5,15 +5,13 @@ from selenium.webdriver.common.by import By from selenium.common.exceptions import ( NoSuchElementException, StaleElementReferenceException, - TimeoutException, - JavascriptException + TimeoutException ) import json import logging import logging.config import os -import pendulum SELENIUM_EXCEPTIONS = ( NoSuchElementException, @@ -21,12 +19,14 @@ SELENIUM_EXCEPTIONS = ( TimeoutException ) + def click_button(driver, el): """ Click a button using Javascript """ driver.execute_script("arguments[0].click();", el) + def scroll_to(driver, el): """ Scroll an element into view, using JS @@ -36,6 +36,7 @@ def scroll_to(driver, el): except SELENIUM_EXCEPTIONS: return + def logger(name): """ Args: @@ -66,7 +67,8 @@ def wait_xpath(driver, expr): except SELENIUM_EXCEPTIONS: return + NO_CHROME_DRIVER = """ -You need to install the chromedriver for Selenium\n +You need to manually install the chromedriver for Selenium\n Please see this link https://github.com/weskerfoot/DeleteFB#how-to-use-it\n """ diff --git a/deletefb/tools/login.py b/deletefb/tools/login.py index 772b53e..2d3f39c 100644 --- a/deletefb/tools/login.py +++ b/deletefb/tools/login.py @@ -1,11 +1,11 @@ -from .common import NO_CHROME_DRIVER from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.chrome.options import Options -from seleniumrequests import Chrome -import sys import time +from .chrome_driver import get_webdriver, setup_selenium + + def login(user_email_address, user_password, is_headless, @@ -34,15 +34,8 @@ def login(user_email_address, chrome_options.add_argument('--disable-gpu') chrome_options.add_argument('log-level=2') - try: - driver = Chrome(options=chrome_options) - except Exception as e: - # The user does not have chromedriver installed - # Tell them to install it - sys.stderr.write(str(e)) - sys.stderr.write(NO_CHROME_DRIVER) - sys.exit(1) - + driver_path = get_webdriver() + driver = setup_selenium(driver_path, chrome_options) driver.implicitly_wait(10) driver.get("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110") From 6ce333780d3f58ba54318a3e6351f771fa88896c Mon Sep 17 00:00:00 2001 From: esir Date: Sat, 9 Nov 2019 11:14:07 +0300 Subject: [PATCH 2/4] Include dependencies added --- requirements.txt | 2 ++ setup.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9b578c6..25df0c8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,11 +4,13 @@ bleach==3.1.0 cattrs==0.9.0 certifi==2018.11.29 chardet==3.0.4 +clint==0.5.1 docutils==0.14 idna==2.8 lxml==4.4.0 pendulum==2.0.5 pkginfo==1.5.0.1 +progressbar==2.5 pybloom-live==3.0.0 Pygments==2.4.2 python-dateutil==2.8.0 diff --git a/setup.py b/setup.py index b83d23b..49e119d 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,9 @@ setuptools.setup( "attrs", "cattrs", "lxml", - "pendulum" + "pendulum", + "clint", + "progressbar" ], classifiers= [ "Programming Language :: Python :: 3", From 6340d2c50acd6e71b914a4cd61dfd7457ee83103 Mon Sep 17 00:00:00 2001 From: esir Date: Sun, 10 Nov 2019 16:41:38 +0300 Subject: [PATCH 3/4] Adds a custom exceptions class --- deletefb/exceptions.py | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 deletefb/exceptions.py diff --git a/deletefb/exceptions.py b/deletefb/exceptions.py new file mode 100644 index 0000000..6f22085 --- /dev/null +++ b/deletefb/exceptions.py @@ -0,0 +1,2 @@ +class UnknownOSException(Exception): + pass From d08d8861d4f398856e8df4c6c5caa221f3e661e9 Mon Sep 17 00:00:00 2001 From: esir Date: Sun, 10 Nov 2019 16:42:45 +0300 Subject: [PATCH 4/4] Code cleanup --- deletefb/tools/chrome_driver.py | 42 +++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/deletefb/tools/chrome_driver.py b/deletefb/tools/chrome_driver.py index ddd8fc1..d6549ba 100644 --- a/deletefb/tools/chrome_driver.py +++ b/deletefb/tools/chrome_driver.py @@ -2,14 +2,23 @@ import re import zipfile import os, sys, stat, platform from urllib.request import urlretrieve +from collections import namedtuple from clint.textui import puts, colored import progressbar from selenium import webdriver -from selenium.webdriver.chrome.options import Options from .common import NO_CHROME_DRIVER +from ..exceptions import UnknownOSException + + +_ = namedtuple('WebDrivers', 'mac linux windows') +drivers = ['https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_mac64.zip', + 'https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_linux64.zip', + 'https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_win32.zip' + ] +WebDriver = _(drivers[0], drivers[1], drivers[2]) def extract_zip(filename): @@ -19,29 +28,28 @@ def extract_zip(filename): :return: new filename """ try: - file = zipfile.ZipFile(filename, 'r') + _file = zipfile.ZipFile(filename, 'r') except FileNotFoundError: puts(colored.red(f"{filename} Does not exist")) - sys.exit() + sys.exit(1) # Save the name of the new file - new_file_name = file.namelist()[0] + new_file_name = _file.namelist()[0] # Extract the file and make it executable - file.extractall() + _file.extractall() driver_stat = os.stat(new_file_name) os.chmod(new_file_name, driver_stat.st_mode | stat.S_IEXEC) - file.close() + _file.close() os.remove(filename) return new_file_name def setup_selenium(driver_path, options): # Configures selenium to use a custom path - driver = webdriver.Chrome(executable_path=driver_path, options=options) - return driver + return webdriver.Chrome(executable_path=driver_path, options=options) def get_webdriver(): @@ -59,23 +67,20 @@ def get_webdriver(): # Extract file extract_zip(web_driver[0]) - return os.getcwd() + '/chromedriver' + return "{0}/chromedriver".format(os.getcwd()) else: # Download it according to the current machine - webdrivers = ['https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_mac64.zip', - 'https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_linux64.zip', - 'https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_win32.zip' - ] + os_platform = platform.system() if os_platform == 'Darwin': - chrome_webdriver = webdrivers[0] + chrome_webdriver = WebDriver.mac elif os_platform == 'Linux': - chrome_webdriver = webdrivers[1] + chrome_webdriver = WebDriver.linux elif os_platform == 'Windows': - chrome_webdriver = webdrivers[2] + chrome_webdriver = WebDriver.windows else: - raise Exception("Unknown Operating system platform") + raise UnknownOSException("Unknown Operating system platform") global total_size @@ -102,7 +107,8 @@ def get_webdriver(): if int(response[1].get('Content-Length')) == total_size: puts(colored.green(f"DONE!")) - return os.getcwd() + '/' + extract_zip(file_name) + return "{0}/{1}".format(os.getcwd(), extract_zip(file_name)) + else: puts(colored.red("An error Occurred While trying to download the driver.")) # remove the downloaded file and exit