最近段考剛過,又要通知家長學生成績。原本讓學生寫聯絡簿,然後將紙本成績單貼上聯絡簿,家長在聯絡簿與紙本成績單上簽名,導師批閱聯絡簿與紙本成績單就可以知道家長是否知情。但是,學生會仿冒家長簽名或拿家長的印章蓋章,阻止家長得知成績。老師必須要比對筆跡,才能知道學生是否仿冒家長簽名。
由於法規限制,家長只能收到自己孩子的成績,不能知道班上其他學生的成績。老師會從學校方面取得紙本全班成績單或從雲端校務系統下載電子全班成績單。換言之,老師要讓家長知道自己孩子的成績,就得對紙本全班成績單做處理,將之一一切割成紙本個人成績單。或是重新整理電子全班成績單,將之複製貼上到個人成績單。總之,這是一項大工程。
是否能夠開發程式,讓老師只要點兩下就能夠建立全班個人成績單。接下來,點兩下就能夠將個人成績單一一發送到家長電子信箱。
最後完成程式:
以下是使用教學,共有五個步驟:
一.若沒有Gmail,請先建立自己的Gmail
二.下載程式與解壓縮
三.設定寄件者電郵與密碼
四.自雲端校務系統下載report.xlsx
五.對著01建立學生成績PDF_PyScroeTablePdf.exe點兩下
六.對著02批次寄電郵給家長_PythonGmail.exe點兩下
依序如下:
一.若沒有Gmail,請先建立自己的Gmail
二.下載程式與解壓縮
解壓縮時,要注意:不能破壞資料夾結構。
三.設定寄件者電郵與密碼
設定 應用程式密碼
四.自雲端校務系統下載report.xlsx
五.對著01建立學生成績PDF_PyScroeTablePdf.exe點兩下
六.對著02批次寄電郵給家長_PythonGmail.exe點兩下
程式設計部分:
程式目的:讀取report.xlsx 並整理全班學生成績匯出學生個人成績.pdf 到 附件資料夾
檔案名稱:PyScroeTablePdf.py
檔案內容:
import os
import openpyxl as opxl
from win32com.client import DispatchEx
class StudentDataDict():
def __init__(self,FileName):
self.FileName = FileName
def StudentData(self):
#取得學生成績資料
wb = opxl.load_workbook(self.FileName)
wbsh = wb['Worksheet']
StudentDataDict = dict()
ScoreName = wbsh.cell(1,1).value
StudentDataDict[1] = ScoreName
SubjectNameList = []
for i in range(1,wbsh.max_column+1):
SubjectNameList.append(wbsh.cell(2,i).value)
StudentDataDict[2] = SubjectNameList
for j in range(3,wbsh.max_row+1):
StudentDataList = []
for i in range(1,wbsh.max_column+1):
StudentDataList.append(wbsh.cell(j,i).value)
StudentDataDict[j] = StudentDataList
return StudentDataDict
class ScoreTablePdf():
def __init__(self,StudentData):
self.StudentData = StudentData
def RecipientData(self):
#建立收件者資料
RecipientFile = str(os.path.abspath(os.getcwd()))+'\\收件者資料.xlsx'
TempStudentData = self.StudentData
if not os.path.exists(RecipientFile):
print("建立收件者資料.xlsx.......")
#收件者資料.xlsx不存在,則自動建立收件者資料.xlsx
TempExcelFile = opxl.Workbook()
TempExcelFileSheet = TempExcelFile.active
TitleName = ['年班座號','學生姓名','家長姓名','家長電郵','附件名稱','附件副檔名']
for i in range(0,len(TitleName)):
TempExcelFileSheet.cell(row=1,column=i+1).value = TitleName[i]
for j in range(0,len(TempStudentData)):
TempExcelFileSheet.cell(row=j+2,column=1).value = TempStudentData[j+3][0]+str(TempStudentData[j+3][1]).zfill(2)
TempExcelFileSheet.cell(row=j+2,column=2).value = TempStudentData[j+3][3]
TempExcelFileSheet.cell(row=j+2,column=5).value = TempExcelFileSheet.cell(row=j+2,column=1).value
TempExcelFileSheet.cell(row=j+2,column=6).value = 'pdf'
TempExcelFile.save(RecipientFile)
print("建立收件者資料.xlxs OK")
def ScoreTable(self):
TempPath = str(os.path.abspath(os.getcwd()))+'\\Temp\\'
if not os.path.isdir(TempPath):
os.mkdir(TempPath)
AttachPath = str(os.path.abspath(os.getcwd()))+'\\附件\\'
if not os.path.isdir(AttachPath):
os.mkdir(AttachPath)
TempStudentData = self.StudentData
TableSubject = self.StudentData[1]
TempStudentData.pop(1)
TestSubject = self.StudentData[2]
TempStudentData.pop(2)
for i in TempStudentData:
ExcelWorkBook = opxl.Workbook()
ExcelSheet = ExcelWorkBook.worksheets[0]
ExcelSheet['A1'] = TableSubject
for j in range(1,len(TestSubject)):
ExcelSheet.cell(row=j+1,column=1).value = TestSubject[j]
ExcelSheet.cell(row=j+1,column=2).value = TempStudentData[i][j]
ExcelFileName = TempStudentData[i][0]+str(TempStudentData[i][1]).zfill(2)+".xlsx"
ExcelWorkBook.save(TempPath+ExcelFileName)
PdfFileName = TempStudentData[i][0]+str(TempStudentData[i][1]).zfill(2)+".pdf"
TempExcelApplication = DispatchEx("Excel.Application")
TempExcelApplication.Visible = False
TempExcelApplication.DisplayAlerts = 0
TempBooks = TempExcelApplication.Workbooks.Open(TempPath+ExcelFileName,False)
TempBooks.ExportAsFixedFormat(0,AttachPath+PdfFileName)
TempBooks.Close(False)
print("建立學生 "+PdfFileName+" 成績單...OK")
os.remove(TempPath+ExcelFileName)
os.removedirs(TempPath)
print("取得report.xlsx 資料....")
pep01 = StudentDataDict('report.xlsx').StudentData()
print("取得report.xlsx 資料OK")
print("建立全班學生個人成績單.....")
ScoreTablePdf(pep01).ScoreTable()
print("建立全班學生個人成績單OK")
ScoreTablePdf(pep01).RecipientData()
os.system("pause")
os.system("exit")
程式設計部分:
程式目的:將附件內的學生個人成績.pdf 依著收件者資料.xlsx 一一寄給家長
檔案名稱:PythonGmail.py
檔案內容:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
from email.mime.image import MIMEImage
from pathlib import Path
from email.mime.application import MIMEApplication
import os
import openpyxl as opxl
class EmailOpenFiles():
#開啟檔案
def __init__(self,DirectoryName,FileName):
self.DirectoryName = DirectoryName
self.FileName = FileName
def AttachFiles(self):
#取得附件資料夾內所有檔案名稱並回傳List
AttachDirPath=str(os.path.abspath(os.getcwd()))+'\\'+self.DirectoryName+'\\'
AttachFileNameList = os.listdir(AttachDirPath)
return AttachFileNameList
def EmailFileContent(self):
#設定信件內容檔名並取得檔案內容並回傳List
EmailContentFileName = str(os.path.abspath(os.getcwd()))+"\\"+self.FileName
EmailContentFile = open(EmailContentFileName,'r')
EmailContentList = EmailContentFile.readlines()
EmailContentFile.close()
return EmailContentList
def AttachDirPath(self):
#取得附件資料夾路徑
AttachDirPath=str(os.path.abspath(os.getcwd()))+'\\'+self.DirectoryName+'\\'
return AttachDirPath
def AttachExcelOpen(self):
#打開附件為Excel檔案並回傳List
AttachExcelFileName = str(os.path.abspath(os.getcwd()))+"\\"+self.FileName
TempExcelWorkBook = opxl.load_workbook(AttachExcelFileName)
TempMax_Row = TempExcelWorkBook.worksheets[0].max_row
TempMax_Column = TempExcelWorkBook.worksheets[0].max_column
TempReturnList = []
for i in range(1,TempMax_Row+1):
TempList = []
for j in range(1,TempMax_Column+1):
TempList.append(TempExcelWorkBook.worksheets[0].cell(i,j).value)
TempReturnList.append(TempList)
return TempReturnList
class PythonGmail():
def __init__(self,EmailSubject,EmailFrom,EmailTo,EmailContent,EmailAttachments,EmailSender,EmailPass):
self.EmailSubject = EmailSubject
self.EmailFrom = EmailFrom
self.EmailTo = EmailTo
self.EmailContent = EmailContent
self.EmailAttachments = EmailAttachments
self.EmailSender = EmailSender
self.EmailPass = EmailPass
def PythonGmail(self):
#建立MIMEMMultipart物件
content = MIMEMultipart()
#郵件標題
content["subject"] = self.EmailSubject
#寄件者Email
content["from"] = self.EmailFrom
#收件者Email
content["to"] = self.EmailTo
#郵件內容
content.attach(MIMEText(self.EmailContent))
#附件寄送檔案
AttachFileName = self.EmailAttachments
AttachFileload = MIMEApplication(open(AttachFileName,'rb').read())
AttachFileload.add_header('Content-Disposition','attachment',filename=AttachFileName)
content.attach(AttachFileload)
#設定SMTP伺服器
with smtplib.SMTP(host="smtp.gmail.com",port="587") as smtp:
try:
#驗證SMTP伺服器
smtp.ehlo()
#建立加密傳輸
smtp.starttls()
#登入寄件者Gmail
#smtp.login("寄件者信箱","寄件者密碼")
smtp.login(self.EmailSender,self.EmailPass)
#寄送郵件
smtp.send_message(content)
#顯示訊息
return "Success! Send OK!"
except Exception as e:
return "Error message:"+str(e)
#取得附件資料夾內所有檔案名稱
EmailAttachments = EmailOpenFiles('附件','').AttachFiles()
#取得附件資料夾的絕對路徑
EmailAttachDirPath = EmailOpenFiles('附件','').AttachDirPath()
#取得信件標題檔案內容並存成信件標題list
EmailSubjectlist = EmailOpenFiles('','信件標題.txt').EmailFileContent()
#從信件標題list取得信件標題字串
EmailSubject = EmailSubjectlist[0]
#取得信件內容檔案內容並存成信件內容list
EmailContentlist = EmailOpenFiles('','信件內文.txt').EmailFileContent()
#從信件內容list取得信件內容字串
EmailContent = ""
for i in EmailContentlist:
EmailContent = EmailContent + i
#從寄件者電郵與密碼.txt取得List
EmailSenderAddrList = EmailOpenFiles('','寄件者電郵與密碼.txt').EmailFileContent()
#去除List[0]標題
EmailSenderAddrList.pop(0)
#取得寄信者email與密碼
EmailSender,EmailPass = EmailSenderAddrList[0].split(',')
#從收件者資料.xlsx 取得List
EmailToList = EmailOpenFiles('','收件者資料.xlsx').AttachExcelOpen()
#去除List[0]標題
EmailToList.pop(0)
#取得收件者資料並逐一寄信
for i in EmailToList:
A1,A2,A3,A4,A5,A6 = i
EmailAttachFileName=EmailAttachDirPath+A5+'.'+A6
EmailTest=PythonGmail(EmailSubject,EmailSender,A4,EmailContent,EmailAttachFileName,EmailSender,EmailPass).PythonGmail()
print(A1+" "+A2+" Email "+ EmailTest)
os.system("pause")
os.system("exit")
1.Python實現Gmail客製化信件大量發送 — 【基礎篇】
2.Python 初學第十二講—檔案處理
3.Python split 字串分割用法與範例