pythyon爬虫实现12306查票

今天接触python的第二天,犹豫现在刚好是春运阶段,所以想用python实现12306抢票功能,犹豫刚接触python,能力有限,所以只根据百度可以查到的教程,做了一个查票功能

1.实现查票功能,就是爬取12306上的余票信息,再在本地进行组织展示

首先打开12306的余票查询界面,分析页面

pythyon爬虫实现12306查票

从上图可以看到,当点击查询功能是所访问的连接,以及响应数据,我们所要做的就是对响应数据进行解析

2.从地址中我们可以看到查票时所需要传递的参数

https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2018-01-16&leftTicketDTO.from_station=VNP&leftTicketDTO.to_station=CDW&purpose_codes=ADULT

leftTicketDTO.train_date为出发日期 leftTicketDTO.from_station为出发地leftTicketDTO.to_station为目的地 purpose_codes=ADULT为成人票

从链接中可以看到 出发地与目的地都为字母,这个是因为12306将所有的地点都做了一个字典存在下面这个js中,可以将地址输入到浏览器上,查看js中内容

https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8964
本人在程序中将以上JS文件中的内容存到了stations.py中

3.开始今天的正文部分,爬取数据,

先根据improt将所需要的插件安装好,然后将所需要的参数准备好:

import stations
from Splider12306 import Splider
#将地点与所对应的字母对应到字典中,我是将
station = {}
for s in stations.station_names.split('@'):
    if s:
        tmp = s.split('|')
        station[tmp[1]] = tmp[2]
# train_date = raw_input("请输入出发时间(格式为2018-01-01) >")
# from_station = station[raw_input("请输入出发城市 >")]
# to_station = station[raw_input("请输入目的城市 >")]
# print from_station+ to_station
splider = Splider()
train_date = '2018-02-11'
from_station = 'JNK'
to_station = 'ZDN'
splider.doCraw(train_date,from_station,to_station,station)
开始爬取数据:本例中利用PrettyTable将解析好的数据已表格形式展现

# coding=utf-8
import requests
import re
import base64

from prettytable import PrettyTable
class Splider :
    def __init__(self):
        self.headers = {
            "Accept": "*/*",
            "Accept-Encoding": "gzip, deflate, sdch, br",
            "Accept-Language": "zh-CN,zh;q=0.8",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4549.400 QQBrowser/9.7.12900.400"
        }


# stations=r.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)',r.json()["data"]["result"])#用正则表达式 来获取车站的拼音和大小写字母的代号信息
# print stations
# print isinstance(str(r.json()), unicode)
# print r.content.decode('utf-8')

    def doCraw(self,train_date,from_station,to_station,station) :
        new_station = {v: k for k, v in station.items()}
        # print station
        self.TicketSession = requests.Session()
        self.TicketSession.headers = self.headers
        self.TicketSession.verify = False

        self.query_url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=%s&leftTicketDTO.from_station=%s&leftTicketDTO.to_station=%s&purpose_codes=ADULT' %(train_date,from_station,to_station)
        # r = requests.get(query_url, verify=False)
        r = self.TicketSession.get(self.query_url)
        if r.status_code != 200 :
            print '查询超时,请稍后再试!'
            return
        # print r.status_code

        # with open('json.txt', 'w') as fp:
        #     fp.write(str(r.json()).decode('utf-8').encode('mbcs'))
        pt = PrettyTable()
        header = '车次 出发站 到达站 出发时间 到达时间 时长 一等座 二等座 软卧 硬卧 硬座 无座 预定'.split()
        pt._set_field_names(header)
        if 'result' in r.json()["data"]:
            rj = r.json()["data"]["result"]
            c = 0
            d = 0
            for i in rj:
                ptrow = []
                n = i.split('|')
                # d += 1
                # for n in i.split('|'):
                #     # ptrow.append(x["station_train_code"])
                #     print'[%s] %s' % (c, n)
                #     c += 1
                # c = 0
                # # if d>1:
                # #     break
                # print n[6]
                # print n[7]
                ptrow.append(n[3])#车次
                ptrow.append(new_station[n[6]])#出发站
                ptrow.append(new_station[n[7]])#到达站
                ptrow.append(n[8])#出发时间
                ptrow.append(n[9])#到达时间
                ptrow.append(n[10])#时长
                ptrow.append(n[31])#一等座
                ptrow.append(n[30])#二等座
                ptrow.append(n[23])#软卧
                ptrow.append(n[26])#硬卧
                ptrow.append(n[28])#硬座
                ptrow.append(n[29])#无座
                ptrow.append(n[1])  # 预定
                pt.add_row(ptrow)

            print pt
        else:
            print '这两个站点没有直达列车'

4.结果展示:当控制台出现r.json()报错是,是因为没有查询到数据,只需要再次执行即可

pythyon爬虫实现12306查票