当前位置: 首页 > news >正文

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

相关文章:

自动化抢票 12306

自动化抢票 12306 1. 明确需求 明确采集的网站以及数据内容 网址: https://kyfw.12306.cn/otn/leftTicket/init数据: 车次相关信息 2. 抓包分析 通过浏览器开发者工具分析对应的数据位置 打开开发者工具 F12 或鼠标右键点击检查 刷新网页 点击下一页/下滑网页页面/点击搜…...

海外云服务器安装 MariaDB10.6.X (Ubuntu 18.04 记录篇二)

本文首发于 秋码记录 MariaDB 的由来(历史) 谈起新秀MariaDB,或许很多人都会感到陌生吧,但若聊起享誉开源界、业界知名的关系型数据库——Mysql,想必混迹于互联网的人们(coder)无不知晓。 其…...

Mybatis_基础

文章目录 第一章 Mybatis简介1.1 Mybatis特性1.2 和其它持久化层技术对比 第二章 Mybatis的增删改查第三章 Mybatis的增删改查 第一章 Mybatis简介 1.1 Mybatis特性 MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和…...

8Manage采购申请管理:轻松实现手动采购流程自动化

您是否感受到通过手动采购申请流程管理成本的压力? 信息的不充分常常导致现金流的不透明,这已成为财务高管们的常见痛点。本文将展示采购申请管理软件如何帮助您减轻负担,使您能够简化流程。 没有采购申请软件会面临哪些挑战? …...

PADS Router 入门基础教程(一)

有将近三周没有更新过博客了,最近在整理PADS Router 入门基础教程,希望喜欢本系列教程的小伙伴可以点点关注和订阅!下面我们开始进入PADS Router课程的介绍。 一、PADS Router 快捷键 ​ 二、课程介绍 本教程主要介绍:PADS Rou…...

一台手机一个ip地址吗?手机ip地址泄露了怎么办

在数字化时代,‌手机作为我们日常生活中不可或缺的一部分,‌其网络安全性也日益受到关注。‌其中一个常见的疑问便是:‌“一台手机是否对应一个固定的IP地址?‌”实际上,‌情况并非如此简单。‌本文首先解答这一问题&a…...

【扇贝编程】使用Selenium模拟浏览器获取动态内容笔记

文章目录 selenium安装 selenium下载浏览器驱动 获取数据处理数据查找一个元素查找所有符合条件的元素 控制浏览器 selenium selenium是爬虫的好帮手, 可以控制你的浏览器,模仿人浏览网页,从而获取数据,自动操作等。 我们只要让…...

TCP Analysis Flags 之 TCP Port numbers reused

前言 默认情况下,Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态,并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时,会对每个 TCP 数据包进行一次分析,数据包按照它们在数据包列表中出现的顺序进行处理。可…...

【Python机器学习】核心数、进程、线程、超线程、L1、L2、L3级缓存

如何知道自己电脑的CPU是几核的,打开任务管理器(同时按下:Esc键、SHIFT键、CTRL键) 然后,点击任务管理器左上角的性能选项,观察右下角中的内核:后面的数字,就是你CPU的核心数,下图中我的是16个核心的。 需要注意的是,下面的逻辑处理器:32 表示支持 32 线程(即超线…...

JavaScript使用地理位置 API

前言 在JavaScript中,Geolocation API 是一种用于访问用户地理位置的接口。这个API允许网页应用程序获取用户的位置并提供基于位置的服务。 if (navigator.geolocation)navigator.geolocation.getCurrentPosition(function () {},function () {});这个函数中需要传…...

dockerfile部署fastapi项目

dockerfile部署fastapi项目 1、Dockerfile # 使用Python官方镜像作为基础镜像 FROM python:3.8-slim# 更新apt-get源并安装依赖 # RUN apt-get update -y && apt-get install -y git# 设置环境变量 ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1# 创建工作目…...

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgen…...

【Linux系统学习】2.Linux基础命令

Linux基础命令 Linux的目录结构 Linux命令入门 目录切换相关命令(cd/pwd) 相对路径、绝对路径和特殊路径符 创建目录命令(mkdir) 文件操作命令part1(touch、cat、more) 文件操作命令part2(cp、mv、rm) 查找命令(which、find) grep、wc和管道符…...

ABAP正则表达式 特殊字符处理

REPLACE ALL OCCURRENCES OF REGEX [[:space:]] IN <fs_purhdinfo>-cell_value WITH ."可去掉空格或回车键 REPLACE ALL OCCURRENCES OF &#xff1a; IN <fs_purhdinfo>-cell_value WITH ."可去掉空格或回车键 REPLACE ALL OCCURRENCES OF R…...

【2024高教社杯全国大学生数学建模竞赛】ABCDEF题 问题分析、模型建立、参考文献及实现代码

【2024高教社杯全国大学生数学建模竞赛】ABCDEF题 问题分析、模型建立、参考文献及实现代码 1 比赛时间 北京时间&#xff1a;2024年9月5日 18:00-2024年9月8日20:00 2 思路内容 2.1 往届比赛资料 【2022高教社杯数学建模】C题&#xff1a;古代玻璃制品的成分分析与鉴别方案…...

# VMware 共享文件

VMware tools快速安装 VMware 提供了 open-vm-tools&#xff0c;这是 VMware 官方推荐的开源工具包&#xff0c;通常不需要手动安装 VMware Tools&#xff0c;因为大多数 Linux 发行版&#xff08;包括 Ubuntu、CentOS 等&#xff09;都包含了 open-vm-tools&#xff0c;并且已…...

[UVM]3.核心基类 uvm_object 域的自动化 copy() compare() print() pack unpack

1.核心基类&#xff1a;uvm_object &#xff08;1&#xff09;虚类只能声明&#xff0c;不能例化。 &#xff08;2&#xff09;uvm_object提供的方法 2.域的自动化&#xff08;field automation&#xff09; &#xff08;1&#xff09;简述 &#xff08;2&#xff09;示例 格…...

Java网络编程入门

在现代软件开发中&#xff0c;网络编程是一项不可或缺的技能。Java提供了强大的网络编程支持&#xff0c;使得开发者能够轻松地创建网络应用程序。今天将介绍Java中的网络编程基础&#xff0c;重点讲解Socket和ServerSocket类的使用。 什么是Socket&#xff1f; Socket是网络通…...

前端基础面试题·第三篇——JavaScript(其一)

1.JavaScript数据类型与运算符 数据类型 原始数据类型&#xff1a; 1.Number 2.String 3.Boolean 4.undefined 5.null 6.Symbol 7.bigint 复杂数据类型&#xff1a; 1.Function 2.非函数&#xff1a; Array: 数组 Object: 对象 Date: 日期 RegExp: 正则 Map: 映射 Set: 集合 …...

【机器学习】生成对抗网络(Generative Adversarial Networks, GANs)详解

1.引言 生成对抗网络(Generative Adversarial Networks, GANs)是近年来人工智能领域最具创新性和颠覆性的模型之一。自2014年由Ian Goodfellow及其团队提出以来,GAN的出现彻底改变了生成模型的研究范式。传统的生成模型,如变分自编码器(VAE)、隐马尔可夫模型(HMM)等,…...

QT作业1

1> 手写unique_ptr指针指针 代码&#xff1a; #include <iostream>using namespace std;// 自定义的unique_ptr类模板 template <typename T> class unique_ptr { public:// 构造函数&#xff0c;接收一个指针explicit unique_ptr(T* ptr nullptr) noexcept …...

Mybatis-设计模式总结

1、Builder模式 Builder模式的定义是“将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。”&#xff0c;它属于创建类模式&#xff0c;一般来说&#xff0c;如果一个对象的构建比较复杂&#xff0c;超出了构造函数所能包含的范围&#x…...

【笔记】Java | 三目运算符和Math函数的比较

实际效果 比较两数并赋值&#xff0c;如下两种方法的耗时不会有差异。 result Math.min(result, subLen);result result < subLen ? result : subLen; 源码解析 因为源码Math.min的源码本质就算三目运算符的比较&#xff0c;所以执行结果是一样的。 三目运算符简介 概…...

信创实践(2):利用Leapp工具迁移CentOS至AnolisOS,实现系统升级与自主可控

1. 引言 为了满足用户在CentOS退出后对操作系统使用的诉求&#xff0c;OpenAnolis龙蜥社区正式发布了Anolis OS。越来越多的CentOS客户期望能够迁移到Anolis OS上来。操作系统迁移是一个复杂工程&#xff0c;手工迁移技术要求高&#xff0c;操作复杂度强&#xff0c;需要耗费大…...

数据库死锁查询SQL

Oracle 从Oracle数据库的动态性能视图&#xff08;Dynamic Performance Views&#xff09;中检索当前被锁定的数据库对象的相关信息&#xff0c;以及持有这些锁的会话&#xff08;session&#xff09;的详细信息。具体来说&#xff0c;它连接了v$ session和v$locked_object两个…...

vLLM (4) - LLMEngine上篇

系列文章目录 vLLM (1) - Qwen2推理&部署 vLLM (2) - 架构总览 vLLM (3) - Sequence & SequenceGroup vLLM (4) - LLMEngine上篇 vLLM (5) - LLMEngine下篇 文章目录 系列文章目录前言一、类图二、LLM三、LLMEngine四、GPUExectuor五、Worker六、ModelRunner七、Cache…...

Java重修笔记 第五十天 HashSet 和 TreeSet 的去重机制比较

HashSet 和 TreeSet 的去重机制比较 1. HashSet 的去重机制&#xff1a;HashCode() equals() 。通过运算得到 key &#xff0c;也就是该对象的哈希值&#xff0c;再通过哈希值得到该对象在 table 表上的索引位置&#xff0c;若该位置上没有链表数据就直接存放&#xff0c;若…...

提前购|基于SSM+vue的创新型产品提前购平台(源码+数据库+文档)

创新型产品提前购平台 基于SSMvue的创新型产品提前购平台 一、前言 二、系统设计 三、系统功能设计 系统功能实现 后台模块实现 管理员模块实现 发布企业管理实现 个体管理实现 投资企业管理实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选…...

上海市计算机学会竞赛平台2024年7月月赛丙组求和问题

题目描述 给定 nn 个整数 a1,a2,…,ana1​,a2​,…,an​&#xff0c;请问这个序列最长有多少长的前缀&#xff0c;满足元素的和大于或等于 00&#xff1f;如果任何长度大于 00 的前缀之和都为负数&#xff0c;则输出 00 输入格式 第一行&#xff1a;单个整数表示 nn第二行&a…...

【LVI-SAM】激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节

激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节 1. 特征提取实现过程总结1.0 特征提取过程小结1.1 类 FeatureExtraction 的整体结构与作用1.2 详细特征提取的过程1. 平滑度计算&#xff08;calculateSmoothness()&#xff09;2. 标记遮挡点&#xff08;markOcc…...