PyQt5實踐課程1——PyQt5之天氣預報

今天我們做一個基于Python3 + PyQt5的一個天氣預報,先來看一下效果圖:


整體界面比較簡陋,但是這里我們主要把功能實現(xiàn)就行了。

工具準備:

  • Python3.x
    運行本例代碼還需要裝幾個Python3的模塊:
$ pip install pyqt5
$ pip install bs4
$ pip install lxml 

正文開始

1.天氣信息爬取

在制作天氣預報信息顯示時,我們首先需要獲取預報信息,這里我們準備從中國天氣網(wǎng)爬取我們所需要的天氣信息。具體思路是:

  1. 獲取所在城市碼,構造爬取鏈接
  2. 使用urllib獲取網(wǎng)站html源碼
  3. 分析html源碼,獲取我們所需的天氣信息

大概就上面三條,分析html源碼我們使用bs4包所提供的BeautifulSoup進行,關于BeautifulSoup的使用參見[腳本之家——Python中使用Beautiful Soup庫的超詳細教程]。

  1. 獲取城市碼
    打開中國天氣網(wǎng),輸入你所在的城市名,打開后點擊今天,注意瀏覽器上的鏈接地址。我輸入的城市是西安,所以地址是:
    http://www.weather.com.cn/weather1d/101110101.shtml
    其中101110101就是西安的城市碼,其他城市以此類推。
  2. 使用urllib獲取網(wǎng)站html源碼
from urllib import request

city_code = "101110101"
req = request("http://www.weather.com.cn/weather1d/" + city_code + ".shtml")
# 將網(wǎng)頁數(shù)據(jù)解碼為utf-8字符集
html = req.read().decode('utf-8')
# 為了節(jié)省調(diào)試時間,我們這里直接將網(wǎng)頁源碼保存至本地文件tmp.html中
f = open("tmp.html", "w", encoding="utf-8")
f.write(html)
f.close()
  1. 分析html源碼,獲取我們所需的天氣信息
from bs4 import BeautifulSoup
# 我們使用lxml解析器
soup = BeautifulSoup(open("tmp.html", "r", encoding="utf-8"), "lxml")
# 使用字典保存我們所獲取的兩組數(shù)據(jù)
weather = {}
weather['day_wea'] = soup.select('div.t > ul.clearfix > li > p.wea')[0].text
weather['night_wea'] = soup.select('div.t > ul.clearfix > li > p.wea')[1].text
weather['day_tem'] = soup.select('div.t > ul.clearfix > li > p.tem > span')[0].text
weather['night_tem'] = soup.select('div.t > ul.clearfix > li > p.tem > span')[1].text
print(weather)

>>> {'day_wea': '陣雨', 'night_wea': '陣雨', 'day_tem': '30', 'night_tem': '22'}

我們所需要的天氣信息和溫度信息已經(jīng)獲取到了,原始資料準備妥當,開始構建我們的圖形顯示界面

2. 構造圖形界面

我們獲取的天氣信息有兩組,分別是當日白天天氣信息、當日夜間天氣信息,我們準備用3個QHBoxLayout、1個QVBoxLayout、6個QLabel控件完成信息的顯示。
布局如下:

白天 夜間
天氣圖標 天氣圖標
預報+溫度 預報+溫度

窗口實現(xiàn)代碼如下:

class MainWindow(QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.img_label = QLabel()
        self.wea_label = QLabel()

        pal = QPalette()
        pal.setColor(QPalette.WindowText, Qt.white)
        font = QFont("微軟雅黑", 10)
        
        # 標題Layout
        title_layout = QHBoxLayout()
        self.day_title = QLabel('白天')
        self.night_title = QLabel('夜間')
        title_layout.addWidget(self.day_title)
        title_layout.addWidget(self.night_title)
         # 設置字體顏色為白色
        self.day_title.setPalette(pal)
        self.night_title.setPalette(pal)
        # 設置對齊方式為居中對齊
        self.day_title.setAlignment(Qt.AlignHCenter)
        self.night_title.setAlignment(Qt.AlignHCenter) 
        # 設置顯示字體
        self.day_title.setFont(font)
        self.night_title.setFont(font)
       

        # 天氣圖標Layout
        img_layout = QHBoxLayout()
        self.day_img_label = QLabel()
        self.night_img_label = QLabel()
        img_layout.addWidget(self.day_img_label)
        img_layout.addWidget(self.night_img_label)

        # 天氣信息Layout
        wea_layout = QHBoxLayout()
        self.day_wea_label = QLabel()
        self.night_wea_label = QLabel()
        wea_layout.addWidget(self.day_wea_label)
        wea_layout.addWidget(self.night_wea_label)
        self.day_wea_label.setPalette(pal)
        self.night_wea_label.setPalette(pal)
        # 文本居中對齊
        self.day_wea_label.setAlignment(Qt.AlignHCenter)
        self.night_wea_label.setAlignment(Qt.AlignHCenter)
        self.day_wea_label.setFont(font)
        self.night_wea_label.setFont(font)
       
        layout = QVBoxLayout(self)
        layout.addLayout(title_layout)
        layout.addLayout(img_layout)
        layout.addLayout(wea_layout)

        self.setLayout(layout)
        # 設置窗口屬性,去除系統(tǒng)標題欄、隱藏狀態(tài)欄、置頂顯示
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool | Qt.WindowStaysOnTopHint)
        # 設置窗口背景透明
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setAutoFillBackground(False)
        # 重新調(diào)整窗口大小
        self.resize(300, 200)

        # 用于移動窗口
        self.__x_offset = 0
        self.__y_offset = 0

    def mousePressEvent(self, event):
        """ 父類方法重寫,用于實現(xiàn)窗口隨鼠標拖動 """
        self.__x_offset = event.globalX() - self.pos().x()
        self.__y_offset = event.globalY() - self.pos().y()

    def mouseMoveEvent(self, event):
        """ 父類方法重寫,用于實現(xiàn)窗口隨鼠標拖動 """
        self.move(event.globalX() - self.__x_offset, event.globalY() - self.__y_offset)

    def update_weather(self, wea):
        """ 更新天氣顯示 """
        pixmap = QPixmap(self.__get_images__('day_' + wea['day_wea']))
        self.day_img_label.setPixmap(pixmap)
        self.day_wea_label.setText('%s %s℃' % (wea['day_wea'], wea['day_tem']))

        pixmap = QPixmap(self.__get_images__('night_' + wea['night_wea']))
        self.night_img_label.setPixmap(pixmap)
        self.night_img_label.resize(pixmap.size())
        self.night_wea_label.setText('%s %s℃' % (wea['night_wea'], wea['night_tem']))

    def __get_images__(self, wea_str):
        imags = {"day_陣雨":':/images/day_shower.png', "night_陣雨":":/images/night_shower.png",
            "day_多云":':/images/day_cloudy.png', "night_多云":":/images/night_cloudy.png",
            "day_晴":':/images/day_sunny.png', "night_晴":":/images/night_sunny.png",
            }
        return imags[wea_str]

我們在上面添加了兩個新的方法update_weather(wea),我們第一步爬取到的天氣信息輸入給這個方法,即可對界面顯示元素進行更新。還有一個是get_images(wea_str),當獲取到具體的當日天氣后傳參給這個函數(shù)將返回當前天氣信息的圖標名稱。PS:我太懶了,所以我只做了陣雨、多云、晴三種天氣信息,剩下的按照需求自己完成就行。

  • 為了使我們的天氣信息能夠自動更新,我們將每隔1小時對中國天氣網(wǎng)進行一次天氣信息解析,為此我們寫了個線程用于完成這個功能。

    # 城市碼
    city_codes = {'西安':'101110101'}

    def __init__(self, win):
        super(WeatherThread, self).__init__()
        self.__win = win

    def run(self):
        while True:
            url = self.get_url('西安')
            html = self.get_html(url)
            wea = self.get_data(html)
            self.__win.update_weather(wea)
            print(wea)
            # 等待1小時
            time.sleep(3600)

    def get_url(self, city):
        url = 'http://www.weather.com.cn/weather1d/' + self.city_codes[city] + '.shtml'
        return url

    def get_html(self, url):
        req = request.urlopen(url)
        html = req.read().decode('utf-8')
        return html

    def get_data(self, html):
        weather = {}
        soup = BeautifulSoup(html, 'lxml')
        weather['day_wea'] = soup.select('div.t > ul.clearfix > li > p.wea')[0].text
        weather['night_wea'] = soup.select('div.t > ul.clearfix > li > p.wea')[1].text
        weather['day_tem'] = soup.select('div.t > ul.clearfix > li > p.tem > span')[0].text
        weather['night_tem'] = soup.select('div.t > ul.clearfix > li > p.tem > span')[1].text
        return weather

城市碼我只弄了一種就是西安的,剩下的自己按照我之前介紹的方法獲取就行了。

  • 圖片我是在懶人圖庫上找的,圖片我使用Qt資源進行存儲,貼上qrc代碼:
<RCC version="1.0">
    <qresource prefix="images">
        <file alias="day_shower.png">./images/shower2.png</file>
        <file alias="night_shower.png">./images/shower2_night.png</file>
        <file alias="day_cloudy.png">./images/cloudy3.png</file>
        <file alias="night_cloudy.png">./images/cloudy3_night.png</file>
        <file alias="night_sunny.png">./images/sunny_night.png</file>
        <file alias="day_sunny.png">./images/sunny.png</file>
    </qresource>
</RCC>

使用pyrcc5進行資源的處理:

$ pyrcc5 images.qrc -o images.py

最后添上我們的程序入口:

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    wea_thread = WeatherThread(win)
    wea_thread.start()
    sys.exit(app.exec())

哦對了,我列一下這個程序所用到的模塊:

import sys, time
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QHBoxLayout
from PyQt5.QtGui import QFont, QPixmap, QColor, QPalette
from PyQt5.QtCore import Qt, QThread
from bs4 import BeautifulSoup
from urllib import request
from images import *

本例所有代碼已上傳至github,有興趣的朋友可以pull下來。
https://github.com/xtinyd/weather.git

結束語

在PyQt5上我也只是個菜鳥,出這個系列教程的目的呢,還是想讓自己學到的東西能夠用上,不至于學起來那么盲目,另外也希望可以幫助想學習PyQt5的你。附上我的座右銘:
沒有什么是學習學不來的。
——skyloveraining

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容