pythyon爬虫实现12306查票
今天接触python的第二天,犹豫现在刚好是春运阶段,所以想用python实现12306抢票功能,犹豫刚接触python,能力有限,所以只根据百度可以查到的教程,做了一个查票功能
1.实现查票功能,就是爬取12306上的余票信息,再在本地进行组织展示
首先打开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()报错是,是因为没有查询到数据,只需要再次执行即可