实现12306全自动下单功能(Python+PyCharm附:主要代码)

基本实现步骤

(一)selenium

Selenium是开源的自动化测试工具,它主要是用于Web 应用程序的自动化测试,同时支持所有基于web 的管理任务自动化。
在本项目中相当于:上层统一的控制浏览器API接口

流程图如下:

1.安装selenium,在命令行输入“pip install selenium
2.进国内淘宝镜像 http://npm.taobao.org/mirrors/chromedriver/,下载相对应版本的chromedriver,将它拷贝进项目里

selenium.py主要实现代码:
import time# 1. 导入模块
from selenium import webdriver# 导入等待对象模块
from  selenium.webdriver.support.wait import  WebDriverWait
# 导入条件判断模块
from  selenium.webdriver.support import expected_conditions as  EC
# 导入查询元素模块
from  selenium.webdriver.common.by import By# 2. 通过驱动创建浏览器对象
# 创建浏览器对象 2 种方式
# 2.1> 参数需要指定驱动路径
browser = webdriver.Chrome('./chromedriver')# 设置隐性等待(缺点:无法控制AJAX请求)
# browser.implicitly_wait(5)# 2.2> PATH 全局的环境变量,可以把驱动文件拷贝到 $PATH 路径中
# browser = webdriver.Chrome()# 3. 输入网址
browser.get('https://www.baidu.com')# 4. 操作浏览器
"""
find 系列函数,专门用于定义元素find_element_by_xxx             寻找符合条件的第一个元素
find_elements_by_xxx            寻找符合条件的所有元素(返回是一个列表)by_xxx
find_element(s)_by_class_name      可以通过 class_name 寻找元素
find_element(s)_by_id
find_element(s)_by_name
find_element(s)_by_tag_name
find_element(s)_by_css_selector
find_element(s)_by_link_text               通过文本内容寻找元素
find_element(s)_by_partial_link_text       通过包含某个内容寻找元素
"""# 4.1 输入关键字
input_element = browser.find_element_by_id("kw")
input_element.send_keys("itcast")# 4.2 点击百度一下
button_element = browser.find_element_by_id('su')
button_element.click()# time.sleep(2)# 4.3 找到传智播客 链接,并且打开# 显性等待,每个元素都可以自己定义检查条件
"""
timeout = 60t = time.time()while True :try:# 检测时间间隔time.sleep(0.1)link_element = browser.find_element_by_class_name("t")link_element.click()breakexcept:# 超时设置if time.time() - t > timeout:breakpass
"""
# 系统提供显性等待API
# 1.创建等待对象
# 第一个参数是浏览器对象
# 第二个参数是超时时间
# 第三个参数是检测时间间隔
wait = WebDriverWait(browser,5.0,0.5)# 2.通过等待对象获取元素
# presence_of_element_located 检查元素是否存在,如果存在就返回,如果不存在就继续检查
# visibility_of_element_located 检查元素是否可见
link_element = wait.until(EC.presence_of_element_located((By.CLASS_NAME,"t")))
link_element.click()time.sleep(5)# 5. 退出浏览器
browser.quit()

(二)打码平台

可以通过第三方平台进行智能识别或者人工识别图片。
优点:价格便宜、使用简单、识别率高

流程图如下:

1.进入云打码平台http://www.yundama.com/,注册用户登录
2.进行在线测试,即点击“在线识别”,选择图片进行测试
3.下载 SDK:http://www.yundama.com/apidoc/YDM_SDK.html
4.解压后,选择3.x的版本,拷贝到项目中,把Deom3.x去掉
5.输入用户名、密码、软件ID、软件秘钥
6.将测试图片拷贝到项目中,输入图片的文件名、验证码类型等

主要实现代码(在文章后面有完整代码 YDMHTTP.py ):
# 用户名
username    = ''# 密码
password    = ''# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid       = # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey      = ''def decode(filename,codetype):# 图片文件# filename    = 'xxxx.png'# 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html# codetype    = 3000# 超时时间,秒timeout     = 60

(三)购票流程

实现步骤:

1>访问列表页
2>通过时间判定选择点击预订
3>点击账号登录
4>输入用户名和密码
5>截图获取验证码图片
6>发送打码平台获取识别数字
7>定义8个点击坐标
8>模拟点击坐标
9>点击登录
10>点击选择人物
11>点击提交订单
12>点击确认订单

12306.py主要实现代码:
import timeimport json
from  selenium import  webdriver
from selenium.webdriver import ActionChainsfrom YDMHTTP import decode# 导入图片操作对象模块
from PIL import Image
from io import BytesIO# 导入等待对象模块
from  selenium.webdriver.support.wait import  WebDriverWait
# 导入条件判断模块
from  selenium.webdriver.support import expected_conditions as  EC
# 导入查询元素模块
from  selenium.webdriver.common.by import Bybrowser = webdriver.Chrome('./chromedriver')linktypeid = "dc"
fs = "上海,SHH"
ts = "广州,GZQ"
date = "2019-09-24"
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)
browser.get(url)wait = WebDriverWait(browser,10,0.5)# 通过时间判定选择点击预订
# 寻找 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:date_string = tr.find_element_by_class_name("start-t").text# print(date_string)# 判断时间是否在符合条件的范围内tr.find_element_by_class_name('btn72').click()break# 点击账号(因为是异步加载的所以需要显性等待)
wait.until(EC.visibility_of_element_located((By.LINK_TEXT,"账号登录"))).click()# 输入用户名和密码
with open('account.json','r',encoding='utf-8') as f:account = json.load(f)
browser.find_element_by_id("J-userName").send_keys(account["username"])
browser.find_element_by_id("J-password").send_keys(account["pwd"])# 获取全屏图片
full_img_data = browser.get_screenshot_as_png()# 计算截图位置
# 获取截图元素对象
login_img_element = browser.find_elements_by_id("J-loginImg")
# 通过截图元素对象计算截图位置坐标print(login_img_element[0], type(login_img_element))
print(login_img_element[0].location, type(login_img_element))login_img_element = login_img_element[0]# 获取验证码图片
left = (login_img_element.location['x'] - 280)
top = login_img_element.location['y']
right = login_img_element.location['x'] + (login_img_element.size['width'] - 250)
bottom = login_img_element.location['y'] + login_img_element.size['height']cut_info = (left,top,right,bottom)# 通过计算出的截图图片位置在全屏图片中截取所需要的图片
full_img = Image.open(BytesIO(full_img_data))
# 通过截图信息对象截图图片
cut_img = full_img.crop(cut_info)
# 把图片保存到本地
cut_img.save("cut_img.png")# 发送打码平台获取数字
result = decode("cut_img.png",codetype=6701)
print(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()# 点击登录
browser.find_element_by_id('J-login').click()# 点击选择人物
wait.until(EC.visibility_of_element_located((By.ID,"normalPassenger_0"))).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()time.sleep(5)
browser.quit()
code.py代码如下:
from YDMHTTP import decode# print(decode('test2.png',codetype=3000))print(decode('test3.png',codetype=6701))
YDMHTTP.py代码如下:
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 = passwordself.appid = str(appid)self.appkey = appkeydef request(self, fields, files=[]):response = self.post_url(self.apiurl, fields, files)response = json.loads(response)return responsedef 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 -9001def 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 -9001def 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 -9001def 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, resultelse: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 -9001def 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####################################################################### 用户名
username    = ''# 密码
password    = ''# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid       = # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey      = ''def decode(filename,codetype):# 图片文件# filename    = 'test2.png'# 验证码类型,# 例: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######################################################################

遇到的问题

一、问题列表

1.错误原因:没有导入requests

  • 解决办法:开始菜单选择运行,输入cmd运行,然后cd命令进入到python安装目录下的Scripts文件中,然后输入pip install requests,就好了。
    或者 打开Python文件的安装目录,进入Scripts文件中,按住Shift键+鼠标右击

2.错误原因:因为20号最早的一趟车无票,导致元素无法查到,代码没有设置跳转下一趟时间的车次

  • 解决办法:首先,截取验证码图片,需要安装操作库“pip install Pillow”;然后改成21号即可正确运行,输出!

3.错误原因:没有准确定位截取的验证码的位置

  • 解决办法:百度获取正确的坐标相关代码

实现12306全自动下单功能(Python+PyCharm附:主要代码)相关推荐

  1. OpenCV文件输入输出的序列化功能的实例(附完整代码)

    OpenCV文件输入输出的序列化功能的实例 OpenCV文件输入输出的序列化功能的实例 OpenCV文件输入输出的序列化功能的实例 #include <opencv2/core.hpp> ...

  2. OpenCV显示copyMakeBorder功能的实例(附完整代码)

    OpenCV显示copyMakeBorder功能的实例 OpenCV显示copyMakeBorder功能的实例 OpenCV显示copyMakeBorder功能的实例 #include "o ...

  3. OpenCV序列化功能的实例(附完整代码)

    OpenCV序列化功能的实例 OpenCV序列化功能的实例 OpenCV序列化功能的实例 #include "opencv2/core.hpp" #include <iost ...

  4. OpenCV绘图和文本输出功能的实例(附完整代码)

    OpenCV绘图和文本输出功能的实例 OpenCV绘图和文本输出功能的实例 OpenCV绘图和文本输出功能的实例 #include "opencv2/core.hpp" #incl ...

  5. OpenCV边缘之间的距离转换功能的实例(附完整代码)

    OpenCV边缘之间的距离转换功能的实例 OpenCV边缘之间的距离转换功能的实例 OpenCV边缘之间的距离转换功能的实例 #include <opencv2/core/utility.hpp ...

  6. OpenCV cv :: Mat的串行输出功能的实例(附完整代码)

    OpenCV cv :: Mat的串行输出功能的实例 OpenCV cv :: Mat的串行输出功能的实例 OpenCV cv :: Mat的串行输出功能的实例 #include "open ...

  7. 【2022 Twitter爬虫高级搜索接口分析及代码编写 Python爬虫 附主要代码及解析】

    目录 前言 一.网页分析 二.主要代码 1.请求Json包 2. Guesstoken获取 2.Json文件解析 3.存入xlsx 运行效果 名人信息解析获取 存入excel 总结 前言 最近在帮助做 ...

  8. 使用Python模拟登陆12306并全自动下单

    最近一段时间一直在研究用Python模拟登陆12306网站并自动刷票下单,经过一段时间的摸索,终于完成了代码,实现了12306刷票的功能.话不多说,先给大伙儿看看成果.我录制了一段时间,展示了自动刷票 ...

  9. python模拟火车订票系统代码_Python3.6实现12306火车票自动抢票,附源码

    原标题:Python3.6实现12306火车票自动抢票,附源码 Python(发音:英[?pa?θ?n],美[?pa?θɑ:n]),是一种面向对象.直译式电脑编程语言,也是一种功能强大的通用型语言,已 ...

  10. Python + selenium + requests实现12306全自动买票

    Python + selenium + requests实现12306全自动买票 2020.05.03更新: 下面是新的测试结果: 2021.03.28更新:谷歌浏览器升级导致之前的隐藏方法失效,更新 ...

最新文章

  1. 入门 | CNN也能用于NLP任务,一文简述文本分类任务的7个模型
  2. sqlmap namespace ibatis 没有生效
  3. C# JsonHelper类
  4. gojs 部分功能实现
  5. RequireJS简单教程
  6. 智能一代云平台(四):15年上半年维护过程中精彩小插曲
  7. Log4Net Layout使用以及扩展
  8. LINUX下载编译opusfile/opus-tools
  9. 【安装记录】如何在官网找到老版本的jdk,如 jdk-8u271-windows-x64
  10. TongWeb基本使用
  11. 看看在职场里是怎么混社会的……
  12. JavaScript图片跟随鼠标移动
  13. theos tweak导入自定义类
  14. java项目里bean文件夹_JavaBean的class文件必须放在WEB-INF文件夹中。()
  15. java蚂蚁智力题,智力题大全_附答案
  16. 图解springboot
  17. 计算机系统安全启动,关闭电脑的安全启动项( Secure Boot )
  18. JPA 7. Spring 整合 JPA
  19. 计算机监控系统维护重点,监控系统维护制度
  20. mysql144错误_MySQL 144错误

热门文章

  1. 高仿富途牛牛-组件化(一)-支持页签拖拽、增删、小工具
  2. win10企业版2016长期服务激活教程
  3. 如何在远程桌面无响应的情况下完成远程电脑重启
  4. 为知笔记——使用第三方Markdown的Typora编辑器编辑为知笔记
  5. 为知笔记 | 快速收集有价值的网页,微博,邮件!
  6. JavaScript基础之new操作神来之笔
  7. 操作系统文件系统练习题
  8. 同一服务器的跨库查询
  9. python软件安装链接电视_Python爬虫程序:电视剧琅琊榜全集的自动化处理
  10. 如何快速新建多个不同名称文件夹?