1. 程式人生 > >基於python3爬蟲的對12306餘票查詢的圖形介面

基於python3爬蟲的對12306餘票查詢的圖形介面

    學了爬蟲也有將近四個月了,寫過的爬蟲也有蠻多的。最近剛要開學,學生來校大多坐火車來,就尋思做一個餘票查詢的小工具,順帶溫習一下所學的爬蟲知識還有對python程式設計的一些用法,將從12306網上爬取到達實時資料做成圖形介面,以下便是我的小工具的version1的具體做法,工具中稍有些bug未能改正,但是我想先把我自己所獲得的東西先放到我的部落格上面來,有想法的小夥伴可以聯絡我,歡迎大路大神指教!
    import requests
    from tkinter import Tk,Label,Entry,Button,Text,END
    首先引入咱們工具所需要用到的庫以及類,其中requests庫是用來想網路發起請求的一個模組,該模組在python3的網路爬蟲中比較常用,然後就是GUI程式設計中所需的tkinter模組,從其中引入給各類用來生成圖形介面。
接下來就是爬取我們所需要的資訊和資料了。我們過通過對12306網站的分析,從開發者工具中找到所需要請求的內容和提交的引數如下圖所示:
    https://img-blog.csdn.net/20180914210504299?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MTM0OTk0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70

    https://img-blog.csdn.net/20180914210520486?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MTM0OTk0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70

通過對網頁的分析可以得到我們需要用get請求的方法並增加引數params來獲取網頁的響應,在提交引數的時候我們需要搞清楚每個變數代表的含義,所以之後我們將會再一次爬取,另外一個網頁得到每個城市的英文程式碼。獲取到的響應內容為json格式的字串,我們通過對字典取值的方法和便利找到我們所需要的資訊。具體請看爬取程式碼:

1.爬取我們所需資料的主要邏輯程式碼,將內容追加到列表中,然後返回;
    def ticket_check(self,date,from_station,to_station):
        url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?'
        data = {
            'leftTicketDTO.train_date':date,
            'leftTicketDTO.from_station':from_station,
            'leftTicketDTO.to_station':to_station,
            'purpose_codes':'ADULT'
        }
        res = requests.get(url,params = data)
        res.encoding = res.apparent_encoding
        info = res.json()['data']['result']
        a = self.box
        for i in info:
            train = i.split('|')[3]
            start_time = i.split('|')[8]
            end_time = i.split('|')[9]
            total_time = i.split('|')[10]
            a.append('\n'+'\t'+'車次:'+train+ '\t\t' + '出發時間:' +start_time+ '\t\t'\
                  +'到達時間:' +end_time+ '\t\t'+ '用時:'+ total_time+'\n'+'\n')
        return a

該類方法中傳入三個引數,分別為時間、出發地、目的地,通過對網頁的爬取和解析,將資訊儲存再列表中並返回;

2.獲取出發地和目的地的城市英文程式碼;
 def get_tstation_name(self,t):
    url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9061'
    res = requests.get(url)
    res.encoding = res.apparent_encoding
    ret = res.text
    ret = ret[20:-2]
    ret_list = ret.split('|')
    station_name = ret_list[1::5]
    station_code = ret_list[2::5]
    name_code = dict(tuple(zip(station_name, station_code)))
    if t in name_code.keys():
        return name_code[t]
    else:
        return name_code[input('請重新輸入正確的到達地:')]

    傳入目的地的中文,對網頁獲取和解析,得到所需要的城市英文程式碼並返回;同理,獲得出發地的英文程式碼並返回;

3.接下來就是圖形介面的編寫了,主要圖形如下圖所示:
![這裡寫圖片描述](https://img-blog.csdn.net/20180914211727520?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MTM0OTk0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

通過輸入出發時間、出發地、目的地,點選‘查詢’按鈕,對餘票資訊的列印,將結果顯示在下方的Text框中,以下為圖形介面的主要邏輯程式碼:
    def __init__(self):
        #main window
        self.window = Tk()
        self.window.title('Train check tool')
        self.window.geometry('600x750+400+20')
        #label
        self.label1 = Label(self.window,text = '請輸入出發日期:')
        self.label1.place(x=60,y = 10)
        self.label2 = Label(self.window,text = '請輸入出發地:')
        self.label2.place(x=60,y = 40)
        self.label3 = Label(self.window,text = '請輸入目的地:')
        self.label3.place(x=60,y = 70)
        self.label4 = Label(self.window,text = '查詢結果如下:')
        self.label4.place(x=60,y=150)
        #entry
        self.enter1 = Entry(self.window)
        self.enter1.place(x = 200,y=10)
        self.enter2 = Entry(self.window)
        self.enter2.place(x = 200,y=40)
        self.enter3 = Entry(self.window)
        self.enter3.place(x = 200,y=70)
        # button check
        self.button1 = Button(self.window, text='查詢', command=self.check)
        self.button1.place(x=100, y=110, width=100)
        # button cls
        self.button2 = Button(self.window, text='清空', command=self.clear)
        self.button2.place(x=270, y=110, width=100)
        # text field
        self.text = Text(self.window)
        self.text.place(x=10, y=170, height=540)
        self.box = []

    設定好介面的大小和距離後,通過Button中的command引數將事件驅動連線起來,達到點選按鈕完成事件,其中clear方法稍簡單些,只要通過在定義的entry、text物件中的delete方法將所有內容清空即可,程式碼如下:
    def clear(self):
        self.enter1.delete(0,END)
        self.enter2.delete(0, END)
        self.enter3.delete(0, END)
        self.text.delete('1.0',END)

主要的功能實現的介面就是check方法了,通過對輸入框的get方法,將輸入的內容獲取到後,分別定義三個變數來接收,之後再呼叫我們之前寫好的對12306網站爬蟲的方法,我們前面說過,將所需資訊內容儲存在列表中,目的是將列表的內容在Text中用insert方法進行插入,實現對內容的抓取和展現。以下為check方法的具體邏輯程式碼:
    def check(self):
        date = self.enter1.get()
        f = self.enter2.get()
        t = self.enter3.get()
        f_des = self.get_fstation_name(f)
        t_des = self.get_tstation_name(t)
        content = self.ticket_check(date,f_des,t_des)
        self.text.insert(END,content)
主要功能實現以及全部寫好了,接下來我們將所有的程式碼整合起來,稍加整理,定義一個Application類,將所有的邏輯程式碼整合在該類中,然後我們例項化該類,呼叫類方法run將整個程式執行起來,其中run方法為:
    def run(self):
        self.window.mainloop()
 例項化該類,執行程式:
     if __name__ =='__main__':
        app = Application()
        app.run()
至此,火車票餘票查詢小工具就做好了,其中還有很多值得改正的地方,我也繼續學習,不斷完善不斷改進。以下為程式執行結果:
https://img-blog.csdn.net/20180914213329802?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MTM0OTk0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70
總結一下以上所寫的全部內容,這是我的第一步部落格文章,在部落格編寫期間,總是感覺自己在程式碼編寫和部落格文章時的不平衡,我的想法可能比較奇怪,今後一定多多完善,歡迎大家留言討論和指正,謝謝!

                                        來自一個正在打怪升級的軟院大學生