自动化抢票 12306

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

自动化抢票 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"]')
    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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/874860.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

learn C++ NO.13——list

前言 本文将从list的使用,再到根据sgi库对于list实现作为参考模拟实现一下list。通过模拟实现来增加对它的理解。 介绍list list是一个由带头双向循环链表实现的STL容器,它提供常规时间内对数据进行插入和删除操作。 list在内存中存储不连续的空间存储…

【HarmonyOS NEXT】实现网络图片保存到手机相册

【问题描述】 给定一个网络图片的地址,实现将图片保存到手机相册 【API】 phAccessHelper.showAssetsCreationDialog【官方文档】 https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-photoaccesshelper-V5#showassetscreationdialog…

ISO27001信息安全管理体系认证怎么做?

ISO27001认证是关于信息安全管理体系认证,ISO27001将有效保证企业在信息安全领域的可靠性,降低企业泄密风险,更好的保存核心数据。下面给大家详细讲讲ISO27001信息安全管理体系认证详细办理流程。 一、ISO27001信息安全管理体系认证的办理条…

【Centos】Centos系统换yum源

【Centos】Linux,Centos系统换yum源 1、备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak/etc/yum.repos.d/CentOS-Base.repo 是yum的配置文件 /etc/yum.repos.d/CentOS-Base.repo.bak 是我们备份的配置文件 2、下载yum源 这里…

【EI稳定,马来亚大学主办】2024年计算机与信息安全国际会议(WCCIS 2024,9月27-29)

2024年计算机与信息安全国际会议 (WCCIS 2024) 将于2024年9月27-29日召开。 会议旨在为从事计算机与信息安全的专家学者、工程技术人员、技术研发人员提供一个共享科研成果和前沿技术,了解学术发展趋势,拓宽研究思路,加强学术研究和探讨&…

【编译原理】编译器概述、编译器结构、编译器实例

编译器概述、编译器结构、编译器实例 编译器概述 1.编译器是一个程序 核心功能是把源代码翻译成目标代码 比如源代码:C/C,Java,C#,html 目标代码:X86,IA64,ARM,… 把一种源程序翻译成另外一种源程序&…

/bin/bash的作用

1、为啥使用不了很多命令? 我刚进入一个新系统: 我当时蒙蔽了,这是啥意思,为啥没命令? 原因是:当时进入的shell并没有初始化这些路径环境,所以正确的方法是: 2、/bin/bash运行的过程中执行…

Mac清理其他文件:释放存储空间的高效指南

每个Mac用户都可能遇到存储空间不足的问题,尤其是当“其他”文件积累到一定体积时。在Mac上,“其他”文件通常包括各种系统文件、缓存、文档以及不被归类为应用程序、照片、电影或音乐的其他类型的文件。这些文件往往不易被注意,但逐渐占用了…

C语言代码练习(第十八天)

今日练习: 48、猴子吃桃问题。猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时&…

TMGM:欧元区储蓄率处于结构性增高

法国的家庭储蓄率进一步上升,从2024年第一季度的家庭总可支配收入(GDI)的17.6%上升到2024年第二季度的17.9%,这信息来自于法国国家统计和经济研究所(INSEE)。这也是欧元区正在进行的上升趋势的早期迹象。虽然第二季度数字还没出来…

【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现

C语法相关知识点可以通过点击以下链接进行学习一起加油!命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现 本文将详细介绍如何使用容器适…

探索最佳 Shell 工具:全面测评 Bash、Zsh、Fish、Tcsh 和 Ksh

感谢浪浪云支持发布 浪浪云活动链接 :https://langlangy.cn/?i8afa52 文章目录 1. 简介2. 测评工具3. 测评标准4. Bash 测评4.1 易用性4.2 功能特性4.3 性能4.4 可定制性4.5 社区和支持 5. Zsh 测评5.1 易用性5.2 功能特性5.3 性能5.4 可定制性5.5 社区和支持 6. F…

3款数据恢复免费版软件评测:帮你轻松解决数据丢失问题

如今数字化时代,数据至关重要,珍贵照片、重要文档、成长记录的视频音频,承载回忆与努力。但数据丢失风险常伴,误删、格式化、病毒攻击等意外频发,令人陷入绝望,如坠数据黑洞。所幸科技发展,数据…

精益生产现场管理和改善的“蜕变”之旅:从理念到落地的全方位指南

精益生产现场管理和改善,正逐步成为众多企业转型升级的必经之路。今天,就让我们(深圳天行健企业管理咨询公司)带大家一起踏上这场从理念到落地的“蜕变”之旅,探索精益生产现场管理与改善的方方面面,为企业…

API安全 | 发现API的5个小tips

在安全测试目标时,最有趣的测试部分是它的 API。API 是动态的,它们比应用程序的其他部分更新得更频繁,并且负责许多后端繁重的工作。在现代应用程序中,我们通常会看到 REST API,但也会看到其他形式,例如 Gr…

游戏论坛网站|基于Springboot+vue的游戏论坛网站系统游戏分享网站(源码+数据库+文档)

游戏论坛|游戏论坛系统|游戏分享网站 目录 基于Springbootvue的游戏论坛网站系统游戏分享网站 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大…

JAVA同城服务系统大集结活动报名通道已开启构建你的同城圈子系统小程序源码

同城服务系统大集结,活动报名通道已开启! 🎉 【开篇号角】同城服务大狂欢,集结号已吹响! 嘿,小伙伴们!你们期待已久的同城服务系统大集结活动终于来啦!🎊 是的&#xff…

kubernetes微服务基础及类型

目录 1 什么是微服务 2 微服务的类型 3 ipvs模式 ipvs模式配置方式 4 微服务类型详解 4.1 ClusterIP 4.2 ClusterIP中的特殊模式headless 4.3 nodeport 4.4 metalLB配合loadbalance实现发布IP 1 什么是微服务 用控制器来完成集群的工作负载,那么应用如何暴漏出去&…

【卷起来】VUE3.0教程-08-路由管理

在Vue中,我们可以通过vue-router路由管理页面之间的关系。 Vue Router是Vue.js的官方路由,它与Vue.js核心深度集成,让用Vue.js构建单页应用变得轻而易举。 🌲 在Vue中引入路由 安装路由 npm install --save vue-router 建立三个…

详聊LLaMa技术细节:LLaMA大模型是如何炼成的?

本文介绍来自 Meta AI 的 LLaMa 模型,类似于 OPT,也是一种完全开源的大语言模型。LLaMa 的参数量级从 7B 到 65B 大小不等,是在数万亿个 token 上面训练得到。值得一提的是,LLaMa 虽然只使用公共的数据集,依然取得了强…