Python 爬虫抢火车票:实现原理与代码示例
抢火车票的实现思路如下:
- 登录 12306 网站,获取用户登录后的 cookie 信息
- 输入出发日期和出发地点、目的地点等信息,获取需要抢购的车票的相关信息,如车次、座位类型、价格等
- 模拟用户查询车票,并获取车票的余票信息
- 如果有余票,模拟用户提交订单
- 如果提交订单成功,模拟用户支付订单
具体实现代码如下:
import requests
import time
# 登录 12306 网站,获取 cookie
def login():
url = 'https://kyfw.12306.cn/otn/login/init'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}
session = requests.Session()
session.headers.update(headers)
session.get(url)
login_url = 'https://kyfw.12306.cn/passport/web/login'
data = {
'username': 'your_username',
'password': 'your_password',
'appid': 'otn'
}
session.post(login_url, data=data)
return session.cookies
# 获取车票信息
def get_ticket_info(date, from_station, to_station, seat_type):
url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ'
params = {
'leftTicketDTO.train_date': date,
'leftTicketDTO.from_station': from_station,
'leftTicketDTO.to_station': to_station,
'purpose_codes': 'ADULT'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
resp = session.get(url, params=params)
data = resp.json()['data']
for d in data:
d = d['queryLeftNewDTO']
if d['seat_types'].find(seat_type) != -1:
return d['train_no'], d['from_station_telecode'], d['to_station_telecode'], d['start_time'], d['arrive_time'], d['lishi'], d['swz_num'], d['tz_num'], d['zy_num'], d['ze_num'], d['wz_num'], d['yb_num'], d['rw_num'], d['yw_num'], d['rz_num'], d['yz_num']
return None
# 提交订单
def submit_order(date, train_no, from_station, to_station, seat_type, passengers):
url = 'https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest'
data = {
'secretStr': '',
'train_date': date,
'back_train_date': date,
'tour_flag': 'dc',
'purpose_codes': 'ADULT',
'query_from_station_name': '',
'query_to_station_name': '',
'undefined': ''
}
params = {
'leftTicketDTO.train_no': train_no,
'leftTicketDTO.train_date': date,
'leftTicketDTO.station_train_code': '',
'train_location': '',
'stationTrainDTO.from_station_telecode': from_station,
'stationTrainDTO.to_station_telecode': to_station,
'stationTrainDTO.start_time': '',
'stationTrainDTO.end_time': '',
'stationTrainDTO.over_time': '',
'stationTrainDTO.train_no': train_no,
'stationTrainDTO.from_station_name': '',
'stationTrainDTO.to_station_name': '',
'passengerTicketStr': '',
'oldPassengerStr': '',
'randCode': '',
'purpose_codes': '00',
'key_check_isChange': ''
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://kyfw.12306.cn/otn/leftTicket/init'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
resp = session.post(url, data=data, params=params)
if resp.json()['status']:
url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
data = {
'_json_att': ''
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://kyfw.12306.cn/otn/leftTicket/init'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
session.post(url, data=data)
url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'
data = {
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': resp.json()['data']['submitToken']
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
resp = session.post(url, data=data)
passenger_info = resp.json()['data']['normal_passengers']
passenger_str_list = []
for passenger in passenger_info:
if passenger['passenger_name'] in passengers:
passenger_str_list.append('{},{},{},{},{},{},{},N'.format(passenger['passenger_name'], passenger['passenger_id_type_code'], passenger['passenger_id_no'], passenger['mobile_no'], '1', '0', passenger['passenger_name']))
url = 'https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo'
data = {
'cancel_flag': '2',
'bed_level_order_num': '000000000000000000000000000000',
'passengerTicketStr': '_'.join(passenger_str_list),
'oldPassengerStr': '_'.join(passenger_str_list),
'tour_flag': 'dc',
'randCode': '',
'whatsSelect': '1',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': resp.json()['data']['submitToken']
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
resp = session.post(url, data=data)
if resp.json()['status']:
url = 'https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount'
data = {
'train_date': time.strftime('%a %b %d %Y', time.strptime(date, '%Y-%m-%d')) + ' 00:00:00 GMT+0800 (中国标准时间)',
'train_no': train_no,
'stationTrainDTO.from_station_telecode': from_station,
'stationTrainDTO.to_station_telecode': to_station,
'seatType': seat_type,
'leftTicket': '',
'purpose_codes': '00',
'train_location': '',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': resp.json()['data']['submitToken']
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
resp = session.post(url, data=data)
if resp.json()['status']:
url = 'https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue'
data = {
'passengerTicketStr': '_'.join(passenger_str_list),
'oldPassengerStr': '_'.join(passenger_str_list),
'randCode': '',
'purpose_codes': '00',
'key_check_isChange': '',
'leftTicketStr': '',
'train_location': '',
'choose_seats': '',
'seatDetailType': '000',
'whatsSelect': '1',
'roomType': '00',
'dwAll': 'N',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': resp.json()['data']['submitToken']
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
resp = session.post(url, data=data)
if resp.json()['status']:
url = 'https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime'
data = {
'random': str(int(time.time())),
'tourFlag': 'dc',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': resp.json()['data']['submitToken']
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
}
session = requests.Session()
session.headers.update(headers)
session.cookies = login()
while True:
resp = session.post(url, data=data)
if resp.json()['data']['waitTime'] == -1:
print('订票成功!')
return
time.sleep(1)
# 抢票
def snatch_ticket(date, from_station, to_station, seat_type, passengers):
ticket_info = None
while not ticket_info:
print('正在尝试获取车票信息...')
ticket_info = get_ticket_info(date, from_station, to_station, seat_type)
time.sleep(1)
print('车票信息:', ticket_info)
submit_order(date, ticket_info[0], ticket_info[1], ticket_info[2], seat_type, passengers)
if __name__ == '__main__':
snatch_ticket('2022-01-01', 'BJP', 'SHH', 'O', ['张三', '李四']) # 示例:抢购 2022 年 1 月 1 日从北京到上海的 O 字头座位,乘客姓名为张三和李四
需要注意的是,这段代码仅供学习和参考使用,不应用于实际抢购车票中,因为 12306 网站严禁使用爬虫程序进行抢票。
原文地址: https://www.cveoy.top/t/topic/o0d3 著作权归作者所有。请勿转载和采集!