Python-定時爬取指定城市天氣(二)-郵件提醒

1、概述

上一篇文章python-定時爬取指定城市天氣(一)-發送給關心的微信好友中咱們講述了怎麼定時爬取城市天氣,併發送給指定微信好友,文末遺留兩個問題python

  • 定時任務作成windows服務,這樣更優雅,隨開機啓動
  • 發送消息給微信好友換成發送郵件給指定郵箱

本篇文章咱們在原來代碼的基礎上進行了必定的模塊拆分,並處理以上兩個問題git

2、模塊從新劃分

一、 新增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串來實現

3、優化定時任務

本篇文章的定時任務是運行在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 在回車

查詢系統日誌

4、發送郵件

這裏咱們使用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")

5、源代碼

之前寫博客測試程序都是放在csdn,最近幾回發現csdn審覈流程太慢了,致使和博客發佈時間不統一,所以後續測試程序代碼我都儘可能放在git上,本篇文章的測試程序有須要的朋友能夠去weather_report_service下載

本篇文章是使用markdown語法寫的,排版實在不怎麼樣,你們湊合看吧,博客園的markdown解釋器沒有簡書好,簡書地址Python-定時爬取指定城市天氣(二) - 郵件提醒




轉載聲明:本站文章無特別說明,皆爲原創,版權全部,轉載請註明:朝十晚八 or Twowords

相關文章
相關標籤/搜索