自动化抢票 12306

0zxm 2024-09-09 12:07:09 阅读 69

注意!!!代码仅供学习和参考,不要用做非法用途!!!

自动化抢票 12306

1. 明确需求

明确采集的网站以及数据内容

网址: https://kyfw.12306.cn/otn/leftTicket/init数据: 车次相关信息

2. 抓包分析

通过浏览器开发者工具分析对应的数据位置

打开开发者工具

F12 或鼠标右键点击检查 刷新网页

点击下一页/下滑网页页面/点击搜索/查询按钮让网页相关数据内容加载出来 (整个网站数据内容重新加载一遍) 通过关键字搜索找到对应数据位置

需要什么数据就搜什么

数据包地址: https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2024-09-06&leftTicketDTO.from_station=IZQ&leftTicketDTO.to_station=SNQ&purpose_codes=ADULT

3. 代码实现步骤
1. 发送请求

模拟浏览器对于 url 地址发送请求

模拟浏览器

可以直接复制,使用请求标头中参数内容去哪里找: 开发者工具 -> 网络 -> 点击对应数据包 -> 标头 -> 请求标头(参数)怎么写: 使用字典接受数据内容 (构建完整的键值对)

请求网址

通过抓包分析找到链接地址,直接复制即可

发送请求

使用第三方模块: requests

安装 requests 模块

win+r 输入 cmd 点击确定,输入安装命令: pip install requests 导入 requests 模块请求方法: 开发者工具 -> 网络 -> 点击对应数据包 -> 标头 -> 常规GET 请求参数: 查询参数 (直接在链接中就有)

2. 获取数据

获取服务器返回响应数据

12306 的请求参数并不是简单的中文字符,而是对应的三字编码,我们需要找到对应的编码

对网页分析发现,在一个 js 文件中可以获取在页面最后有 https://kyfw.12306.cn/otn/resources/js/framework/station_name.js 链接

3. 解析数据

提取我们需要的数据内容: 车次相关内容

4. 保存数据

字典取值

键值对取值: 根据冒号左边的内容 [“键”, 提取冒号右边的内容 [“值”]]

当然,下面我将重点介绍每个步骤的关键点,并附上相应的代码片段。

1. 获取站点编码

关键点:从 12306 的 JS 文件中解析站点的三字码。

代码片段:

def get_station_codes():

code_url = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js"

response = requests.get(code_url)

code_data = response.text[20:-2] # 优化:去除尾部的双引号和换行符

list_code = code_data.split("|")

station_codes = dict(zip(list_code[1::5], list_code[2::5])) # 优化:直接跳过索引获取站点名称和代码

return station_codes

2. 用户输入

关键点:提示用户输入起始站、终点站和出发日期,然后转换为 12306 需要的编码。

代码片段:

def get_user_input(code_dic):

from_station = input("输入起始站:\n")

to_station = input("输入终点站:\n")

time = input("输入时间,例如:2024-09-18:\n")

return code_dic.get(from_station, ""), code_dic.get(to_station, ""), time

3. 获取火车票信息

关键点:构建请求 URL,模拟浏览器发送 HTTP 请求获取数据。

代码片段:

def get_train_info(from_station, to_station, time):

train_url = f"https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={ time}&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.36"

}

response = requests.get(url=train_url, headers=headers)

return response.json()

4. 打印火车票信息

关键点:解析服务器返回的 JSON 数据,并使用PrettyTable格式化输出。

代码片段:

def print_train_info(json_data):

table = PrettyTable()

table.field_names = ['车次', '出发时间', '到达时间', '历时', '一等座', '二等座', '特等座']

if json_data['httpstatus'] == 200:

result = json_data['data']['result']

for item in result:

details = item.split('|')

table.add_row([details[3], details[8], details[9], details[10], details[30], details[31], details[32]])

print(table)

else:

print(f"获取响应数据失败,状态码为{ json_data['httpstatus']}")

5. Selenium 自动化

关键点:使用 Selenium 模拟用户在网页上的操作,如填写表单、点击按钮等。

代码片段:

def main():

# 获取站点编码

code_dic = get_station_codes()

# 获取用户输入

from_station_code, to_station_code, time = get_user_input(code_dic)

# 使用Selenium打开网页

browser = webdriver.Edge()

browser.get('https://kyfw.12306.cn/otn/leftTicket/init')

# 填写查询表单

start_station = browser.find_element(By.CSS_SELECTOR, '#fromStationText')

start_station.send_keys("广州南")

start_station.send_keys(Keys.ENTER)

end_station = browser.find_element(By.CSS_SELECTOR, '#toStationText')

end_station.send_keys("韶关")

end_station.send_keys(Keys.ENTER)

date = browser.find_element(By.CSS_SELECTOR, '#train_date')

date.send_keys("2024-09-18")

date.send_keys(Keys.ENTER)

# 点击查询

browser.find_element(By.CSS_SELECTOR, '#query_ticket').click()

# 等待查询结果

t.sleep(5) # 优化:使用更明确的等待条件

# 处理查询结果

# 省略:根据实际情况处理查询结果

# 关闭浏览器

browser.quit()

6. 完整代码

# coding=gbk

import time as t

import requests

from selenium import webdriver

from selenium.webdriver.common.by import By

from selenium.webdriver.common.keys import Keys

from prettytable import PrettyTable

import re

# 获取站点对应的三字码

def get_station_codes():

code_url = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js"

response = requests.get(code_url)

code_data = response.text[20:-2] # 优化:去除尾部的双引号和换行符

list_code = code_data.split("|")

station_codes = dict(zip(list_code[1::5], list_code[2::5])) # 优化:直接跳过索引获取站点名称和代码

return station_codes

# 用户输入起始站、终点站和时间,转化为编码

def get_user_input(code_dic):

from_station = input("输入起始站:\n")

to_station = input("输入终点站:\n")

time = input("输入时间,例如:2024-09-18:\n")

return code_dic.get(from_station, ""), code_dic.get(to_station, ""), time

# 获取火车票信息

def get_train_info(from_station, to_station, time):

train_url = f"https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={ time}&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.36"

}

response = requests.get(url=train_url, headers=headers)

return response.json()

# 打印火车票信息

def print_train_info(json_data):

table = PrettyTable()

table.field_names = ['车次', '出发时间', '到达时间', '历时', '一等座', '二等座', '特等座']

if json_data['httpstatus'] == 200:

result = json_data['data']['result']

for item in result:

details = item.split('|')

table.add_row([details[3], details[8], details[9], details[10], details[30], details[31], details[32]])

print(table)

else:

print(f"获取响应数据失败,状态码为{ json_data['httpstatus']}")

# 主函数

def main():

# 获取站点编码

code_dic = get_station_codes()

# 获取用户输入

from_station, to_station, time = get_user_input(code_dic)

# 获取火车票信息

json_data = get_train_info(from_station, to_station, time)

# 打印火车票信息

print_train_info(json_data)

# 使用Selenium打开网页

browser = webdriver.Edge()

browser.get('https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc')

# 填写查询表单

start_station = browser.find_element(By.CSS_SELECTOR, '#fromStationText')

start_station.clear()

start_station.send_keys("广州南")

start_station.send_keys(Keys.ENTER)

end_station = browser.find_element(By.CSS_SELECTOR, '#toStationText')

end_station.clear()

end_station.send_keys("韶关")

end_station.send_keys(Keys.ENTER)

date = browser.find_element(By.CSS_SELECTOR, '#train_date')

date.clear()

date.send_keys("2024-09-18")

date.send_keys(Keys.ENTER)

# 点击查询

browser.find_element(By.CSS_SELECTOR, '#query_ticket').click()

# 等待查询结果

t.sleep(5) # 优化:使用更明确的等待条件

# 处理查询结果

elements = browser.find_elements(By.CSS_SELECTOR, '#queryLeftTable tr:nth-child(7) .btn72')

if elements:

elements[0].click()

# 扫码登陆

saoma = browser.find_element(By.CSS_SELECTOR, '#login > div.login-box > ul > li.login-hd-account > a')

saoma.click()

t.sleep(5) # 优化:使用更明确的等待条件

# 登录操作

J_userName = browser.find_element(By.CSS_SELECTOR, '#J-userName')

J_userName.clear()

J_userName.send_keys("aaa")

J_password = browser.find_element(By.CSS_SELECTOR, '#J-password')

J_password.clear()

J_password.send_keys("password")

J_loginmodalBtn = browser.find_element(By.CSS_SELECTOR, '#J-login')

J_loginmodalBtn.click()

# 点击预订

browser.find_element(By.CSS_SELECTOR, '#normalPassenger_0').click()

t.sleep(1)

browser.find_element(By.CSS_SELECTOR, '#dialog_xsertcj_cancel').click()

# 修改成人票

ticket_type_select = browser.find_element(By.CSS_SELECTOR, '#ticketType_1')

ticket_type_select.click()

# 选择成人票

adult_ticket_option = browser.find_element(By.CSS_SELECTOR, '#ticketType_1 > option[value="1"]')code>

adult_ticket_option.click()

t.sleep(1)

browser.find_element(By.CSS_SELECTOR, '#submitOrder_id').click()

qr_submit_id = browser.find_element(By.CSS_SELECTOR, '#qr_submit_id')

if qr_submit_id:

qr_submit_id.click()

input("输入任意字符后回车继续...")

# 关闭浏览器

browser.quit()

if __name__ == "__main__":

main()



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。