1. 程式人生 > >Python 獲取車票資訊

Python 獲取車票資訊

提示:該程式碼僅供學習使用,切勿濫用!!!

 

先來一個git地址:https://gitee.com/wang_li/li_wang

 

效果圖:

 

邏輯:

1.獲取Json檔案的內容
2.根據資訊生成URL
3.獲取URL的內容,根據時間進行分析,如果有票則傳送郵件,如果沒有,則繼續監聽

 

1.定義Json檔案

內容如下:

{
  "_Nodes" : "定義起始站",
  "from_address" : "成都東",

  "_Nodes" : "定義終點站",
  "to_address" : "遂寧",

  "_Nodes" : "定義車次",
  "departure_date" : "2018-12-30",

  "_Nodes" : "定義時間檢查區間",
  "start_time" : "09:00",

  "_Nodes" : "定義時間結束區間",
  "stop_time" : "12:00",

  "_Nodes" : "定義列車型別 [ D:動車 Z:直達 T:特快 K:快速 A:全部 ]",
  "type" : "A",

  "_Nodes" : "定義是否傳送郵件 true為傳送 false為不傳送",
  "send_mail" : "false",

  "_Nodes" : "如果上述定義為true,則下面則定義郵箱的資訊包括,SMTP 和 認證資訊",
  "mail_smtp" : "smtp.qq.com",
  "user_name" : "
[email protected]
", "user_password" : "password", "mail_subject" : "僅僅是為了好玩", "_Nodes" : "將資訊傳送給誰", "mail_to_address" : "[email protected];[email protected]", "_Nodes" : "有票時,提示的最大次數,當有間隔時,則重新計數 , 這裡最大值為100", "send_mail_max" : 3, "_Nodes" : "重新整理間隔時間,單位:秒", "interval_time" : 30 }

 

2.Python程式碼處理Json檔案並且返回結果

程式碼如下:

#!/usr/bin/env python3

import requests
import json
import time
import sys
import email.mime.text
import smtplib

#解析json檔案

def Dealwith_jsonfile(jsonfile) :

    return_dirct = {}
    #定義json標題
    json_title = ['from_address' , 'to_address' , 'departure_date
' , 'start_time' , 'stop_time' , 'type' , 'send_mail' , 'mail_smtp' , 'user_name' , 'user_password' , 'mail_subject', 'mail_to_address' , 'send_mail_max','interval_time'] #讀取檔案 open_json_file = open(jsonfile , 'rb') #初始化send_mail引數 send_mail_on = 0 #開啟try except 捕獲json錯誤的資訊 try: dict_json_file = json.load(open_json_file) #查詢是否開啟發送郵件 if 'true' == dict_json_file['send_mail'] : send_mail_on = 1 # 0 為不開啟,則不需要記錄smtp/username/password/send_mail的資訊 if 0 == send_mail_on : for title_configure in json_title : if 'mail_smtp' == title_configure or 'user_name' == title_configure or 'user_password' == title_configure or 'send_mail_max' == title_configure or 'mail_subject' == title_configure or 'mail_to_address' == title_configure: continue else : return_dirct[title_configure] = dict_json_file[title_configure] else : for title_configure in json_title : return_dirct[title_configure] = dict_json_file[title_configure] #關閉檔案 open_json_file.close() print(return_dirct) return return_dirct except Exception as e: print("處理Json檔案失敗,詳情如下:") print(e) if __name__ == "__main__" : Dealwith_jsonfile("go_gome.json")

執行的結果如下:

{'from_address': '成都東', 'to_address': '遂寧', 'departure_date': '2019-01-04', 'start_time': '09:30', 'stop_time': '12:00', 'type': 'D', 'send_mail': 'true', 'mail_smtp': 'smtp.qq.com', 'user_name': '[email protected]', 'user_password': 'idfqdnnrfjttbjbe', 'mail_subject': '僅僅是為了好玩', 'mail_to_address': '[email protected]', 'send_mail_max': 2, 'interval_time': 10}

 

3.獲取站別ID

網址:https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9085 

具體內容如下:

通過分析得到,名詞的後一位就是站別ID

 

Python獲取站別ID如下:

#!/usr/bin/env python3

import requests

def Get_Address_resolution(from_address,to_address , Address_type) :

    return_station_name = []

    # 站點資訊可以在12306網站上找到
    station_name_url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9085'

    #獲取網頁資訊
    station_information = requests.get(station_name_url).text

    #以 | 分割
    list_station_information = station_information.split("|")

    # 獲取from_address 和 to_address 地址的ID
    if 1 == Address_type :
        address_com = 1
    elif 2 == Address_type :
        address_com = -1
    else :
        return  return_station_name

    for address in from_address , to_address  :
        try:
            if list_station_information.index(address):
                return_station_name.append(
                    list_station_information[list_station_information.index(address) + address_com])
        except Exception as e:
            print(e)

    return return_station_name

if __name__ == "__main__" :
    print(Get_Address_resolution('成都東','遂寧',1))
    print(Get_Address_resolution('ICW', 'NIW', 2))

 

執行結果如下:

['ICW', 'NIW']
['成都東', '遂寧']

 

3.獲取實際URL

通過分析,我們可以得知,每次請求網頁,實際上實在請求一個數據包,例如:

https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2019-01-05&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=SHH&purpose_codes=ADULT

我們只需要將資料拼接上就可以了

 

程式碼如下:

#!/usr/bin/env python3

def Generate_Url () :
    try:
        station_code = ['ICW', 'NIW']
        #獲取最新的地址解析時間(此資訊也是固定的)
        return_url = "https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=%s&leftTicketDTO.from_station=%s&leftTicketDTO.to_station=%s&purpose_codes=ADULT" \
                     %('2019-01-03' ,station_code[0] , station_code[1] )
        return return_url
    except Exception as e:
        print("生成URL失敗")
        print(e)

if __name__ == "__main__" :
    print(Generate_Url())

 

https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=2019-01-03&leftTicketDTO.from_station=ICW&leftTicketDTO.to_station=NIW&purpose_codes=ADULT

 

 

綜合程式碼

#!/usr/bin/env python3

import requests
import json
import time
import sys
import email.mime.text
import smtplib

#解析json檔案

def Dealwith_jsonfile(jsonfile) :

    return_dirct = {}
    #定義json標題
    json_title = ['from_address' , 'to_address' , 'departure_date' , 'start_time' , 'stop_time' , 'type' , 'send_mail' , 'mail_smtp' , 'user_name' , 'user_password' , 'mail_subject', 'mail_to_address' , 'send_mail_max','interval_time']

    #讀取檔案
    open_json_file = open(jsonfile , 'rb')

    #初始化send_mail引數
    send_mail_on = 0

    #開啟try except 捕獲json錯誤的資訊
    try:
        dict_json_file = json.load(open_json_file)

        #查詢是否開啟發送郵件
        if 'true' == dict_json_file['send_mail'] :
            send_mail_on = 1

        # 0 為不開啟,則不需要記錄smtp/username/password/send_mail的資訊
        if 0 == send_mail_on :
            for title_configure in json_title :
                if 'mail_smtp' == title_configure or 'user_name' == title_configure or 'user_password' == title_configure or 'send_mail_max' == title_configure or 'mail_subject' == title_configure or 'mail_to_address' == title_configure:
                    continue
                else :
                    return_dirct[title_configure] = dict_json_file[title_configure]

        else :
            for title_configure in json_title :
                return_dirct[title_configure] = dict_json_file[title_configure]

        #關閉檔案
        open_json_file.close()
        return return_dirct

    except Exception as e:
        print("處理Json檔案失敗,詳情如下:")
        print(e)

#抓取城市名稱對應的ID
def Get_Address_resolution(from_address,to_address , Address_type) :

    #定義返回列表
    return_station_name = []

    # 站點資訊可以在12306網站上找到
    station_name_url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9085'

    #獲取網頁資訊
    station_information = requests.get(station_name_url).text

    #以 | 分割
    list_station_information = station_information.split("|")

    # 獲取from_address 和 to_address 地址的ID
    if 1 == Address_type :
        address_com = 1
    elif 2 == Address_type :
        address_com = -1
    else :
        return  return_station_name

    for address in from_address , to_address  :
        try:
            if list_station_information.index(address):
                return_station_name.append(
                    list_station_information[list_station_information.index(address) + address_com])
        except Exception as e:
            print(e)

    return return_station_name

    #     try:
    #         if list_station_information.index(from_address) :
    #             return_station_name.append(list_station_information[list_station_information.index(from_address) + 1])
    #     except Exception as e:
    #         print(e)
    #
    #     try:
    #         if list_station_information.index(to_address):
    #             return_station_name.append(list_station_information[list_station_information.index(to_address) + 1])
    #     except Exception as e:
    #         print(e)
    #
    #     #將ID返回回去
    #     return return_station_name
    #
    # #程式碼和上述一致,可以合併為到一塊
    # elif 2 == Address_type :
    #     try:
    #         if list_station_information.index(from_address) :
    #             return_station_name.append(list_station_information[list_station_information.index(from_address) - 1])
    #     except Exception as e:
    #         print(e)
    #
    #     try:
    #         if list_station_information.index(to_address):
    #             return_station_name.append(list_station_information[list_station_information.index(to_address) - 1])
    #     except Exception as e:
    #         print(e)
    #
    #     #將ID返回回去
    #     return return_station_name


#生成URL連線
def Generate_Url (operation_parameters) :

    try:
        station_code = Get_Address_resolution(operation_parameters['from_address'],operation_parameters['to_address'],1)
        #獲取最新的地址解析時間(此資訊也是固定的)
        return_url = "https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=%s&leftTicketDTO.from_station=%s&leftTicketDTO.to_station=%s&purpose_codes=ADULT" \
                     %(operation_parameters['departure_date'] ,station_code[0] , station_code[1] )
        return return_url
    except Exception as e:
        print("生成URL失敗")
        print(e)

#爬取是否有票
def Crawling_Informations (url , operation_parameters) :

    #初始化檢查失敗引數
    check_failed = 0

    #初始化票send-mail次數
    send_mail_number = {}

    #定義無限迴圈
    while True:
        if check_failed > 10 :
            print("連續10次抓取失敗,程式退出")
            break

        try:
            #獲取內容並且轉換為json
            crawling_text = requests.get(url).text
            crawling_json = json.loads(crawling_text)

            #定義空的列表用於存放票務資訊
            checkmessageall = []

            #便利json檔案的['data']['result']資訊
            for crawling_list in crawling_json['data']['result'] :
                checkmessage = []

                #將票務資訊按 | 分割
                for split_list_json in crawling_list.split('|'):
                    #排除長度問20字元的行
                    if len(split_list_json) > 20:
                        pass
                    else:
                        #將其他值壓進checkmessage
                        checkmessage.append(split_list_json)

                #將整個checkmessage 押進checkmessageall
                checkmessageall.append(checkmessage)

            #開始處理我們爬過來的票務資訊
            for dealwithforlist in checkmessageall:

                # 計算列車型別
                train_type = operation_parameters['type']

                # 判斷 [ D:動車 Z:直達 T:特快 K:快速 A:全部 ] 如果都不是的話,預設設定為A 全部
                if train_type != 'D' and train_type != 'Z' and train_type != 'T' and train_type != 'K' and train_type != 'A' :
                    train_type = 'A'

                # 開始匹配列車型別
                if train_type in dealwithforlist[dealwithforlist.index('預訂') + 2] or train_type == 'A' :

                    #獲取設定的開始時間和結束時間
                    start_time = operation_parameters['start_time']
                    stop_time = operation_parameters['stop_time']

                    # 判斷開始時間是否大於結束時間
                    if stop_time <= start_time :
                        print("開始時間不能超過結束時間")
                        sys.exit(-1)

                    # 開始匹配我們的 開始時間 和 結束時間
                    if (start_time <= dealwithforlist[dealwithforlist.index('預訂') + 7] ) and (stop_time >= dealwithforlist[dealwithforlist.index('預訂') + 7] ) :

                        # 判斷是否有票
                        if 'Y' == (dealwithforlist[dealwithforlist.index('預訂') + 10]):
                            print("有票")
                            print(dealwithforlist)

                            # 判斷是否傳送郵件
                            if 'true' == operation_parameters['send_mail']:
                                #獲取郵件傳送最大次數
                                send_mail_max = operation_parameters['send_mail_max']

                                # 如果沒有郵件傳送計數,則重新生成
                                if (dealwithforlist[dealwithforlist.index('預訂') + 2]) not in send_mail_number:
                                    send_mail_number[dealwithforlist[dealwithforlist.index('預訂') + 2]] = 0

                                # 判斷髮送郵件
                                if (send_mail_number[dealwithforlist[dealwithforlist.index('預訂') + 2]]) <= send_mail_max :
                                    Send_Mail_Only_You_Yan(dealwithforlist , operation_parameters)
                                    pass

                                if send_mail_number[dealwithforlist[dealwithforlist.index('預訂') + 2]] <= 1200 :
                                    send_mail_number[dealwithforlist[dealwithforlist.index('預訂') + 2]] = send_mail_number[dealwithforlist[dealwithforlist.index('預訂') + 2]] + 1

                        else:
                            print("沒有票")
                            print(dealwithforlist)
                            #將sned_mail_number至0
                            send_mail_number[dealwithforlist[dealwithforlist.index('預訂') + 2]] = 0

            # 獲取間隔時間
            interval_time = operation_parameters['interval_time']
            #定義睡眠時間
            time.sleep(interval_time)

            check_failed = 0
        except Exception as e:
            print(e)
            check_failed = check_failed + 1

def Send_Mail_Only_You_Yan (dealwithforlist , operation_parameters):

    #獲取票的資訊
    network_list_info_station_address = Get_Address_resolution(dealwithforlist[dealwithforlist.index('預訂') + 3],dealwithforlist[dealwithforlist.index('預訂') + 4],2)
    network_list_info_train_number = dealwithforlist[dealwithforlist.index('預訂') + 2]
    network_list_info_start_time = dealwithforlist[dealwithforlist.index('預訂') + 7]
    network_list_info_stop_time = dealwithforlist[dealwithforlist.index('預訂') + 8]
    network_list_info_run_time = dealwithforlist[dealwithforlist.index('預訂') + 9]
    network_list_info_date = dealwithforlist[dealwithforlist.index('預訂') + 11]
    local_list_info_start_address = operation_parameters['from_address']
    local_list_info_to_address = operation_parameters['to_address']

    #獲取郵件資訊
    local_list_info_mail_smtp = operation_parameters['mail_smtp']
    local_list_info_mail_user = operation_parameters['user_name']
    local_list_info_mail_password = operation_parameters['user_password']
    local_list_info_mail_subject = operation_parameters['mail_subject']
    local_list_info_mail_to_address = operation_parameters['mail_to_address']

    HOST = local_list_info_mail_smtp
    SUBJECT = local_list_info_mail_subject
    TO = local_list_info_mail_to_address
    FROM = local_list_info_mail_user

    msg = email.mime.text.MIMEText(
    """
        <html>
                <head>
                    <title>僅僅是為了好玩</title>
                        <style>
                            body {
                                width: 35em;
                                margin: 0 auto;
                                font-family: Tahoma, Verdana, Arial, sans-serif;
                            }
                        </style>
                </head>

                <body>
                        <table style="padding: 1px;background-color: #2300f9;">
                            <tr>
                                <th style="background-color: white">車次</th>
                                <th style="background-color: white">需求出發站</th>
                                <th style="background-color: white">需求到達站</th>
                                <th style="background-color: white">車票出發站</th>
                                <th style="background-color: white">車票到達站</th>
                                <th style="background-color: white">時間</th>
                                <th style="background-color: white">發車時間</th>
                                <th style="background-color: white">到達時間</th>
                                <th style="background-color: white">歷時</th>
                            </tr>
                            <tr>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                                <td style="background-color: white">%s</td>
                            </tr>
                        </table>
                </body>
        </html>
    """ %(network_list_info_train_number ,local_list_info_start_address ,local_list_info_to_address , network_list_info_station_address[0] , network_list_info_station_address[1] ,network_list_info_date , network_list_info_start_time , network_list_info_stop_time , network_list_info_run_time ), "html","utf-8")

    msg['Subject'] = SUBJECT
    msg['From'] = FROM
    msg['TO'] = TO

    server = smtplib.SMTP_SSL(HOST,'465')
    server.login(local_list_info_mail_user,local_list_info_mail_password)
    server.sendmail(FROM,TO.split(';'),msg.as_string())
    server.quit

if __name__ == "__main__" :

    # #解析json檔案
    # operation_parameters = Dealwith_jsonfile("go_gome.json")
    #
    # #生成URL連線
    # url = Generate_Url(operation_parameters)
    #
    # #開始查詢票票
    # Crawling_Informations(url , operation_parameters)

    Crawling_Informations(Generate_Url(Dealwith_jsonfile("go_gome.json")) , Dealwith_jsonfile("go_gome.json"))