Python3.6实现12306火车票自动抢票

最近在学Python,所以用Python写了这个12306抢票脚本,分享出来,与大家共同交流和学习,有不对的地方,请大家多多指正。话不多说,进入正题:

在进入正题之前,我想说明一下,由于12306官网的改版更新,所以脚本作了一点小小的变化,具体修改后的源码,可以到GitHub上面查看……

这个脚本目前只能刷一趟车的,人数可以是多个,支持选取作为类型等。
实现思路是splinter.browser模拟浏览器登陆和操作,由于12306的验证码不好自动识别,所以,验证码需要用户进行手动识别,并进行登陆操作,之后的事情,就交由脚本来操作就可以了,下面是我测试时候的一些截图:

第一步:如下图,首先输入抢票基本信息:Python入门到实践学习教程请加群

第二步:然后进入登录页,需要手动输入验证码,并点击登陆操作:219539519零基础,进阶欢迎加入免费获取学习教程

第三步:登陆后,自动进入到抢票页面,如下图这样的

通过“>”,来重定向输出的内容,通过“>>”将输出的内容追加到文件中,这里我们通过 $ python parse_station.py > station.py

# coding: utf-8
import re
import requests
from pprint import pprint 


def main():

url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971'
# 发送get请求,不判断证书
response = requests.get(url, verify=False)
# 使用正则表达式提取所有的站点:汉字和大写代号
stations = dict(re.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text))
# 转换成字典就是为了将汉字站点和字母代号分开且有一一对应关系:键-->值
pprint(stations.keys())
pprint(stations.values())

if __name__ == '__main__':
main()
在station.py 中建立键值之间的双向关系

def get_name(telecode):

return names[telecodes.index(telecode)]

def get_telecode(name):
return telecodes[names.index(name)]
这里先对提取数据的代码中涉及到的点进行总结:

1.两种格式化输出的方式:%和format
In [7]: "%s,%d"%("kzc",18)
Out[7]: 'kzc,18'
In [8]: '{0},{1}'.format('kzc',18)
Out[8]: 'kzc,18'
2.用到的库

requests:爬虫必用的发送请求,获取HTML网页内容的库
docopt:命令行解析工具,可以根据自定义的文档描述,自动生成解析器

prettytable:能让你的数据像MySQL的命令行显示数据的格式一样

colorama:命令行着色库

# coding: utf-8

"""命令行火车票查看器:Usage Options为docopt库固定格式
Usage:
tickets [-dgktz] <from>  
Options:
-h, --help 查看帮助
-d 动车
-g 高铁
-k 快速
-t 特快
-z 直达
Examples:
tickets 上海 北京 2017-10-10
tickets -dg 成都 南京 2017-10-10
"""

from docopt import docopt
import requests
from prettytable import PrettyTable
from colorama import Fore
import stations

def cli():
arguments = docopt(__doc__,version='ticket 1.0')
from_station = stations.get_telecode(arguments.get(''))
to_station = stations.get_telecode(arguments.get(''))
date = arguments.get('')
# 列表推导式,得到的是查询车次类型的集合
options = ''.join([key for key,value in arguments.items() if value is True])
print(options)

url = ('https://kyfw.12306.cn/otn/leftTicket/query?'
'leftTicketDTO.train_date={}&'
'leftTicketDTO.from_station={}&'
'leftTicketDTO.to_station={}&'
'purpose_codes=ADULT').format(date,from_station,to_station)

r = requests.get(url, verify=False)
# print(r.json())
#   requests得到的是一个json格式的对象,r.json()转化成python字典格式数据来提取,所有的车次结果result
raw_trains = r.json()['data']['result']
pt = PrettyTable()
pt._set_field_names("车次 车站 时间 经历时 一等座 二等座 软卧 硬卧 硬座 无座".split())
for raw_train in raw_trains:
# split切割之后得到的是一个列表
data_list = raw_train.split("|")
train_no = data_list[3]
initial = train_no[0].lower()
# print(train_no[0])
# 判断是否是查询特定车次的信息
if not options or initial in options:
from_station_code = data_list[6]
to_station_code = data_list[7]
from_station_name = ''
to_station_name = ''
start_time = data_list[8]
arrive_time = data_list[9]
time_duration = data_list[10]
first_class_seat = data_list[31] or "--"
second_class_seat = data_list[30] or "--"
soft_sleep = data_list[23] or "--"
hard_sleep = data_list[28] or "--"
hard_seat = data_list[29] or "--"
no_seat = data_list[33] or "--"

pt.add_row([
# 对特定文字添加颜色
train_no,
'\n'.join([Fore.GREEN + stations.get_name(from_station_code) + Fore.RESET, Fore.RED + stations.get_name(to_station_code) + Fore.RESET]),
'\n'.join([Fore.GREEN + start_time + Fore.RESET,Fore.RED + arrive_time + Fore.RESET]),
time_duration,
first_class_seat,
second_class_seat,
soft_sleep,
hard_sleep,
hard_seat,
no_seat
])

print(pt)


if __name__ == '__main__':
cli()

 

你可能感兴趣的:(Python3.6实现12306火车票自动抢票)