Browse Source

Fix chromedriver (#120)

* add appdirs for managing user data

* use cache_dir for downloading chromedriver

* cleanly shut down selenium when an exception happens
pull/121/head
Wesley Kerfoot 4 years ago
committed by GitHub
parent
commit
cc5a5b8b32
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      deletefb/deletefb.py
  2. 10
      deletefb/quit_driver.py
  3. 29
      deletefb/tools/chrome_driver.py
  4. 114
      deletefb/tools/login.py
  5. 6
      deletefb/version.py
  6. 2
      requirements.txt
  7. 3
      setup.py

37
deletefb/deletefb.py

@ -6,6 +6,7 @@ from .tools.login import login
from .tools.wall import delete_posts from .tools.wall import delete_posts
from .tools.conversations import traverse_conversations from .tools.conversations import traverse_conversations
from .tools.comments import delete_comments from .tools.comments import delete_comments
from .quit_driver import quit_driver_and_reap_children
import argparse import argparse
import getpass import getpass
@ -116,22 +117,26 @@ def run_delete():
chrome_binary_path=args.chromebin chrome_binary_path=args.chromebin
) )
if args.mode == "wall": try:
delete_posts( if args.mode == "wall":
driver, delete_posts(
args.profile_url, driver,
year=args.year args.profile_url,
) year=args.year
)
elif args.mode == "unlike_pages":
unlike_pages(driver, args.profile_url) elif args.mode == "unlike_pages":
unlike_pages(driver, args.profile_url)
elif args.mode == "conversations":
traverse_conversations(driver, year=args.year) elif args.mode == "conversations":
traverse_conversations(driver, year=args.year)
else:
print("Please enter a valid mode") else:
sys.exit(1) print("Please enter a valid mode")
sys.exit(1)
except:
if driver:
quit_driver_and_reap_children(driver)
if __name__ == "__main__": if __name__ == "__main__":
run_delete() run_delete()

10
deletefb/quit_driver.py

@ -0,0 +1,10 @@
import os
def quit_driver_and_reap_children(driver):
driver.quit()
try:
pid = True
while pid:
pid = os.waitpid(-1, os.WNOHANG)
except ChildProcessError:
pass

29
deletefb/tools/chrome_driver.py

@ -5,12 +5,22 @@ from selenium import webdriver
from shutil import which from shutil import which
from subprocess import check_output from subprocess import check_output
from urllib.request import urlretrieve from urllib.request import urlretrieve
from appdirs import AppDirs
from ..version import version
import os, sys, stat, platform import os, sys, stat, platform
import progressbar import progressbar
import re import re
import zipfile import zipfile
import requests import requests
import pathlib
cache_dir = AppDirs("DeleteFB", version=version).user_cache_dir
try:
pathlib.Path(cache_dir).mkdir(parents=True, exist_ok=True)
except FileExistsError:
pass
def extract_zip(filename): def extract_zip(filename):
""" """
@ -25,10 +35,10 @@ def extract_zip(filename):
sys.exit(1) sys.exit(1)
# Save the name of the new file # Save the name of the new file
new_file_name = _file.namelist()[0] new_file_name = f"{cache_dir}/{_file.namelist()[0]}"
# Extract the file and make it executable # Extract the file and make it executable
_file.extractall() _file.extractall(path=cache_dir)
driver_stat = os.stat(new_file_name) driver_stat = os.stat(new_file_name)
os.chmod(new_file_name, driver_stat.st_mode | stat.S_IEXEC) os.chmod(new_file_name, driver_stat.st_mode | stat.S_IEXEC)
@ -55,7 +65,6 @@ def get_chrome_version(chrome_binary_path=None):
driver_locations = [which(loc) for loc in ["google-chrome", "google-chrome-stable", "chromium", "chrome.exe"]] driver_locations = [which(loc) for loc in ["google-chrome", "google-chrome-stable", "chromium", "chrome.exe"]]
for location in driver_locations: for location in driver_locations:
print(location)
if location: if location:
return parse_version(check_output([location, "--version"]).strip()) return parse_version(check_output([location, "--version"]).strip())
return None return None
@ -94,17 +103,19 @@ def get_webdriver(chrome_binary_path):
Ensure a webdriver is available Ensure a webdriver is available
If Not, Download it. If Not, Download it.
""" """
cwd = os.listdir(os.getcwd())
webdriver_regex = re.compile('chromedriver') webdriver_regex = re.compile('chromedriver')
web_driver = list(filter(webdriver_regex.match, cwd))
web_driver = list(filter(webdriver_regex.match, cache_dir))
if web_driver: if web_driver:
# check if a extracted copy already exists # check if a extracted copy already exists
if not os.path.isfile('chromedriver'): if not os.path.isfile(f"{cache_dir}/chromedriver"):
# Extract file # Extract file
extract_zip(web_driver[0]) extract_zip(web_driver[0])
return "{0}/chromedriver".format(os.getcwd()) return "{0}/chromedriver".format(cache_dir)
else: else:
# Download it according to the current machine # Download it according to the current machine
@ -133,13 +144,13 @@ def get_webdriver(chrome_binary_path):
pbar.finish() pbar.finish()
puts(colored.yellow("Downloading Chrome Webdriver")) puts(colored.yellow("Downloading Chrome Webdriver"))
file_name = chrome_webdriver.split('/')[-1] file_name = f"{cache_dir}/{chrome_webdriver.split('/')[-1]}"
response = urlretrieve(chrome_webdriver, file_name, show_progress) response = urlretrieve(chrome_webdriver, file_name, show_progress)
if int(response[1].get("Content-Length")) == total_size: if int(response[1].get("Content-Length")) == total_size:
puts(colored.green("Completed downloading the Chrome Driver.")) puts(colored.green("Completed downloading the Chrome Driver."))
return "{0}/{1}".format(os.getcwd(), extract_zip(file_name)) return extract_zip(file_name)
else: else:
puts(colored.red("An error Occurred While trying to download the driver.")) puts(colored.red("An error Occurred While trying to download the driver."))

114
deletefb/tools/login.py

@ -1,6 +1,7 @@
from .chrome_driver import get_webdriver, setup_selenium from .chrome_driver import get_webdriver, setup_selenium
from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.options import Options
from ..quit_driver import quit_driver_and_reap_children
import time import time
@ -42,59 +43,62 @@ def login(user_email_address,
driver_path = get_webdriver(chrome_binary_path) driver_path = get_webdriver(chrome_binary_path)
driver = setup_selenium(driver_path, chrome_options) 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")
email = "email"
password = "pass"
login_button = "loginbutton"
approvals_code = "approvals_code"
driver.find_element_by_name(email).send_keys(user_email_address)
driver.find_element_by_name(password).send_keys(user_password)
driver.find_element_by_id(login_button).click()
# Defaults to no 2fa
has_2fa = False
try: try:
# If this element exists, we've reached a 2FA page driver.implicitly_wait(10)
driver.find_element_by_xpath("//form[@class=\"checkpoint\"]")
driver.find_element_by_xpath("//input[@name=\"approvals_code\"]") driver.get("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110")
has_2fa = True
except NoSuchElementException: email = "email"
has_2fa = "two-factor authentication" in driver.page_source.lower() or has_2fa password = "pass"
login_button = "loginbutton"
if has_2fa: approvals_code = "approvals_code"
print("""
Two-Factor Auth is enabled. driver.find_element_by_name(email).send_keys(user_email_address)
Please file an issue at https://github.com/weskerfoot/DeleteFB/issues if you run into any problems driver.find_element_by_name(password).send_keys(user_password)
""") driver.find_element_by_id(login_button).click()
if two_factor_token and has_2fa: # Defaults to no 2fa
twofactorelement = driver.find_element_by_name(approvals_code) has_2fa = False
twofactorelement.send_keys(two_factor_token)
try:
# Submits after the code is passed into the form, does not validate 2FA code. # If this element exists, we've reached a 2FA page
contelement = driver.find_element_by_id("checkpointSubmitButton") driver.find_element_by_xpath("//form[@class=\"checkpoint\"]")
contelement.click() driver.find_element_by_xpath("//input[@name=\"approvals_code\"]")
has_2fa = True
# Defaults to saving this new browser, this occurs on each new automated login. except NoSuchElementException:
save_browser = driver.find_element_by_id("checkpointSubmitButton") has_2fa = "two-factor authentication" in driver.page_source.lower() or has_2fa
save_browser.click()
elif has_2fa: if has_2fa:
# Allow time to enter 2FA code print("""
print("Pausing to enter 2FA code") Two-Factor Auth is enabled.
time.sleep(35) Please file an issue at https://github.com/weskerfoot/DeleteFB/issues if you run into any problems
print("Continuing execution") """)
else:
pass if two_factor_token and has_2fa:
twofactorelement = driver.find_element_by_name(approvals_code)
# block until we have reached the main page twofactorelement.send_keys(two_factor_token)
# print a message warning the user
while driver.current_url != "https://www.facebook.com/": # Submits after the code is passed into the form, does not validate 2FA code.
print("Execution blocked: Please navigate to https://www.facebook.com to continue") contelement = driver.find_element_by_id("checkpointSubmitButton")
time.sleep(5) contelement.click()
return driver # Defaults to saving this new browser, this occurs on each new automated login.
save_browser = driver.find_element_by_id("checkpointSubmitButton")
save_browser.click()
elif has_2fa:
# Allow time to enter 2FA code
print("Pausing to enter 2FA code")
time.sleep(35)
print("Continuing execution")
else:
pass
# block until we have reached the main page
# print a message warning the user
while driver.current_url != "https://www.facebook.com/":
print("Execution blocked: Please navigate to https://www.facebook.com to continue")
time.sleep(5)
return driver
except:
quit_driver_and_reap_children(driver)

6
deletefb/version.py

@ -0,0 +1,6 @@
import pkg_resources # part of setuptools
try:
version = pkg_resources.require("delete-facebook-posts")[0].version
except pkg_resources.DistributionNotFound:
version = "source"

2
requirements.txt

@ -1,3 +1,5 @@
appdirs==1.4.3
args==0.1.0
attrs==19.1.0 attrs==19.1.0
bitarray==0.9.3 bitarray==0.9.3
bleach==3.1.1 bleach==3.1.1

3
setup.py

@ -29,7 +29,8 @@ setuptools.setup(
"lxml", "lxml",
"pendulum", "pendulum",
"clint", "clint",
"progressbar" "progressbar",
"appdirs"
], ],
classifiers= [ classifiers= [
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",

Loading…
Cancel
Save