春节到了 教你使用python来抢票回家

以下是”春节到了教你使用python来抢票回家“的完整攻略:

1. 前置条件

在使用 Python 进行自动购票之前,你需要满足以下条件:

  • 一台能够访问网络的计算机。
  • 已经安装 Python,并了解 Python 的基础语法和操作。
  • 了解如何解析 HTML 和发送网络请求。
  • 已经获取了想要购买的车票的 url、出发站和目的站代码,以及出发时间、车次等信息。

2. 需要掌握的Python库

  • requests: 用于发送网络请求,获取响应内容。
  • BeautifulSoup: 用于解析 HTML 文件,提取所需要的信息。
  • execjs: 用于执行 Javascript 代码。
  • time: 用于进行时间控制。

可以在命令行中使用以下命令进行安装:

pip install requests BeautifulSoup4 PyExecJS

3. 代码实现

以下是一份简单的 Python 代码来模拟登录并购买车票的过程。

3.1 模拟登录


import requests
from bs4 import BeautifulSoup
import execjs

# 示例参数,请替换为自己的值
username = 'your_username'
password = 'your_password'
login_url = 'https://kyfw.12306.cn/passport/web/login'

# 获取cookie
session = requests.session()
res = session.get(login_url)
cookie = requests.utils.dict_from_cookiejar(session.cookies)

# 解析html,获取一些必要的参数lt、execution,以及密码加密用的公钥
soup = BeautifulSoup(res.text, 'html.parser')
lt = soup.find('input', {'name': 'lt'})['value']
exec_code = soup.find('script', {'minfraud-honeypot': 'javascript'})['src']
res2 = session.get(exec_code)
pub_key = execjs.compile(res2.text).call("getKey")
en_password = execjs.compile(res2.text).call("getPwd", pub_key, password)

# 发送post请求,模拟登录
data = {
    'username': username,
    'password': en_password,
    'lt': lt,
    'execution': 'e1s1',
    '_eventID': 'submit',
    'submit': '',
}
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.36',
    'Referer': 'https://kyfw.12306.cn/otn/resources/login.html'
}
response = session.post(login_url, data=data, headers=headers)

3.2 查询车票信息


# 示例参数,请替换为自己的值
from_station = 'BJP'
to_station = 'SHH'
start_time = '2019-01-01'

query_url = "https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=" + start_time + "&leftTicketDTO.from_station=" + from_station + "&leftTicketDTO.to_station=" + to_station + "&purpose_codes=ADULT"

# 发送查询请求,获取可购买车票信息
query_res = session.get(query_url)

# 解析json,获取所有车次的信息
trains = query_res.json()['data']['result']

3.3 执行购票操作


# 示例参数,请替换为自己的值
train_num = 'G1'
seat_type = '二等座'

# 构造购票url及请求体
buy_url = ("https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest?"
           "secretStr={0}&train_date={1}&"
           "back_train_date={2}&tour_flag=dc&"
           "purpose_codes=ADULT&query_from_station_name={3}&"
           "query_to_station_name={4}&undefined=").format(secret_str, start_time, start_time, from_station_name, to_station_name)

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.36',
    'Referer': 'https://kyfw.12306.cn/otn/leftTicket/init'
}
data = {
  'secretStr': secret_str,
  'train_date': start_time,
  'back_train_date': start_time,
  'tour_flag': 'dc',
  'purpose_codes': 'ADULT',
  'query_from_station_name': from_station_name,
  'query_to_station_name': to_station_name,
  'undefined': ''
}

# 发送post请求,进入购票页面
response = session.post(buy_url, headers=headers, data=data)

# 检查购票页面是否正确返回
if response.status_code != 200:
    print("进入购票页面失败!")
    exit()

# 获取购票页面的submit_token
soup = BeautifulSoup(response.text, 'html.parser')
submit_token = soup.select_one('input[name="globalRepeatSubmitToken"]')['value']

# 构造订单确认url及请求体
order_confirm_url = "https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest"

params = {
    'tour_flag': 'dc',
    'is_org_price': 'N',
    'round_train_date': start_time,
    'train_date': start_time,
    'back_train_date': start_time,
    'from_station_name': from_station_name,
    'to_station_name': to_station_name,
    'purpose_codes': 'ADULT',
    'train_location': secret_str.split('#')[1],
    '_json_att': '',
    'REPEAT_SUBMIT_TOKEN': submit_token
}

data = {
    'passengerTicketStr': '{0},0,1,{1},N'.format(seat_type_code, passenger_seed),
    'oldPassengerStr': '{0},{1},1_'.format(passenger_name, id_num),
    'randCode': '',
    'whatsSelect': '1',
    '_json_att': '',
    'REPEAT_SUBMIT_TOKEN': submit_token
}

# 发送post请求,进行订单确认
response = session.post(order_confirm_url, headers=headers, params=params, data=data)

# 检查订单确认页面是否正确返回
if response.status_code != 200:
    print("订单确认失败!")
    exit()

4. 示例说明

以下是一些有关代码实现的示例说明:

4.1 爬取车票信息

代码中需要构造查询url,并根据返回结果解析车票信息。示例中查询了车次从"BJP"(北京站)到"SHH"(上海站)的所有列车,并输出了经过这两个站点的车次号和出发、到达时间:


from_station = 'BJP'
to_station = 'SHH'
start_time = '2019-01-01'

query_url = "https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=" + start_time + "&leftTicketDTO.from_station=" + from_station + "&leftTicketDTO.to_station=" + to_station + "&purpose_codes=ADULT"

# 发送查询请求,获取可购买车票信息
query_res = session.get(query_url)

# 解析json,获取所有车次的信息
trains = query_res.json()['data']['result']

# 输出所有经过这两个站点的车次号和出发、到达时间
for train in trains:
    data_list = train.split('|')
    train_num = data_list[3]
    start_time = data_list[8]
    arrive_time = data_list[9]
    if '北京' in data_list[6] and '上海' in data_list[7]:
        print('{0}: {1} -> {2}'.format(train_num, start_time, arrive_time))

4.2 购票操作

代码中需要构造购票url和订单确认url,并根据返回结果检查流程是否正确进行,最后成功提交购票订单。示例中为购买G1列车的二等座车票:


# 示例参数,请替换为自己的值
train_num = 'G1'
seat_type = '二等座'

# 构造购票url及请求体
buy_url = ("https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest?"
           "secretStr={0}&train_date={1}&"
           "back_train_date={2}&tour_flag=dc&"
           "purpose_codes=ADULT&query_from_station_name={3}&"
           "query_to_station_name={4}&undefined=").format(secret_str, start_time, start_time, from_station_name, to_station_name)

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.36',
    'Referer': 'https://kyfw.12306.cn/otn/leftTicket/init'
}
data = {
  'secretStr': secret_str,
  'train_date': start_time,
  'back_train_date': start_time,
  'tour_flag': 'dc',
  'purpose_codes': 'ADULT',
  'query_from_station_name': from_station_name,
  'query_to_station_name': to_station_name,
  'undefined': ''
}

# 发送post请求,进入购票页面
response = session.post(buy_url, headers=headers, data=data)

# 检查购票页面是否正确返回
if response.status_code != 200:
    print("进入购票页面失败!")
    exit()

# 获取购票页面的submit_token
soup = BeautifulSoup(response.text, 'html.parser')
submit_token = soup.select_one('input[name="globalRepeatSubmitToken"]')['value']

# 构造订单确认url及请求体
order_confirm_url = "https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest"

params = {
    'tour_flag': 'dc',
    'is_org_price': 'N',
    'round_train_date': start_time,
    'train_date': start_time,
    'back_train_date': start_time,
    'from_station_name': from_station_name,
    'to_station_name': to_station_name,
    'purpose_codes': 'ADULT',
    'train_location': secret_str.split('#')[1],
    '_json_att': '',
    'REPEAT_SUBMIT_TOKEN': submit_token
}

data = {
    'passengerTicketStr': '{0},0,1,{1},N'.format(seat_type_code, passenger_seed),
    'oldPassengerStr': '{0},{1},1_'.format(passenger_name, id_num),
    'randCode': '',
    'whatsSelect': '1',
    '_json_att': '',
    'REPEAT_SUBMIT_TOKEN': submit_token
}

# 发送post请求,进行订单确认
response = session.post(order_confirm_url, headers=headers, params=params, data=data)

# 检查订单确认页面是否正确返回
if response.status_code != 200:
    print("订单确认失败!")
    exit()

# 获取订单排队等待时间
json_res = response.json()
wait_time = json_res['data']['waitTime']
if 'orderId' not in json_res['data']:
    print("购票失败!原因:{0}".format(json_res['data']['errMsg']))
    exit()

# 构造提交订单url及请求体
submit_order_url = "https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue"
data = {
    'passengerTicketStr': '{0},0,1,{1},N'.format(seat_type_code, passenger_seed),
    'oldPassengerStr': '{0},{1},1_'.format(passenger_name, id_num),
    'randCode': '',
    'purpose_codes': '00',
    'key_check_isChange': json_res['data']['checkCodeKey'],
    'leftTicketStr': json_res['data']['leftTicketStr'],
    'train_location': json_res['data']['train_location'],
    'choose_seats': '',
    'seatDetailType': '000',
    'whatsSelect': '1',
    'roomType': '00',
    'dwAll': 'N',
    '_json_att': '',
    'REPEAT_SUBMIT_TOKEN': submit_token
}

# 进行购票
while True:
    response = session.post(submit_order_url, headers=headers, data=data)

    # 检查购票提交返回值
    if response.status_code != 200:
        print("提交订单失败!")
        continue

    # 获取提交订单json
    json_res = response.json()

    if 'data' in json_res and json_res['data']['submitStatus']:
        print("购票成功!")
        break
    else:
        print("购票失败!{0}".format(json_res['messages'][0]))

以上是示例代码实现,实践中还需要了解如何模拟验证码、如何队列表单优化等更多问题。因此在使用 python 刷票时也需要根据需求逐步完善代码,针对不同的问题采用不同的方式进行解决。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:春节到了 教你使用python来抢票回家 - Python技术站

(0)
上一篇 2023年5月14日
下一篇 2023年5月14日

相关文章

  • 浅析pandas 数据结构中的DataFrame

    以下是浅析 Pandas 数据结构中的 DataFrame 的完整攻略。 什么是DataFrame DataFrame 是 Pandas 库中最常用的数据结构之一,类似于 Excel 中的数据表格。DataFrame 可以看作是由多个 Series 组成的,每个 Series 代表着一列数据,而 DataFrame 中的每行数据则对应着多个 Series 中…

    python 2023年5月14日
    00
  • Python Pandas – 检查两个共享封闭端点的Interval对象是否重叠

    Python Pandas是一个强大的数据分析库,它提供了丰富的数据处理和分析工具,其中包括对interval对象的支持。在Pandas中,可以使用interval_range()函数来创建interval对象,可以使用overlaps()方法来检查interval对象是否重叠。 要检查两个共享封闭端点的interval对象是否重叠,可以使用overlaps…

    python-answer 2023年3月27日
    00
  • 如何获取Pandas数据框架的第一列

    获取Pandas数据框架的第一列可以使用iloc方法,即通过索引值获取指定行列的数据。具体步骤如下: 读取数据 python import pandas as pd df = pd.read_csv(‘example.csv’) 获取第一列数据 python first_col = df.iloc[:,0] 通过 iloc[:,0] 可以获取所有行的第一列数…

    python-answer 2023年3月27日
    00
  • pandas 小数位数 精度的处理方法

    下面是关于“pandas小数位数精度的处理方法”的完整攻略。 1. pandas浮点数默认情况下的小数位数 在pandas中,浮点数默认情况下是会自动四舍五入到六位小数。比如下面的代码: import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(3, 3) * 1000)…

    python 2023年5月14日
    00
  • Python Pandas中某一列的累积百分比

    确实,Python的Pandas可以很容易地计算某一列的累积百分比。具体流程分以下几步: 载入数据到 Pandas DataFrame 累积数值处理 计算累积百分比 接下来,我们将针对这些步骤进行详细说明,包括实例说明。 1. 载入数据到 Pandas DataFrame 在载入数据到 Pandas 的 DataFrame 中时,必须先创建 DataFram…

    python-answer 2023年3月27日
    00
  • Python Pandas读取csv/tsv文件(read_csv,read_table)的区别

    当使用Python Pandas库读取文本文件时,可以使用read_csv()和read_table()两种函数。它们的区别在于默认使用的分隔符不同。 read_csv()函数默认使用逗号作为分隔符,可以读取以.csv格式保存的文件。而read_table()函数默认使用制表符作为分隔符,可以读取以.tsv格式保存的文件。 另外,这两个函数还可以通过参数进行…

    python 2023年5月14日
    00
  • 从列表或字典创建Pandas的DataFrame对象的方法

    从列表或字典创建Pandas的DataFrame对象是一种快捷且常见的方式,下面是具体步骤: 1. 导入所需库 import pandas as pd 2. 从列表创建DataFrame 列表中的每个元素将代表DataFrame中的一行数据,使用pandas.DataFrame()函数从列表创建DataFrame对象。 示例1: data = [ [1, ‘…

    python 2023年5月14日
    00
  • 合并两个具有相同列名的数据框架

    如果要合并两个具有相同列名的数据框架,可以使用R语言中的merge()函数。下面将给出详细的完整攻略。 步骤1:准备数据框架 首先需要准备两个数据框架,它们应该有相同的列名,数量可以不同,但是列名应该至少有一个是相同的。这里给出两个示例数据框架: df1 <- data.frame( name = c("Alice", "…

    python-answer 2023年3月27日
    00
合作推广
合作推广
分享本页
返回顶部