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.

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.

ABSP, Ch 10, Practice Project

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

import random
guess = ''
while guess not in ('heads', 'tails'):
    print('Guess the coin toss! Enter heads or tails:')
    guess = input()
toss = random.randint(0, 1) # 0 is tails, 1 is heads
if toss == 0:
    toss = 'tails'
else:
    toss = 'heads'
if toss == guess:
    print('You got it!')
else:
    print('Nope! Guess again!')
    guess = input()
    if toss == guess:
       print('You got it!')
    else:
        print('Nope. You are really bad at this game.')

Comments about the code are welcome.

ABSP, Ch 9, Practice Project #3

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

#! usr/bin/env python3
# by lorenzo - 21/09/2017
# filling in the gaps - program that finds all files with a given prefix, 
#                       such as spam001.txt, spam002.txt, and so on,
#                       in a single folder, locates any gaps 
#                       in the numbering (such as if there is a spam001.txt and #                       spam003.txt but no spam002.txt) and subsequently
#                       renames all the later files to close this gap.                       

import os, sys, shutil

print('Enter location of folder to search in:')
myFolder = os.path.abspath(input())
if not os.path.exists(myFolder):
    print("This path doesn't exist!")
    sys.exit()

print('Enter name part of prefix of the files:')
fileName = input()

print('From which number should the numbering of the files start?')
nStart = int(input())

print('At which number should the numbering of the files end?')
nStop = int(input())

print('How many digits in numbering? (ex. 010 has three digits)')
nDig = int(input())

listOfFiles = []
for i in range(nStart, nStop + 1):    
    nZero = nDig - len(str(i))    
    currentFile = fileName + nZero * '0' + str(i)
    listOfFiles.append(currentFile)

os.chdir(myFolder)
myList = []
for thisFile in os.listdir():
    if thisFile in listOfFiles:
        myList.append(thisFile)
myList.sort()    
for i in range(len(myList)):
        if listOfFiles[i] != myList[i]:
            shutil.move(myList[i], listOfFiles[i])
#! usr/bin/env python3
# by lorenzo - 21/09/2017
# filling in the gaps (alternative version)
# program that finds all files with a given prefix, such as spam001.txt, 
# spam002.txt, and so on, in a single folder, locates any gaps 
# in the numbering (such as if there is a spam001.txt and spam003.txt 
# but no spam002.txt) and subsequently creates appropriately named files
# to close this gap.
                                   
import os, sys

print('Enter location of folder to search in:')
myFolder = os.path.abspath(input())
if not os.path.exists(myFolder):
    print("This path doesn't exist!")
    sys.exit()

print('Enter name part of prefix of the files:')
fileName = input()

print('From which number should the numbering of the files start?')
nStart = int(input())

print('At which number should the numbering of the files end?')
nStop = int(input())

print('How many digits in numbering? (ex. 010 has three digits)')
nDig = int(input())

listOfFiles = []
for i in range(nStart, nStop + 1):    
    nZero = nDig - len(str(i))    
    currentFile = fileName + nZero * '0' + str(i)
    listOfFiles.append(currentFile)
os.chdir(myFolder)
for myFile in listOfFiles:
    if myFile not in os.listdir():
        thisFile = open(myFile, 'w')
        thisFile.close()
    else:
        continue
#! usr/bin/env python3
# by lorenzo - 21/09/2017
# added challenge - program that can insert gaps into numbered files
#                   so that a new file can be added.

import os, sys, shutil

def Add(myString, numToAdd):
    numZeros = 0
    aNumber = []
    aString = []
    for ch in myString:
        if ch.isdecimal():
            aNumber.append(ch)
        else:
            aString.append(ch)
    
    for i in range(len(aNumber)):
        if aNumber[i] == 0:
            numZeros += 1
            del aNumber[i]
        else:
            break
        
    myNumber = ''.join(aNumber)
    thisNumber = int(myNumber) + numToAdd
    strNumb = str(thisNumber)
    finalList = aString[:]
    zeros = numZeros - (len(str(thisNumber))-len(myNumber))
                       
    for num in range(zeros):
                        finalList.append('0')

    for j in range(len(strNumb)):
                        finalList.append(strNumb[i])

    returnStr = ''.join(finalList)
    return returnStr
                           
print('Enter location of folder to search in:')
myFolder = os.path.abspath(input())
if not os.path.exists(myFolder):
    print("This path doesn't exist!")
    sys.exit()

print('Enter prefix of the files:')
fileName = input()

print('Enter complete name of the file from which you want to add spaces:')
fileStart = input()

print('How many spaces do you want between this file and the next one?')
nSpace = int(input())

os.chdir(myFolder)
myList = []
for thisFile in os.listdir():
    if thisFile.startswith(fileName) and thisFile[-1].isdigit():
        myList.append(thisFile)
myList.sort()
myIndex = myList.index(fileStart)
thisList = myList[myIndex+1:]

for myFile in thisList:
    os.rename(myFile, Add(myFile,nSpace))

Comments about the code are welcome.

ABSP Ch 9, Practice Project #1

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

#! usr/bin/env python3
# by lorenzo - 21/09/2017
# selective copy - program that walks through a folder tree,
#                  searches for files with a certain file extensons
#                  and then copies them into a new folder

import os, sys, shutil

print("Enter file extension you want to search for (ex:.pdf):")
extension = input()
print("Enter location of the folder you want to search in:")
location = input()
print("Enter location of the folder where you want to place the files found:")
copyLoc = input()

if not os.path.exists(location):
    print("Location to search in does not exist!")
    sys.exit()

if not os.path.exists(copyLoc):
    print("Location to copy files does not exist!")
    sys.exit()

for folderName, subfolders, filenames in os.walk(location):
    for filename in filenames:
        if filename.endswith(extension):
            shutil.copy(os.path.join(folderName,filename),copyLoc)

Comments about the code are welcome.