Python实例--12306的抢票功能
基础知识学习
目标: 通过python程序实现自动登录下单功能
知识点: Selenium + 云打码 + Python
学习链接:
需求分析
Chrome浏览器:71.0.3578.98_chrome_installer.exe
12306官网: https://www.12306.cn/index/index.html

# 选择时间,点击确定,查询列表,获取列表页的请求URL

# 通过F12,查看当前页面的请求URL:
https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E4%B8%8A%E6%B5%B7,SHH&ts=%E6%88%90%E9%83%BD,CDW&date=2019-02-03&flag=N,N,Y

# 查看请求参数

# 选择一条车次数据,查看该列表(一条tr一条数据)

# 获取时间元素

# 查看预定按钮

# 当根据时间选择好了列车后,点击预定按钮就会提示我们登录账号(注意是Ajax请求,所以需要until查找)

# 查找用户名和密码登录框的ID


# 截取验证码
安装插件 pip3 install Pillow

# 获取全屏图片 –> 计算截图位置(根据元素的宽和高确定大小) –> 截取所需要图片的大小

# 利用云打码进行验证码解析

# 定义打点(模拟选中图片)

# 点击登录

# 选择需要买票的人

# 点击提交

完整代码
12306.py
# coding: utf-8 import os
import time
import json
# 图片操作对象
from PIL import Image
# 将二进制文件转换为IO流输出
from io import BytesIO
import yundama from selenium import webdriver
# 1. 导入模块
from selenium import webdriver
# 1> 等待对象模块
from selenium.webdriver.support.wait import WebDriverWait
# 2> 导入等待条件模块
from selenium.webdriver.support import expected_conditions as EC
# 3> 导入查询元素模块
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains browser = webdriver.Chrome("chromedriver") # 12306是异步请求,所以使用selenium的显性等待方案
wait = WebDriverWait(browser, 10, 0.5) # 创建等待对象 # 请求参数
linktypeid = 'dc'
fs = '上海,SHH'
ts = '成都,CDW'
date ='2019-02-03'
flag = 'N,N,Y' # 请求URL:
# https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=上海&ts=北京&date=2019-02-03&flag=N,N,Y
base_url = "https://kyfw.12306.cn/otn/leftTicket/init?linktypeid={}&fs={}&ts={}&date={}&flag={}"
url = base_url.format(linktypeid, fs, ts, date, flag) # 访问12306的列表页面
browser.get(url) # 通过时间判定,选择点击预订
# 寻找tr标签中,属性id以ticket开头的数据
tr_list = wait.until(EC.visibility_of_all_elements_located((By.XPATH, "//tr[starts-with(@id, 'ticket_')]"))) # 找到所有可见元素 for tr in tr_list:
count = 0
t_start = tr.find_element_by_class_name('start-t').text
with open('start.txt', 'a') as f:
f.write(t_start) # 判断时间是否在符合条件的范围内
if count < 5 and t_start == "11:16": # 这里以06:33为例
tr.find_element_by_class_name('btn72').click()
break
else:
count += 1
continue # 点击账号(注意因为是异步加载的所有需要显性等待)
# browser.find_element_by_link_text("账号登录").click() # 因为还没有加载出来,因为是Ajax请求,所以要用until查找
wait.until(EC.visibility_of_element_located((By.LINK_TEXT, "账号登录"))).click() # 打开json文件,
with open('account.json', 'r', encoding='utf-8') as f:
account = json.load(f, encoding='utf-8') # 输入用户名和密码
j_username = browser.find_element_by_id('J-userName').send_keys(account['username'])
j_password = browser.find_element_by_id('J-password').send_keys(account['password']) # 获取全屏图片
full_img_data = browser.get_screenshot_as_png() # 计算截图位置
login_img_element = browser.find_element_by_id("J-loginImg") # 获取截图元素对象
scale = 1.0
x1 = login_img_element.location["x"] - 155
y1 = login_img_element.location["y"] - 100
x2 = x1 + login_img_element.size["width"]
y2 = y1 + login_img_element.size["height"]
cut_info = (x1, y1, x2, y2)
print('cut_info', cut_info) # 把全屏图片构建成全屏图片操作对象
full_img = Image.open(BytesIO(full_img_data))
# 通过截图信息对象截图图片
cut_img = full_img.crop(cut_info)
# 把图片保存到本地
cut_img.save('cut_img.png')
time.sleep(5)
# 利用云打码进行图片解析
result = yundama.decode('cut_img.png', '6701')
print('Image Decode:', result) # 定义8个点击坐标点
positions = [
(80, 140),
(230, 140),
(380, 140),
(530, 140),
(80, 280),
(230, 280),
(380, 280),
(530, 280)
] # 模拟点击坐标
for num in result:
position = positions[int(num) - 1]
# ActionChains 动作对象
ActionChains(browser).move_to_element_with_offset(login_img_element,position[0] / 2,position[1] / 2).click().perform()
print(position[0], position[1], "点击图片完成")
time.sleep(5) # 点击登录
browser.find_element_by_id("J-login").click() # 点击选择人物
wait.until(EC.visibility_of_element_located((By.ID, "normalPassenger_1"))).click() # 点击提交订单
browser.find_element_by_id('submitOrder_id').click() time.sleep(2)
# 点击确认订单
wait.until(EC.visibility_of_element_located((By.ID, 'qr_submit_id'))).click() print("抢票成功,请支付") time.sleep(5)
browser.quit()
account.json
{
"username":"18XXXXXXXXXX",
"password":"18XXXXXXXXXX"
}
yundama.json
import http.client, mimetypes, urllib, json, time, requests ###################################################################### class YDMHttp:
apiurl = 'http://api.yundama.com/api.php'
username = ''
password = ''
appid = ''
appkey = '' def __init__(self, username, password, appid, appkey):
self.username = username
self.password = password
self.appid = str(appid)
self.appkey = appkey def request(self, fields, files=[]):
response = self.post_url(self.apiurl, fields, files)
response = json.loads(response)
return response def balance(self):
data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid,
'appkey': self.appkey}
response = self.request(data)
if (response):
if (response['ret'] and response['ret'] < 0):
return response['ret']
else:
return response['balance']
else:
return -9001 def login(self):
data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid,
'appkey': self.appkey}
response = self.request(data)
if (response):
if (response['ret'] and response['ret'] < 0):
return response['ret']
else:
return response['uid']
else:
return -9001 def upload(self, filename, codetype, timeout):
data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid,
'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)}
file = {'file': filename}
response = self.request(data, file)
if (response):
if (response['ret'] and response['ret'] < 0):
return response['ret']
else:
return response['cid']
else:
return -9001 def result(self, cid):
data = {'method': 'result', 'username': self.username, 'password': self.password, 'appid': self.appid,
'appkey': self.appkey, 'cid': str(cid)}
response = self.request(data)
return response and response['text'] or '' def decode(self, filename, codetype, timeout):
cid = self.upload(filename, codetype, timeout)
if (cid > 0):
for i in range(0, timeout):
result = self.result(cid)
if (result != ''):
return cid, result
else:
time.sleep(1)
return -3003, ''
else:
return cid, '' def report(self, cid):
data = {'method': 'report', 'username': self.username, 'password': self.password, 'appid': self.appid,
'appkey': self.appkey, 'cid': str(cid), 'flag': '0'}
response = self.request(data)
if (response):
return response['ret']
else:
return -9001 def post_url(self, url, fields, files=[]):
for key in files:
files[key] = open(files[key], 'rb');
res = requests.post(url, files=files, data=fields)
return res.text def decode(filename, codetype):
######################################################################
# 用户名
username = 'XXXXXXXXX' # 密码
password = 'XXXXXXXX'
# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid = 6795 # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey = '62a6760f83a91f818be141d9a77463c5' # 图片文件
# filename = 'getimage.jpg' # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。
# 在此查询所有类型 http://www.yundama.com/price.html
# codetype = 3000 # 超时时间,秒
timeout = 60 # 检查
if (username == 'username'):
print('请设置好相关参数再测试')
else:
# 初始化
yundama = YDMHttp(username, password, appid, appkey) # 登陆云打码
uid = yundama.login();
print('uid: %s' % uid) # 查询余额
balance = yundama.balance();
print('balance: %s' % balance) # 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
cid, result = yundama.decode(filename, codetype, timeout);
print('cid: %s, result: %s' % (cid, result))
return result ######################################################################
Python实例--12306的抢票功能的更多相关文章
- python之12306自动查票
一.导读 本篇文章所采用的技术仅用于学习.研究,任何其他用途请自行承担后果. 12306自动查票使用到的python库主要是splinter,同时也涉及到查票的城市编码,具体的城市编码请在网络上搜 ...
- 抢票季:吐槽12306 & 分享抢票经验
又是一年一度的春运抢票季,不管你是北上.南下或者东进,在外漂泊了一年,有钱没钱总是要回家过年的. [图片来源于网络] 吐槽:12306抢票的悲伤 据说12306改版了,新版本里面除了UI这些面儿上的改 ...
- 利用Python实现12306爬虫--查票
在上一篇文章(http://www.cnblogs.com/fangtaoa/p/8321449.html)中,我们实现了12306爬虫的登录功能,接下来,我们就来实现查票的功能. 其实实现查票的功能 ...
- python+selenium实现自动抢票
使用说明 程序运行开始,需要输入出发地,目的地,出发时间,乘客信息,车次:乘客信息和车次可以输入多个 刚刚开始学习爬虫,selenium仅仅是解放了双手,运行效率不是很高: 程序运行时会打开chrom ...
- 12306 Pytho抢票代码
1.需要先安装python环境 2.安装selenium模拟用户来操作浏览器 3.将chromedriver驱动放入chrome浏览器应用根目录 4.用文本编辑器打开脚本,编辑购票人信息 5.通过cm ...
- Python实现12306自动查票程序
这是在网上扒拉过来的,原文链接: http://blog.csdn.net/An_Feng_z/article/details/78631290 目前时间2018/01/04 文中各种接口均为可用,亲 ...
- 基于selenium+java的12306自动抢票
import java.util.concurrent.TimeUnit; import org.openqa.selenium.By;import org.openqa.selenium.Keys; ...
- 简单的Python 火车抢票程序
当你想查询一下火车票信息的时候,你还在上12306官网吗?或是打开你手机里的APP?下面让我们来用Python写一个命令行版的火车票查看器, 只要在命令行敲一行命令就能获得你想要的火车票信息!如果你刚 ...
- 春运到了,带你用python来抢票回家!
不知不觉,一年一度的春运抢票大幕已经拉开,想快速抢到回家的车票吗?作为程序员,这些技术手段,你一定要知道. 为了让大家更快捷更便利的抢火车票,各种各样的抢票软件应需而生,这类软件大部分都是付费抢票的机 ...
随机推荐
- shell脚本案例分享 - 业务系统日志自定义保留或删除需求
需求说明: 线上某些业务系统的日志不定期产生, 有的每天产生, 有的好几天才产生, 因为系统只有在用的时候才产生日志,日志文件均存放在以当天日期命名的目录下. 当日志目录越来越多时就需要处理, 由此 ...
- .Net Core vs .Net Framework 如何为一个应用程序选择一个运行时(翻译)
.Net Core是下一件大事吗?我已经使用了一段时间了,我倾向认为它是.事实上,我们推测,在2018年,对这项技术熟练的开发人员将会有巨大的需求.但是它和.Net Framework的区别是什么?你 ...
- 在MVC应用程序中,怎样删除上传的文件
在ASP.NET MVC应用程序中,怎样删除上传的文件. 由于上传时,真正文件是存储在应用程序某一目录,在数据库表中,只是存储其基本信息.在删除时,需要注意一下,由于没有事务可操作.Insus.NET ...
- OpenGL学习笔记:Console工程下如何不显示控制台黑窗口只显示Windows窗口
刚学习OpenGL,绘制图形的时候,如果不进行设置,运行的时候会先出现黑窗口再出现Windows窗口. 其实要去除控制台窗口非常简单,只需要修改工程设置,把子系统改成Windows,程序的入口点改成m ...
- C++虚析构函数解析
当派生类对象从内存中撤销时一般先运行派生类的析构函数,然后再调用基类的析构函数. 如果用new运算符建立的派生类的临时对象,对指向基类的指针指向这个临时对象当用delete运算符撤销对象时,系统执行的 ...
- Gold Rush(hnu13249)
Gold Rush Time Limit: 2000ms, Special Time Limit:5000ms, Memory Limit:65536KB Total submit users: 15 ...
- mysql建表以及列属性
一.整型( int, tinyint, smallint 等 ) ------------------------------------------------------------------- ...
- JavaScript--事件入门(24)
// JavaScript事件是由访问Web页面的用户引起的一系列操作; // 例如:用户点击;当用户执行某些操作的时候,再去执行一系列代码; 一 事件介绍 // 事件一般是用于浏览器和用户操作进行交 ...
- 在学习使用webpack中遇到的错误
1.局部安装webpack之后使用node_modules/.bin/webpack app/main.js public/bundle.js命令报错 解决方法: webpack版 ...
- JavaScrip 概述 -- 前端知识
JavaScript概述 ECMAScript和JavaScript的关系 1996年11月,JavaScript的创造者--Netscape公司,决定将JavaScript提交给国际标准化组织ECM ...