ABSP, Ch 18, Practice Project #1

My solution to the Practice Project #1 in Chapter 18 of the excellent book “Automate the Boring Stuff with Python” (ABSP)

#! usr/bin/env python3
# by lorenzo - 23/10/2017
# script that nudges the mouse cursor slightly every ten seconds


import pyautogui, time

print("Move the cursor to the upper-left corner of the screen to stop.")
pyautogui.FAILSAFE = True
try:
    while True:
        pyautogui.moveRel(10, 0, duration=1)
        pyautogui.moveRel(-10, 0, duration=1)
        time.sleep(10)

except pyautogui.FailSafeException:
    print("\nDone")

Comments about the code are welcome.

ABSP, Ch 13, Practice Project #3

My solution to the Practice Project #3 in Chapter 13 of the excellent book “Automate the Boring Stuff with Python” (ABSP)

import os, sys, PyPDF2, time

print("Enter location of the dictionary (ex: .../dictionary.txt):")
dictLoc = input()
if not os.path.isfile(dictLoc):
    print("Invalid location for dictionary!")
    sys.exit()

print("Enter location of PDF file to decrypt:")
pdfLoc = input()
if not os.path.isfile(pdfLoc):
    print("Invalid location for PDF file!")
    sys.exit()

pdfFile = open(pdfLoc, "rb")
pdfReader = PyPDF2.PdfFileReader(pdfFile)
if pdfReader.isEncrypted != True:
    print("PDF file: " + os.path.basename(pdfLoc) + " is not encrypted!")
    sys.exit()
keysFile = open(dictLoc)
allKeysNewline = keysFile.readlines() # each entry contains a newline "\n" at the end
keysFile.close()
allKeys = []
for i in range(len(allKeysNewline)):
    allKeys.append(allKeysNewline[i].rstrip("\n"))
startTime = time.time()
for key in allKeys:
    if pdfReader.decrypt(key.upper()) == 1:
        print(key.upper() + " is the password")
        endTime = time.time()
        print("It took %s seconds to find the password." % round(endTime-startTime,2))
        sys.exit()
    elif pdfReader.decrypt(key.lower()) == 1:
        print(key.lower() + " is the password")
        endTime = time.time()
        print("It took %s seconds to find the password." % round(endTime-startTime,2))
        sys.exit()
    else:
        continue

print("Sorry, the password of the PDF is not in the dictionary.")

Comments about the code are welcome.

ABSP, Ch 13, Practice Project #1

My solution to the Practice Project #1 in Chapter 13 of the excellent book “Automate the Boring Stuff with Python” (ABSP)

#! usr/bin/env python3
# by lorenzo - 13/10/2017
# go through every PDF in a folder (and its subfolders)
# and encrypt the PDFs using a password provided on the command line

import os, PyPDF2, sys, send2trash

directory = sys.argv[1]
password = sys.argv[2]

if not os.path.isdir(directory):
    print("Invalid directory!")
    sys.exit()

for folderName, subfolders, filenames in os.walk(directory):
    for filename in filenames:
        if filename.endswith(".pdf"):
            pdfFile = open(os.path.join(folderName, filename), "rb")
            pdfReader = PyPDF2.PdfFileReader(pdfFile)
            pdfWriter = PyPDF2.PdfFileWriter()
            if pdfReader.isEncrypted == True:
                continue
            for pageNum in range(pdfReader.numPages):
                pdfWriter.addPage(pdfReader.getPage(pageNum))
            pdfWriter.encrypt(password)
            pdfResult = open(folderName + "/" + filename[:-4] + "_encrypted.pdf", "wb")
            pdfWriter.write(pdfResult)
            pdfResult.close()
            pdfFile.close()

            pdfFile = open(folderName + "/" + filename[:-4] + "_encrypted.pdf", "rb")
            pdfReader = PyPDF2.PdfFileReader(pdfFile)
            if pdfReader.isEncrypted == True and pdfReader.decrypt(password) == 1:
                print("File " + filename + " encrypted correctly")
                send2trash.send2trash(os.path.join(folderName, filename))
                pdfFile.close()
            else:
                print("File " + filename + " not encrypted correctly")
                pdfFile.close()
#! usr/bin/env python3
# by lorenzo - 13/10/2017
# finds all encrypted PDFs in a folder (and its subfolders)
# and creates a decrypted copy of the PDF using a provided password

import os, PyPDF2, sys, send2trash

directory = sys.argv[1]
password = sys.argv[2]

if not os.path.isdir(directory):
    print("Invalid directory!")
    sys.exit()

for folderName, subfolders, filenames in os.walk(directory):
    for filename in filenames:
        if filename.endswith(".pdf"):
            pdfFile = open(os.path.join(folderName, filename), "rb")
            pdfReader = PyPDF2.PdfFileReader(pdfFile)
            pdfWriter = PyPDF2.PdfFileWriter()
            if pdfReader.isEncrypted == True:
                if pdfReader.decrypt(password) == 1:
                    print("File " + os.path.join(folderName, filename) + " correctly decrypted")
                    pdfReader.decrypt(password)
                    for pageNum in range(pdfReader.numPages):
                        pdfWriter.addPage(pdfReader.getPage(pageNum))
                    pdfResult = open(folderName + "/" + filename[:-4] + "_decrypted.pdf", "wb")
                    pdfWriter.write(pdfResult)
                    pdfFile.close()
                else:
                    print("File: " + os.path.join(folderName, filename) + " not correctly decrypted")

Comments about the code are welcome.

ABSP, Ch 11, Practice Project #1

My solution to the Practice Project #1 in Chapter 11 of the excellent book “Automate the Boring Stuff with Python” (ABSP)

#! usr/bin/env python3
# by lorenzo - 10/10/2017
# command line emailer

from selenium import webdriver

print("Enter e-mail address of recipient:")
recipient = input()
print("Enter subject of the e-mail:")
subject = input()
print("Enter text of the e-mail:")
emailText = input()

browser = webdriver.Firefox()
browser.get("myEmailProvider")
emailElem = browser.find_element_by_id("usernameDisplay")
emailElem.send_keys("myUsername")
passwordElem = browser.find_element_by_id("password")
passwordElem.send_keys("myPassword")
passwordElem.submit()

# I've successfully tested the code up to this point
# because I haven't been able to make selenium click on the "Write" button.
# I will try to amend the code asap

writeElem = browser.find_element_by_class_name("write") # this doesn't work 😦
writeElem.click()
recipientElem = browser.find_element_by_id("composeTO")
recipientElem.send_keys(recipient)
subjectElem = browser.find_element_by_id("composeSUBJECT")
subjectElem.send_keys(subject)
messageElem = browser.find_element_by_id("messageComposeEditor")
messageElem.send_keys(emailText)
sendElem = browser.find_element_by_class_name("sendNormalmail")
sendElem.click()
exitElems = browser.find_element_by_class_name("exit")
exitElems.click()
browser.quit()

NOTE:

  • to make send_keys work properly* set the default language of the computer to “English”
  • to make browser = webdriver.Firefox() work properly install geckodriver with the following command: brew install geckodriver

*otherwise it might eat some of the characters that you want selenium to write

ABSP, Ch 11, Practice Project #2

My solution to the Practice Project #2 in Chapter 11 of the excellent book “Automate the Boring Stuff with Python” (ABSP)

#! usr/bin/env python3
# by lorenzo - 06/10/2017
# download all What-If (https://what-if.xkcd.com) images

import requests, os, bs4, sys

print("Where do you want to save the images?")
location = input()
if not os.path.isdir(location):
    print("This is not a valid location!")
    sys.exit()

url = "http://what-if.xkcd.com"
os.makedirs("xkcdWhatIf", exist_ok=True)
os.chdir(location + "/xkcdWhatIf")

while not url.endswith("/1/"):
    print("Downloading page %s..." % url)
    res = requests.get(url)
    res.raise_for_status()
    whatIfSoup = bs4.BeautifulSoup(res.text, "html.parser")
    whatIfElems = whatIfSoup.select(".illustration")

    if whatIfElems == []:
        print("Could not find any comic image.")
    else:
        for i in range(len(whatIfElems)):
            # some of the images have a full web address (from page 1 to 120), but others do not (from 121 onwards)
            if not whatIfElems[i].get("src").startswith("http://") and not whatIfElems[i].get("src").startswith("https://"):
                whatIfUrl = "http://what-if.xkcd.com" + whatIfElems[i].get("src")
            else:
                whatIfUrl = whatIfElems[i].get("src")
            print("Downloading image %s..." % (whatIfUrl))
            res = requests.get(whatIfUrl)
            res.raise_for_status()

            imageFile = open("xkcdWhatIf" + os.path.basename(whatIfUrl), "wb")
            for chunk in res.iter_content(100000):
                imageFile.write(chunk)
            imageFile.close()

    url = "https://what-if.xkcd.com" + whatIfSoup.select(".nav-prev a[href]")[0].get("href")
    continue

# separate case for the first page of What If -
# I duplicated the above code for lack of a better idea
url = "http://what-if.xkcd.com/1/"
print("Downloading page %s..." % url)
res = requests.get(url)
res.raise_for_status()
whatIfSoup = bs4.BeautifulSoup(res.text, "html.parser")
whatIfElems = whatIfSoup.select(".illustration")

if whatIfElems == []:
    print("Could not find any comic image.")
else:
    for i in range(len(whatIfElems)):
        if not whatIfElems[i].get("src").startswith("http://") and not whatIfElems[i].get("src").startswith("https://"):
            whatIfUrl = "http://what-if.xkcd.com" + whatIfElems[i].get("src")
        else:
            whatIfUrl = whatIfElems[i].get("src")
        print("Downloading image %s..." % (whatIfUrl))
        res = requests.get(whatIfUrl)
        res.raise_for_status()

        imageFile = open("xkcdWhatIf" + os.path.basename(whatIfUrl), "wb")
        for chunk in res.iter_content(100000):
            imageFile.write(chunk)
        imageFile.close()

print("Done.")

Comments about the code are welcome.

ABSP, Ch 11, Practice Project #4

My solution to the Practice Project #4 in Chapter 11 of the excellent book “Automate the Boring Stuff with Python” (ABSP)

#! usr/bin/env python3
# by lorenzo - 06/10/2017
# link verification - given the URL of a web page,
# attempts to download every linked page on the web page

import requests, bs4

print("Enter URL:")
myURL = input()

if not myURL.startswith("http"):
    myURL = "http://" + myURL

res = requests.get(myURL)
try:
    res.raise_for_status()
except Exception as exc:
    print("An error occurred: %s" % (exc))

mySoup = bs4.BeautifulSoup(res.text, "html.parser")
myLinks = mySoup.select("a[href]")
for i in range(len(myLinks)):
    res = requests.get(myURL)
    try:
        res.raise_for_status()
    except Exception as exc:
        print("An error occurred: %s" % (exc))

Comments about the code are welcome.

Python practice: copy Firefox bookmarks from bookmarks.html to bookmarks.txt

#! usr/bin/env python3
# by lorenzo - 05/10/2017
# copy Firefox bookmarks from bookmarks.html to bookmarks.txt file
# in the same folder of bookmarks.html

import bs4, os, sys

print("Enter location of bookmarks.html")
location = input()
if not os.path.isdir(location):
    print("Invalid location!")
    sys.exit()
os.chdir(location)

myBookSoup = bs4.BeautifulSoup(open("bookmarks.html"), "html.parser")
textElem = myBookSoup.select('a')

myFile = open("bookmarks.txt", "w")
for i in range(len(textElem)):
    myFile.write("[" + str(i) + "] " + textElem[i].getText() + "\n")
myFile.close()

Comments about the code are welcome.irefox

ABSP, Ch 11, Practice Project #3

My solution to the Practice Project #3 in Chapter 11 of the excellent book “Automate the Boring Stuff with Python” (ABSP)

#! usr/bin/env python3
# by lorenzo - 04/10/2017
# program that plays the games 2048 by repeatedly sliding
# in an up, right, down, and left pattern over and over again.

import bs4
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import random

browser = webdriver.Safari()
browser.get('https://gabrielecirulli.github.io/2048/')
htmlElem = browser.find_element_by_tag_name("html")
print("How many moves do you want to make in the game?")
numOfMoves = int(input())
for i in range(numOfMoves):
    htmlElem.send_keys(Keys.UP)
    htmlElem.send_keys(Keys.RIGHT)
    htmlElem.send_keys(Keys.DOWN)
    htmlElem.send_keys(Keys.LEFT)

Comments about the code are welcome.

Python practice: get new No Starch Press titles using requests and Beautiful Soup modules

#! usr/bin/env python3
# by lorenzo - 04/10/2017
# get new No Starch Press titles using requests and Beautiful Soup modules
# the code displays each result two times - I'm trying to fix this

import requests, os, bs4, sys

res = requests.get("https://www.nostarch.com")
try:
    res.raise_for_status()
except Exception as exc:
    print("There was a problem: %s" % (exc))

noStarchSoup = bs4.BeautifulSoup(res.text, "html.parser")
titleElems = noStarchSoup.select(".field-items a")
print("Do you want to display the titles (1) or save them in a text file (2)? :")
myChoice = input()
if myChoice == "1":

    if len(titleElems) != 0:
        for i in range(len(titleElems)):
            print(titleElems[i].getText())
    else:
        print("Could not find any title!")

else:
    print("Where do you want to store them (enter valid directory):")
    location = input()
    if not os.path.isdir(location):
        print("Enter a valid directory!")
        sys.exit()
    print("Choose a file name:")
    fileName = input()
    myTitles = open(fileName + ".txt", "w")
    for i in range(len(titleElems)):
        myTitles.write(titleElems[i].getText() + "\n")
    myTitles.close()

Comments about the code are welcome.

Python practice: open web pages from command-line using webbrowser and sys.argv modules

#! usr/bin/env python3
# by lorenzo - 03/10/2017
# open web pages from command-line using webbrowser and sys.argv modules
import webbrowser, sys

if len(sys.argv) > 1:
    for i in range(1,len(sys.argv)):
        if sys.argv[i].startswith("www.") or sys.argv[i].startswith("http://"):
            if sys.argv[i].startswith("http://"):
                webbrowser.open(sys.argv[i])
            else:
                webbrowser.open("http://" + sys.argv[i]) # webbrowser.open() needs URLs to start with "http://"

Comments about the code are welcome.