《Python编程快速上手—让繁琐工作自动化》实践项目答案

9.8.3 消除缺失的编号

编写一个程序, 在一个文件夹中, 找到所有带指定前缀的文件, 诸如spam001.txt, spam002.txt 等,并定位缺失的编号( 例如存在 spam001.txt 和 spam003.txt,但不存在 spam002.txt)。让该程序对所有后面的文件改名,消除缺失的编号。

#! python3

import shutil, os, re

def sortFileName(folder):
    # 查找并提取原始文件名路径列表
    originTextFile = []
    for foldername, subfolders, filenames in os.walk(folder):
        for filename in filenames:
            if re.compile(r'^spam(\d){3}\.txt$').search(filename):
                originTextFile.append(os.path.join(foldername, filename))

    # 建立目标序列文件名路径列表
    totalNum = []
    newTextFile = []
    for i in range(1, len(originTextFile) + 1):
        totalNum.append('%03d' % i)
        newTextFile.append(os.path.join(foldername, 'spam' + totalNum[-1] + '.txt'))

    # 对文件改名以消除缺失的编号
    for index in range(0, len(originTextFile)):
        shutil.move(originTextFile[index], newTextFile[index])

    print('Done.')

sortFileName('.')

12.13.1 乘法表

创建程序 multiplicationTable.py,从命令行接受数字 N,在一个 Excel 电子表格
中创建一个 N×N 的乘法表。例如,如果这样执行程序:
py multiplicationTable.py 6
它应该创建一个图 12-11 所示的电子表格。

《Python编程快速上手—让繁琐工作自动化》实践项目答案_第1张图片
图 12-11 在电子表格中生成的乘法表

行 1 和列 A 应该用做标签,应该使用粗体。

#! python3

import sys, openpyxl
from openpyxl.styles import Font

n = int(sys.argv[1])
wb = openpyxl.Workbook()
sheet = wb.active
font = Font(bold = True)

for rowNum in range(2, n + 2):
    sheet.cell(row = rowNum, column = 1).font = font
    sheet.cell(row = rowNum, column = 1).value = rowNum - 1
for colNum in range(2, n + 2):
    sheet.cell(row = 1, column = colNum).font = font
    sheet.cell(row = 1, column = colNum).value = colNum - 1
for x in range(2, n + 2):
    for y in range(2, n + 2):
        sheet.cell(row = x, column = y).value = (x - 1) * (y - 1)

wb.save('multiplicationTable.xlsx')
print('Done.')

12.13.2 空行插入程序

创建一个程序 blankRowInserter.py,它接受两个整数和一个文件名字符串作为
命令行参数。我们将第一个整数称为 N,第二个整数称为 M。程序应该从第 N 行开
始,在电子表格中插入 M 个空行。例如,如果这样执行程序:
python blankRowInserter.py 3 2 myProduce.xlsx
执行之前和之后的电子表格,应该如图 12-12 所示。

《Python编程快速上手—让繁琐工作自动化》实践项目答案_第2张图片
图 12-12 之前(左边)和之后(右边)在第三行插入两个空行

程序可以这样写:读入电子表格的内容,然后在写入新的电子表格时,利用 for
循环拷贝前面 N 行。对于剩下的行,行号加上 M,写入输出的电子表格。

#! python3

import openpyxl, sys

n = int(sys.argv[1])
m = int(sys.argv[2])
excelFilename = sys.argv[3]

wb = openpyxl.load_workbook(excelFilename)
sheet = wb.active
sheet1 = wb.create_sheet(title = 'Sheet1')
for row in range(1, n):
    for col in range(1, sheet.max_column + 1):
        sheet1.cell(row = row, column = col).value = sheet.cell(row = row, column = col).value
for row in range(n, sheet.max_row + 1):
    for col in range(1, sheet.max_column + 1):
        sheet1.cell(row = row + m, column = col).value = sheet.cell(row = row, column = col).value

wb.save(excelFilename)
print('Done.')

13.6.1 PDF 偏执狂

利用第 9 章的 os.walk()函数编写一个脚本,遍历文件夹中的所有 PDF(包含子文件夹),用命令行提供的口令对这些 PDF 加密。用原来的文件名加上_encrypted.pdf后缀,保存每个加密的 PDF。在删除原来的文件之前,尝试用一个程序读取并解密该文件,确保它被正确的加密。
然后编写一个程序,找到文件夹中所有加密的 PDF 文件(包括它的子文件夹),利用提供的口令,创建 PDF 的解密拷贝。如果口令不对,程序应该打印一条消息,并继续处理下一个 PDF 文件。

#! python3
# 使用方法:python *.py 加密口令

import PyPDF2, os, sys

# 利用os.walk()函数编写一个脚本,遍历文件夹中的所有 PDF(包含子文件夹)
path = 'C:\\folder'  # 文件夹路径
for folderName, subfolders, filenames in os.walk(path):
    for filename in filenames:
        if filename.endswith('.pdf'):

# 用命令行提供的口令对这些 PDF 加密。
            pdfFile = open(folderName + '\\' + filename, 'rb')  # 文件绝对路径
            pdfReader = PyPDF2.PdfFileReader(pdfFile)
            pdfWriter = PyPDF2.PdfFileWriter()
            for pageNum in range(pdfReader.numPages):
                pdfWriter.addPage(pdfReader.getPage(pageNum))
            print('encrypting...')
            pdfWriter.encrypt(sys.argv[1])  # 获取口令并加密

# 用原来的文件名加上_encrypted.pdf后缀,保存每个加密的 PDF。
            resultPdf = open(folderName + '\\' + filename[:-4] + '_encrypted.pdf', 'wb')
            pdfWriter.write(resultPdf)
            resultPdf.close()
            pdfFile.close()

# 在删除原来的文件之前,尝试用一个程序读取并解密该文件,确保它被正确的加密。
            encryptedPdfReader = PyPDF2.PdfFileReader(open(folderName + '\\' + filename[:-4] + '_encrypted.pdf', 'rb'))
            if encryptedPdfReader.isEncrypted and encryptedPdfReader.decrypt(sys.argv[1]):
                print(filename + ' is encrypted.')
                print('deleting... ' + filename)
                os.unlink(folderName + '\\' + filename)
            else:
                print(filename + ' is not encrypted or wrong password.')
        else:
            continue

print('Done.')
#! python3
# 使用方法:python *.py 解密口令

import PyPDF2, os, sys

# 然后编写一个程序,找到文件夹中所有加密的 PDF 文件(包括它的子文件夹)
path = 'C:\\folder'  # 文件夹路径
for folderName, subfolders, filenames in os.walk(path):
    for filename in filenames:
        if filename.endswith('.pdf'):

# 利用提供的口令,创建 PDF 的解密拷贝。
            pdfFile = open(folderName + '\\' + filename, 'rb')  # 文件绝对路径
            pdfReader = PyPDF2.PdfFileReader(pdfFile)
            if pdfReader.isEncrypted:
                if pdfReader.decrypt(sys.argv[1]):
                    print(filename + ' is decrypted.')
                    pdfWriter = PyPDF2.PdfFileWriter()
                    for pageNum in range(pdfReader.numPages):
                        pdfWriter.addPage(pdfReader.getPage(pageNum))
                    resultPdf = open(folderName + '\\' + filename[:-4] + '_decrypted.pdf', 'wb')
                    pdfWriter.write(resultPdf)
                    resultPdf.close()
                    pdfFile.close()

# 如果口令不对,程序应该打印一条消息,并继续处理下一个 PDF 文件。
                else:
                    print('wrong password!')
            else:
                continue

print('Done.')

13.6.3 暴力 PDF 口令破解程序

假定有一个加密的 PDF 文件,你忘记了口令,但记得它是一个英语单词。尝试猜测遗忘的口令是很无聊的任务。作为替代,你可以写一个程序,尝试用所可能的英语单词来解密这个 PDF 文件,直到找到有效的口令。这称为暴力口令攻击。从http://nostarch.com/automatestuff/下载文本文件 dictionary.txt。这个字典文件包含 44000多个英语单词,每个单词占一行。
利用第 8 章学过的文件读取技巧来读取这个文件,创建一个单词字符串的列表。然后循环遍历这个列表中的每个单词,将它传递给 decrypt()方法,如果这个方法返回整数 0,口令就是错的,程序应该继续尝试下一个口令。如果 decrypt()返回 1,程序就应该终止循环,打印出破解的口令。你应该尝试每个单词的大小写形式(在我的笔记本上,遍历来自字典文件的所有 88000 个大小写单词,只要几分钟时间。这就是不应该使用简单英语单词作为口令的原因)。

#! python3

import PyPDF2

def Decrypt(word):
    if pdfReader.decrypt(word):
        print('Password is %s' % word)
        return -1
    elif pdfReader.decrypt(word.lower()):
        print('Password is %s' % word.lower())
        return -1
    else:
        return 0

dictFilePath = 'C:\\dictFilename.txt'  # 字典文件绝对路径
dictFile = open(dictFilePath)
wordList = dictFile.read().split('\n')
dictFile.close()

pdfFilePath = 'C:\\pdfFilename.pdf'  # PDF文件绝对路径
pdfReader = PyPDF2.PdfFileReader(open(pdfFilePath, 'rb'))
if pdfReader.isEncrypted:
    print('Decrypting...')
    for word in wordList:
        if Decrypt(word):
            break
        else:
            continue
else:
    print('This PDF file is not encrypted.')

14.8.1 Excel 到 CSV 的转换程序

Excel 可以将电子表格保存为 CSV 文件,只要点几下鼠标,但如果有几百个 Excel文件要转换为 CSV,就需要点击几小时。利用第 12 章的 openpyxl 模块, 编程读取当前工作目录中的所有 Excel 文件,并输出为 CSV 文件。
一个 Excel 文件可能包含多个工作表,必须为每个表创建一个 CSV 文件。 CSV文件的文件名应该是_<表标题>.csv,其中是没有扩展名的 Excel 文件名(例如'spam_data',而不是'spam_data.xlsx'), <表标题>是Worksheet 对象的 title 变量中的字符串。
从 http://nostarch.com/automatestuff/下载 ZIP 文件 excelSpreadsheets.zip,将这些电子表格解压缩到程序所在的目录中。可以使用这些文件来测试程序。

#! python3

import openpyxl, csv, os

for excelFile in os.listdir('.'):
    # Skip non-xlsx files, load the workbook object.
    if excelFile.endswith('.xlsx'):
        wb = openpyxl.load_workbook(excelFile)
        for sheetName in wb.sheetnames:
            # Loop through every sheet in the workbook.
            sheet = wb[sheetName]

            # Create the CSV filename from the Excel filename and sheet title.
            csvFile = open(os.path.join(excelFile[:-5] + '_' + sheetName + '.csv'), 'w', newline = '')
            # Create the csv.writer object for this CSV file.
            csvWriter = csv.writer(csvFile)

            # Loop through every row in the sheet.
            for rowNum in range(1, sheet.max_row + 1):
                rowData = []  # append each cell to this list
                # Loop through each cell in the row.
                for colNum in range(1, sheet.max_column + 1):
                    # Append each cell's data to rowData.
                    rowData.append(sheet.cell(row = rowNum, column = colNum).value)
                # Write the rowData list to the CSV file.
                csvWriter.writerow(rowData)
                
            csvFile.close()
print('Done.')

15.12.1 美化的秒表

扩展本章的秒表项目,让它利用 rjust()和 ljust()字符串方法来“美化”的输出。(这些方法在第 6 章中介绍过)。输出不是像这样:

Lap #1: 3.56 (3.56)
Lap #2: 8.63 (5.07)
Lap #3: 17.68 (9.05)
Lap #4: 19.11 (1.43)

…而是像这样:

Lap # 1: 3.56 ( 3.56)
Lap # 2: 8.63 ( 5.07)
Lap # 3: 17.68 ( 9.05)
Lap # 4: 19.11 ( 1.43)

请注意,对于 lapNum、 lapTime 和 totalTime 等整型和浮点型变量,你需要字符串版本,以便对它们调用字符串方法。接下来,利用第 6 章中介绍的 pyperclip 模块,将文本输出复制到剪贴板,以便用户可以将输出快速粘贴到一个文本文件或电子邮件中。

#! python3

import time, pyperclip

# Display the program's instructions.
print('Press ENTER to begin. Afterwards, press ENTER to "click" the stopwatch. Press Ctrl-C to quit.')
input() # press Enter to begin
print('Started.')
startTime = time.time() # get the first lap's start time
lastTime = startTime
lapNum = 1
copyList = []

# Start tracking the lap times.
try:
    while True:
        input()
        lapTime = round(time.time() - lastTime, 2)
        totalTime = round(time.time() - startTime, 2)
        result = 'Lap #%s: %s (%s)' % (str(lapNum).rjust(2), str(totalTime).rjust(6), str(lapTime).rjust(5))
        print(result, end='')
        copyList.append(result)
        lapNum += 1
        lastTime = time.time() # reset the last lap time
except KeyboardInterrupt:
    # Handle the Ctrl-C exception to keep its error message from displaying.
    print('\nDone.')
    pyperclip.copy('\n'.join(copyList))

环境:python3

你可能感兴趣的:(《Python编程快速上手—让繁琐工作自动化》实践项目答案)