春节到了 教你使用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中随机选择一行,可以使用Pandas的sample()函数。sample()默认按照随机方式返回指定数量的行,也可以指定要返回的行数或百分比。 以下是从DataFrame中随机选择一行的代码示例: import pandas as pd # 创建DataFrame data = {‘姓名’: [‘小明’, ‘小红’, ‘小…

    python-answer 2023年3月27日
    00
  • 将Pandas数据框架导出到Excel文件中

    导出Pandas数据框架到Excel文件通常是分析数据的重要一步。下面是完整的攻略: 安装必要的库 在导出数据到Excel之前,需要先安装必要的库,推荐使用pandas和openpyxl: pip install pandas openpyxl 如果因为网络问题安装失败,可以考虑换用镜像源,例如: pip install -i https://pypi.tu…

    python-answer 2023年3月27日
    00
  • 如何扩展Pandas DataFrame的列

    首先,将术语解释一下,因为Pandas里的数据是以DataFrame对象的形式存储的,DataFrame可以理解为一个二维表格,行对应数据的条目,列对应数据的属性。从这个角度来看,在Pandas中我们所说的“扩展DataFrame的列”,指的是添加新的列(也就是属性)到DataFrame对象中。 下面是一个添加新列到DataFrame中的完整攻略(注:以下所…

    python-answer 2023年3月27日
    00
  • 如何将Pandas数据框架追加到现有的CSV文件?

    将Pandas数据框追加到现有的CSV文件,其实就是将数据框的行添加到CSV文件的末尾。 以下是如何实现这一操作的完整攻略: 读取现有CSV文件 使用Pandas的read_csv函数读取现有CSV文件,并将其存储在一个数据框中。 创建要追加的数据框 创建要添加到CSV文件中的数据框,确保其具有与现有CSV文件相同的列名称和数据类型。 使用Pandas的to…

    python-answer 2023年3月27日
    00
  • Python – 通过列名对数据框架进行子集

    Python-通过列名对数据框架进行子集的完整攻略 在Python中,通过列名对数据框架进行子集是非常常见的操作,可以通过下面的方法来实现: 步骤1:导入pandas库 在Python中,pandas库是数据处理的非常重要的工具,需要先导入pandas库。 import pandas as pd 步骤2:读取数据 在进行数据处理前,需要先读取数据。这里以读取…

    python-answer 2023年3月27日
    00
  • python机器学习Sklearn实战adaboost算法示例详解

    Python机器学习Sklearn实战Adaboost算法示例详解 Adaboost是一种提升树算法,它能将多个弱分类器组成强分类器,通常被用于二分类和多类分类问题中。本文将对Adaboost算法的原理、实现和优化进行详细的讲解,并提供两个示例说明。 Adaboost算法原理 Adaboost算法利用多个弱分类器组合出一个强分类器,主要步骤如下: 初始化每个…

    python 2023年6月13日
    00
  • pandas 实现 in 和 not in 的用法及使用心得

    下面是“pandas 实现 in 和 not in 的用法及使用心得”的完整攻略: 1. in 和 not in 的基本语法 在 Pandas 中,我们可以使用“in”和“not in”来判断某个元素是否在一个 Series 或 DataFrame 中。具体的基本语法如下: # Series 中判断元素是否在其中 element in my_series e…

    python 2023年5月14日
    00
  • pandas 转换成行列表进行读取与Nan处理的方法

    下面是详细讲解“pandas转换成行列表进行读取与Nan处理的方法”的完整攻略。 1. 转换成行列表 将pandas数据框转换为行列表,可以使用.values.tolist()方法。这样做的好处是可以将数据框中的数据按行打印出来,更加直观地了解数据的结构和内容。 例如,假设有以下的数据框: import pandas as pd # 创建数据框 df = p…

    python 2023年5月14日
    00
合作推广
合作推广
分享本页
返回顶部