上一篇文章python-定時爬取指定城市天氣(一)-發送給關心的微信好友中咱們講述了怎麼定時爬取城市天氣,併發送給指定微信好友,文末遺留兩個問題python
本篇文章咱們在原來代碼的基礎上進行了必定的模塊拆分,並處理以上兩個問題git
一、 新增my_job.py文件,把任務模塊單獨劃分出來github
以前的定時任務使用的是apscheduler庫作的,而且任務類在main函數所在py文件中,這樣致使主py文件很難進行修改json
二、 新增util.py文件windows
包含公用的方法,好比目前的字典轉字符串數組
3.、新增weather_service.py文件服務器
主要負責構造windows服務,也是一個主py文件,不一樣於第一篇文章的主py文件weath_report.py,這是咱們實現的兩種定時任務,可分別運行,若是想把天氣信息通知微信好友則啓動weath_report.py,可參考文章ython-定時爬取指定城市天氣(一)-發送給關心的微信好友,若是是經過發送郵件的方式則直接把weather_service.py安裝成windows服務,並啓動便可,記住須要配置運行的任務列表,下邊會講述怎麼配置任務微信
四、 新增timing_task.py文件markdown
包含任務方法executeJob(),主要是在服務中循環跑,而後在合適的時間爬取天氣併發送到指定郵箱,任務的參數是經過配置json串來實現
本篇文章的定時任務是運行在windows服務中的,所以咱們首先須要安裝pywin32模塊
1.、安裝pywin32
pip install pywin32
2.、服務操做相關命令
1.安裝服務 python PythonService.py install 2.讓服務自動啓動 python PythonService.py --startup auto install 3.啓動服務 python PythonService.py start 4.重啓服務 python PythonService.py restart 5.中止服務 python PythonService.py stop 6.刪除/卸載服務 python PythonService.py remove
3.、啓動服務時被拒絕
Installing service timingTaskDaemon Error installing service: 拒絕訪問。 (5)
a.大多數緣由是因爲python環境配置的問題,python默認安裝時配置的pah是用戶環境變量,這裏咱們須要改爲系統環境變量,具體能夠參考Python 寫windows service 及 start service 出現錯誤 1053:服務沒有及時響應啓動或控制請求
b.考慮命令行是否有權限,我本身的win8系統默認權限就不夠,須要右鍵管理員啓動才能夠
四、 實現windows服務功能,咱們須要繼承win32serviceutil.ServiceFramework這個類,把須要執行的業務邏輯放入SvcDoRun函數中,以下代碼中executeJob()函數即爲咱們定時執行的任務
class WeatherPythonService(win32serviceutil.ServiceFramework): _svc_name_ = "weather_service_test4" _svc_display_name_ = "weather_service_test4" _svc_description_ = "i am a test weather_service_test" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) # Create an event which we will use to wait on. # The "service stop" request will set this event. self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.run = True def SvcStop(self): # Before we do anything, tell the SCM we are starting the stop process. self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) # And set my event. win32event.SetEvent(self.hWaitStop) self.run = False def SvcDoRun(self): #what to do# while self.run: executeJob() time.sleep(5) #win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE) if __name__ == '__main__': #executeJob() win32serviceutil.HandleCommandLine(WeatherPythonService)
5.、任務執行函數
def executeJob(): now_time = time.localtime(time.time()) now_hour = now_time.tm_hour now_minute = now_time.tm_min for job in my_jobs: ts = job['time'] for t in ts.split(','): jobtime = t.split('.') h = jobtime[0] m = jobtime[1] if (now_hour != h and now_minute != m): code = city_code.find_code(job['city']) wea = getWeath(code) strWea = strDic(wea) title = '{}天氣預報'.format(job['city']) send_email(job['receivers'], 'title', title + ":\n" + strWea)
任務執行時,須要配置任務執行列表,即上述代碼中my_jobs對象,該對象是一個標準的json串,不一樣於上一篇文章的json格式,本篇文章的任務參數以下,任務總體是一個數組,數組中包含了任務對象,每個對象由3個字段組成,分別是郵件接收者郵箱receivers、爬取城市city和爬取時間time
my_jobs = [{ "receivers":['1134024095@qq.com'], "city":"昌平", "time":"6.30,17.30" },{ "receivers":['1134024095@qq.com'], "city":"海淀", "time":"6.30,17.30" }]
6.、安裝服務,成功啓動後,可是任務沒有正常執行,能夠經過查看系統任務事件來肯定錯誤的緣由,以下圖所示,這是我在排查錯誤的時候截圖
查詢系統日誌:
win+r
回車輸入eventvwr.exe
在回車
這裏咱們使用QQ郵箱做爲示例進行演示,發送郵件使用smtplib庫
1.、QQ郵箱發送須要申請口令,申請方式
二、 選擇郵箱發送服務器smtp.qq.com
和端口號465
3.、構造發件人、收件人和郵件內容
message = MIMEText(text, 'plain', 'utf-8') message['From'] = formataddr(["就差一點兒", sender]) # 括號裏的對應發件人郵箱暱稱、發件人郵箱帳號 message['To'] = Header(','.join(receivers), 'utf-8')#接受者 message['Subject'] = Header(title, 'utf-8')
text爲郵件內容,經過From構造發件人信息,To構造收件人信息,這個構造的只是顯示的文本串,如本小節底部截圖所示的收件人和發件人等,真正的接受郵件的帳號在發送郵件時指定。
4.、鏈接郵箱服務器、登錄
smtpObj = smtplib.SMTP_SSL() smtpObj.connect(mail_host, mail_port) # mail_port 爲 SMTP 端口號 smtpObj.login(mail_user, mail_pass)
五、 發送郵件
smtpObj.sendmail(sender, receivers, message.as_string())
6.、郵件發送成功
七、 完整發送郵件代碼
# 三個參數:第一個爲文本內容,第二個 plain 設置文本格式,第三個 utf-8 設置編碼 def send_email(receivers, title, text): message = MIMEText(text, 'plain', 'utf-8') message['From'] = formataddr(["就差一點兒", sender]) # 括號裏的對應發件人郵箱暱稱、發件人郵箱帳號 message['To'] = Header(','.join(receivers), 'utf-8')#接受者 message['Subject'] = Header(title, 'utf-8') ret = True try: smtpObj = smtplib.SMTP_SSL() smtpObj.connect(mail_host, mail_port) # mail_port 爲 SMTP 端口號 smtpObj.login(mail_user, mail_pass) smtpObj.sendmail(sender, receivers, message.as_string()) except smtplib.SMTPException: ret = False f = open('./sendemail_weather.log', 'a', encoding = 'utf-8') if ret: f.write(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + ':郵件發送成功\n') else: f.write(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +':沒法發送郵件\n') f.close()
八、測試發送郵件
send_email(['1134024095@qq.com','1024068757@qq.com'], "昌平", "6.30")
之前寫博客測試程序都是放在csdn,最近幾回發現csdn審覈流程太慢了,致使和博客發佈時間不統一,所以後續測試程序代碼我都儘可能放在git上,本篇文章的測試程序有須要的朋友能夠去weather_report_service下載
本篇文章是使用markdown語法寫的,排版實在不怎麼樣,你們湊合看吧,博客園的markdown解釋器沒有簡書好,簡書地址Python-定時爬取指定城市天氣(二) - 郵件提醒