12306余票及票价查询

还原整个思路,遇到的一些问题也会写出来,纯新手向,因为打包在了一个类里,所以单独拷贝一个函数可能会有些问题,后面有完整代码地址,如有错误可以指正- -有问题也可以留言,后面写的有些赶,可以去完整源代码中看看
截至2018/10/9 0:15代码还是有效的

环境:

python3.6
涉及的库:
requests
json
prettytable
re
pprint
1.url分析
先打开12306的余票查询,我用的是火狐浏览器,按F12打开调试工具选择network(网络)选项,选择出发地,目的地,日期,点击查询
在这里插入图片描述
(小白问题:调试窗口里啥也没有是因为 你一番操作猛如虎,结果完事后想起:哎?调试窗口没打开!)
右上角有一排选项,咱选js,xhr 然后从这一条条里找出我们需要的链接(点的时候在右边选择响应,可以看到这条请求返回啥)哇塞!你找到一串data,里面还有各种车票的信息,好了,就是你了:
https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=2018-10-23&leftTicketDTO.from_station=HZH&leftTicketDTO.to_station=RZH&purpose_codes=ADULT
在这里插入图片描述
PS:找json链接这种活就看经验了,老手可能马上就能找到,新手可能就要一条条点(汗~~)我这给一个快速的方法:进入余票查询界面,选择好出发地和目的地及日期,点击查询,好!然后再打开F12调试界面在点查询!哇塞只有1条而且就是我们需要的!(深入原因的话就是在你打开了调试界面后你只进行了这一条查询的post请求,而返回的当然就是你要的了)
在这里插入图片描述
好,继续正题,我们来观察这条json的链接,很容易明白那些参数吧,如下:
https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=2018-10-23&leftTicketDTO.from_station=HZH&leftTicketDTO.to_station=RZH&purpose_codes=ADULT
leftTicketDTO.train_date=日期
leftTicketDTO.from_station=出发点的地点码
leftTicketDTO.to_station=目的地的地点码
purpose_codes=票的种类
2.获取车站对照字典
上文链接中有两个参数是地点码,即一个地名对应一个值,一开始我是直接下载了网上(baidu喽)的一个字典,然后最后写完.不对!我靠!而且调试半天定位到字典错了!(这么多的地名偏偏被窝测试到错误的也是没谁了…)
在这里插入图片描述
好!自己动手!

import requests
import re
#生成字典 运行一次后抛弃之~~~
def new_dictionary():
    url="https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9069"
    station_namesweb=requests.get(url)
    stationdic = re.findall(r'([\u4e00-\u9fa5]+)\|([a-zA-Z]+)', station_namesweb.text)
    stationdic=dict(stationdic)
    print(stationdic)
new_dictionary()

requests请求,json打包,正则提取,over!
打印出一个字典复制然后在一个文件里就ok了(上面代码中的url其实也是一样找的,可以试试手去找找看)哈哈,其实这也是今天整个工程的浓缩版吧,思路也是差不多的
3.输入出发点,目的地,时间,获得需要的查询链接
废多看码!!!

    def getUrl(self):
        startflag = False
        endflag = False
        while startflag == False:
            start = input("请输入始发地:\n")
            startflag = stations.__contains__(start)
            if startflag == False:
                print('始发地输入错误!')
        while endflag == False:
            end = input("请输入目的地:\n")
            endflag = stations.__contains__(end)
            if endflag == False:
                print('目的地输入错误!')

        self.date = input("请输入日期(格式为xxxx-xx-xx):\n")

        url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=' \
              + self.date + '&leftTicketDTO.from_station=' \
              + stations[start] + '&leftTicketDTO.to_station=' \
              + stations[end] + '&purpose_codes=ADULT'
        return url

4.获取车辆信息
因为12306在这里没做啥验证所以可以直接请求,不妨直接在浏览器里看一下,emmm是不是头都大了!!!
在这里插入图片描述
车辆的信息都在这里了,用|分隔开,我们要做的就是从里面提取出我们想要的信息,emmm其实我花的时间最多的是在这里,因为要一一对应知道每个信息代表什么,而我又找不到那么一辆每个信息都齐全的车来让我对照…只能用好几辆的信息来对比喽(还不一定是对的,眼力有限)…我的眼睛!!!
在这里插入图片描述

乱码|预订|030000K5540E|K551|MDB|RZH|HZH|RZH|02:31|10:50|08:19|Y|乱码|20181021|3|B2|44|52|0|0||||无|||无||有|10|||||10401030|1413|0

上代码:

    def getData(self,url):
        dataweb = requests.get(url)
        datajson = json.loads(dataweb.text)
        datatrains = datajson['data']['result']
        restations=datajson['data']['map']#地点缩写:地点全称的字典
        dataans = []
        for train in datatrains:
            per = {
                'train_no': '',
                'from_station_no': '',
                'to_station_no': '',
                'seat_types': '',
                'chufazhan':'',
                'dadaozhan':'',
                'checi': '',
                'chufasj': '',
                'didasj': '',
                'lishi': '',
                'erdeng': '',
                'yideng': '',
                'shangwu': '',
                'wuzuo':''
            }
            train = train.split('|')
            per['train_no'] = train[2]
            per['from_station_no'] = train[16]
            per['to_station_no'] = train[17]
            per['seat_types'] = train[35]
            per['chufazhan']=train[6]
            per['dadaozhan']=train[7]

            #将得到站点名字由缩写转换全称
            per['chufazhan']=restations[per['chufazhan']]
            per['dadaozhan']=restations[per['dadaozhan']]

            per['checi'] = train[3]
            per['chufasj'] = train[8]
            per['didasj'] = train[9]
            per['lishi'] = train[10]
            per['erdeng'] = train[30]
            per['yideng'] = train[31]
            per['shangwu'] = train[32]
            per['wuzuo']=train[26]
            for value in per:
                if (per[value] == ''):
                    per[value] = '-'
            dataans.append(per)
        return dataans

PS:这里有个问题要说明下:比如我朋友温州-金华,而金华有两个站,他只要其中一个站的,所以我们得显示出出发站和抵达站到底是哪个,但是在信息中我们获得地点是一个码而不是一个站的名字,而我们的字典中是 {名字:码},一开始我想要不干脆再做个反转的字典,后来往上翻的时候发现:原来上面已经给我们了!解决!计划通~
在这里插入图片描述
5.获取票价信息
票价的url是另外一条了,获取方式同上上,老方法请求,解析,打包

    def GetPrice(self,train_no,from_station_no,to_station_no,seat_types,date,price):
        url = 'https://kyfw.12306.cn/otn/leftTicket/queryTicketPrice?train_no=' \
              + train_no + '&from_station_no=' \
              + from_station_no + '&to_station_no=' \
              + to_station_no + '&seat_types=' \
              + seat_types + '&train_date=' + date
        priceweb=requests.get(url)
        pricejson=json.loads(priceweb.text)
        pricedata=pricejson['data']
        shangwu=pricedata.__contains__('A9')#商务
        yideng=pricedata.__contains__('M')#一等
        erdeng=pricedata.__contains__('O')#二等
        wuzuo=pricedata.__contains__('WZ')#无座
        if shangwu:
            price['shangwu']=pricedata['A9']
        else :
            price['shangwu']=''
        if yideng:
            price['yideng']=pricedata['M']
        else :
            price['yideng']=''
        if erdeng:
            price['erdeng']=pricedata['O']
        else :
            price['erdeng']=''
        if wuzuo:
            price['wuzuo']=pricedata['WZ']
        else :
            price['wuzuo']=''
        return price

6.输出
用了prettytable库输出表格

    def Print(self):
        price={
            'shangwu':'',
            'yideng':'',
            'erdeng':'',
            'wuzuo':'',
        }
        table = prettytable.PrettyTable()
        table.field_names = ["车次","出发站","达到站" ,"出发时间", "抵达时间", "历时", "二等座", "一等座", "商务座","无座"]
        for per in self.data:
            price=self.GetPrice(per['train_no'],per['from_station_no'],per['to_station_no'],per['seat_types'],self.date,price)
            table.add_row([per['checi'],per['chufazhan'],per['dadaozhan'], per['chufasj'], per['didasj'], per['lishi'], per['erdeng']+'\n'+price['erdeng'], per['yideng']+'\n'+price['yideng'],
                           per['shangwu']+'\n'+price['shangwu'],per['wuzuo']+'\n'+price['wuzuo']])
        print(table)

7.演示
在这里插入图片描述
8.完整代码
https://github.com/senjay/12306tickets_and_price_search

猜你喜欢

转载自blog.csdn.net/qq_36490364/article/details/82974157
今日推荐