PyQt5實(shí)踐課程1——PyQt5之天氣預(yù)報(bào)

今天我們做一個(gè)基于Python3 + PyQt5的一個(gè)天氣預(yù)報(bào),先來看一下效果圖:


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

工具準(zhǔn)備:

  • Python3.x
    運(yùn)行本例代碼還需要裝幾個(gè)Python3的模塊:
$ pip install pyqt5
$ pip install bs4
$ pip install lxml 

正文開始

1.天氣信息爬取

在制作天氣預(yù)報(bào)信息顯示時(shí)甜紫,我們首先需要獲取預(yù)報(bào)信息囚霸,這里我們準(zhǔn)備從中國天氣網(wǎng)爬取我們所需要的天氣信息激才。具體思路是:

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

大概就上面三條傲绣,分析html源碼我們使用bs4包所提供的BeautifulSoup進(jìn)行揣云,關(guān)于BeautifulSoup的使用參見[腳本之家——Python中使用Beautiful Soup庫的超詳細(xì)教程]邓夕。

  1. 獲取城市碼
    打開中國天氣網(wǎng),輸入你所在的城市名焚刚,打開后點(diǎn)擊今天,注意瀏覽器上的鏈接地址抢肛。我輸入的城市是西安碳柱,所以地址是:
    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)試時(shí)間的圆,我們這里直接將網(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)獲取到了,原始資料準(zhǔn)備妥當(dāng)梅掠,開始構(gòu)建我們的圖形顯示界面

2. 構(gòu)造圖形界面

我們獲取的天氣信息有兩組店归,分別是當(dāng)日白天天氣信息、當(dāng)日夜間天氣信息挠蛉,我們準(zhǔn)備用3個(gè)QHBoxLayout肄满、1個(gè)QVBoxLayout、6個(gè)QLabel控件完成信息的顯示掰担。
布局如下:

白天 夜間
天氣圖標(biāo) 天氣圖標(biāo)
預(yù)報(bào)+溫度 預(yù)報(bào)+溫度

窗口實(shí)現(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)
        
        # 標(biāo)題Layout
        title_layout = QHBoxLayout()
        self.day_title = QLabel('白天')
        self.night_title = QLabel('夜間')
        title_layout.addWidget(self.day_title)
        title_layout.addWidget(self.night_title)
         # 設(shè)置字體顏色為白色
        self.day_title.setPalette(pal)
        self.night_title.setPalette(pal)
        # 設(shè)置對(duì)齊方式為居中對(duì)齊
        self.day_title.setAlignment(Qt.AlignHCenter)
        self.night_title.setAlignment(Qt.AlignHCenter) 
        # 設(shè)置顯示字體
        self.day_title.setFont(font)
        self.night_title.setFont(font)
       

        # 天氣圖標(biāo)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)
        # 文本居中對(duì)齊
        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)
        # 設(shè)置窗口屬性带饱,去除系統(tǒng)標(biāo)題欄勺疼、隱藏狀態(tài)欄、置頂顯示
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool | Qt.WindowStaysOnTopHint)
        # 設(shè)置窗口背景透明
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setAutoFillBackground(False)
        # 重新調(diào)整窗口大小
        self.resize(300, 200)

        # 用于移動(dòng)窗口
        self.__x_offset = 0
        self.__y_offset = 0

    def mousePressEvent(self, event):
        """ 父類方法重寫酪耕,用于實(shí)現(xiàn)窗口隨鼠標(biāo)拖動(dòng) """
        self.__x_offset = event.globalX() - self.pos().x()
        self.__y_offset = event.globalY() - self.pos().y()

    def mouseMoveEvent(self, event):
        """ 父類方法重寫轨淌,用于實(shí)現(xiàn)窗口隨鼠標(biāo)拖動(dòng) """
        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]

我們?cè)谏厦嫣砑恿藘蓚€(gè)新的方法update_weather(wea)递鹉,我們第一步爬取到的天氣信息輸入給這個(gè)方法,即可對(duì)界面顯示元素進(jìn)行更新却盘。還有一個(gè)是get_images(wea_str),當(dāng)獲取到具體的當(dāng)日天氣后傳參給這個(gè)函數(shù)將返回當(dāng)前天氣信息的圖標(biāo)名稱谷炸。PS:我太懶了禀挫,所以我只做了陣雨拓颓、多云、晴三種天氣信息砰左,剩下的按照需求自己完成就行场航。

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

    # 城市碼
    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小時(shí)
            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資源進(jìn)行存儲(chǔ)好啰,貼上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進(jìn)行資源的處理:

$ 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())

哦對(duì)了坎怪,我列一下這個(gè)程序所用到的模塊:

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

結(jié)束語

在PyQt5上我也只是個(gè)菜鳥男应,出這個(gè)系列教程的目的呢娱仔,還是想讓自己學(xué)到的東西能夠用上,不至于學(xué)起來那么盲目耐朴,另外也希望可以幫助想學(xué)習(xí)PyQt5的你盹憎。附上我的座右銘:
沒有什么是學(xué)習(xí)學(xué)不來的。
——skyloveraining

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末影晓,一起剝皮案震驚了整個(gè)濱河市檩禾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盼产,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侨核,死亡現(xiàn)場離奇詭異芹关,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)侥衬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門轴总,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人怀樟,你說我怎么就攤上這事⌒岛桑” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵吨瞎,是天一觀的道長颤诀。 經(jīng)常有香客問我,道長崖叫,這世上最難降的妖魔是什么拍柒? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮剧包,結(jié)果婚禮上往果,老公的妹妹穿的比我還像新娘一铅。我一直安慰自己,他們只是感情好潘飘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著戈擒,像睡著了一般艰毒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天蜀肘,我揣著相機(jī)與錄音扮宠,去河邊找鬼。 笑死坛增,一個(gè)胖子當(dāng)著我的面吹牛薄腻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播被廓,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昆婿!你這毒婦竟也來了蜓斧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤看疙,失蹤者是張志新(化名)和其女友劉穎直奋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脚线,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年渠旁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了船逮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡杂靶,死狀恐怖承耿,靈堂內(nèi)的尸體忽然破棺而出加袋,到底是詐尸還是另有隱情,我是刑警寧澤职烧,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布防泵,位于F島的核電站,受9級(jí)特大地震影響足删,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜失受,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一咏瑟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧码泞,春花似錦、人聲如沸领铐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肥缔。三九已至,卻和暖如春续膳,著一層夾襖步出監(jiān)牢的瞬間坟岔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工社付, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸥咖。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像啊研,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子党远,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容