Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能
作者:小酒馆 发布时间:2021-07-24 04:50:52
标签:python,抢票,验证码,selenium
测试结果:
整个买票流程可以再快一点,不过为了稳定起见,有些地方等待了一些时间
完整程序,拿去可用
整个程序分了三个模块:购票模块(主体)、验证码识别模块、余票查询模块
购票模块:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, ElementNotVisibleException
import time
import requests
from urllib.parse import urlencode
from pyquery import PyQuery as pq
from check_ticket import Check
from verify import Code
import json
class Buy_Ticket():
def __init__(self, start_station, end_station, date, username, password, purpose):
self.num = 1
self.start = start_station
self.end = end_station
self.date = date
self.username = username
self.password = password
self.purpose = purpose
self.login_url = 'https://kyfw.12306.cn/otn/login/init'
self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
def login(self):
browser.get(self.login_url)
try:
input_name = browser.find_element_by_id('username')
input_pd = browser.find_element_by_id('password')
button = browser.find_element_by_id('loginSub')
time.sleep(1)
input_name.send_keys(self.username)
input_pd.send_keys(self.password)
c = Code(browser) #调用验证码识别模块
c.main()
button.click()
time.sleep(2)
#等待页面跳转,如果验证码识别错误,就执行下面的while语句
while browser.current_url == self.login_url + '#':
c = Code(browser)
c.main()
button.click()
time.sleep(2)
#self.get_passenger()
self.check()
except NoSuchElementException:
self.login()
def check(self):
#调用余票查询模块
check = Check(self.date, self.start, self.end, self.purpose)
start_end = check.look_up_station()
self.num = check.get_info()
#cookie的添加,json.dumps把以汉字形式呈现的起始、终点站转化成unicode编码,可在审查元素里查看cookie
browser.add_cookie({'name':'_jc_save_fromStation', 'value':json.dumps(self.start).strip('"').replace('\\', '%') + '%2C' + start_end[0]})
browser.add_cookie({'name':'_jc_save_toStation', 'value':json.dumps(self.end).strip('"').replace('\\', '%') + '%2C' + start_end[1]})
browser.add_cookie({'name':'_jc_save_fromDate', 'value':self.date})
browser.get(self.ticket_url)
if self.purpose == '学生':
btn = browser.find_element_by_id('sf2')
time.sleep(1)
btn.click()
button = browser.find_element_by_id('query_ticket')
time.sleep(1)
button.click()
def book_ticket(self):
print('开始预订车票...')
#先查找出所有车次对应的预订按钮,再根据余票查询模块返回的车次序号,点击相应的预订按钮
button = browser.find_elements_by_class_name('btn72')
button[self.num-1].click()
time.sleep(3)
button2 = browser.find_element_by_id('normalPassenger_0') #按实际情况,可自行修改,这里就选择的第一个常用联系人,
#第二个是normalPassenger_1,依此类推
button2.click()
button3 = browser.find_element_by_id('submitOrder_id')
time.sleep(1)
button3.click()
time.sleep(3) #等待页面加载完毕,不然后面可能会报错,等待时间自行决定
try:
button4 = browser.find_element_by_id('qr_submit_id')
button4.click()
except ElementNotVisibleException:
button4 = browser.find_element_by_id('qr_submit_id')
button4.click()
print('车票预定成功!请在30分钟内完成付款!')
def main(self):
self.login()
self.book_ticket()
if __name__ == '__main__':
begin = time.time()
browser = webdriver.Chrome()
b = Buy_Ticket('上海', '重庆', '2018-09-18', '账号', '密码', 'ADULT') #账号、密码自行修改
b.main()
end = time.time()
print('总耗时:%d秒' % int(end-begin))
#browser.close()
验证码识别模块:
import requests
from PIL import Image
from selenium.webdriver import ActionChains
import time
from io import BytesIO
class Code():
def __init__(self, browser):
self.browser = browser
self.verify_url = 'http://littlebigluo.qicp.net:47720/' #验证码识别网址,返回识别结果
#确定验证码的位置
def get_position(self):
time.sleep(3)
element = self.browser.find_element_by_class_name('touclick-img-par')
time.sleep(2)
location = element.location
size = element.size
position= (location['x'], location['y'], location['x'] + size['width'], location['y'] + size['height'])
return position
#截取整个网页页面
def get_screenshot(self):
screenshot = self.browser.get_screenshot_as_png()
screenshot = Image.open(BytesIO(screenshot))
return screenshot
#从截取的网页,裁剪出验证码图片,并保存到本地
def get_touclick_img(self, name = 'captcha.png'):
position = self.get_position()
print('验证码的位置:', position)
screenshot = self.get_screenshot()
captcha = screenshot.crop(position)
captcha.save('captcha.png')
#验证码解析
def parse_img(self):
files = {'file': open('captcha.png', 'rb')} #打开保存到本地的验证码图片
response = requests.post(self.verify_url, files=files)
num = response.text.split('<B>')[1].split('<')[0]
print('验证码识别成功!图片位置:%s' % num)
try:
if int(num):
return [int(num)]
except ValueError:
num = list(map(int,num.split()))
return num
#识别结果num都以列表形式返回,方便后续验证码的点击
#实现验证码自动点击
def move(self):
num = self.parse_img()
try:
element = self.browser.find_element_by_class_name('touclick-img-par')
for i in num:
if i <= 4:
ActionChains(self.browser).move_to_element_with_offset(element,40+72*(i-1),73).click().perform()
else :
i -= 4
ActionChains(self.browser).move_to_element_with_offset(element,40+72*(i-1),145).click().perform()
except:
print('元素不可选!')
def main(self):
self.get_touclick_img()
self.move()
余票查询模块:
import requests
from urllib.parse import urlencode
class Check():
def __init__(self, date, start, end, purpose):
self.base_url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?'
self.url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9018'
self.date = date
self.start_station = start
self.end_station = end
if purpose == '学生':
self.purpose = '0X00'
else:
self.purpose = purpose
#查找出车站的英文简称,用于构造cookie、完整的余票查询链接
def look_up_station(self):
response1 = requests.get(self.url)
a = response1.text.split('@')
a.pop(0)
for each in a:
i = each.split('|')
if self.start_station == i[1]:
self.start_station = i[2]
elif self.end_station == i[1]:
self.end_station = i[2]
return [self.start_station, self.end_station]
def get_info(self):
start_end = self.look_up_station()
#构造请求参数
data = {
'leftTicketDTO.train_date':self.date,
'leftTicketDTO.from_station':start_end[0],
'leftTicketDTO.to_station':start_end[1],
'purpose_codes':self.purpose
}
url = self.base_url + urlencode(data)
response = requests.get(url)
json = response.json()
maps = json['data']['map']
count = 0 #用于对车次编号
for each in json['data']['result']:
count += 1
s = each.split('|')[3:]
info = {
'train':s[0],
'start_end':maps[s[3]] + '-' + maps[s[4]],
'time':s[5] + '-' + s[6],
'历时':s[7],
'一等座':s[-5],
'二等座':s[-6]
}
try:
#余票的结果有3种:有、一个具体的数字(如:18、6等)、无,判断如果余票是有或者一个具体的数字就直接输出对应的车次信息,然后返回
if info['二等座'] == '有' or int(info['二等座']):
print('[%d]' % count, info)
return count
except ValueError:
continue
总结
以上所述是小编给大家介绍的Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能网站的支持!
来源:http://www.cnblogs.com/mumengyun/p/10001109.html
0
投稿
猜你喜欢
- 修复Access数据库,我们一般使用微软Office 97中带的Access 97对数据库进行修复和整理。Access数据库被损坏分以下几种
- 暂时是一个手动设置无向图中的边,用一个二维数组表示,后面会改进为用户自己定义无向图的边。学习python的新手,若大佬有解决的办法,希望不吝
- 本文为大家分享了python八皇后问题的解决方法,供大家参考,具体内容如下题目:给定一个 N*N 正方形棋盘,在上面放置 N个棋子,又叫皇后
- 问题有二进制文件中保存了 20 亿个 2 Bytes 的数,需将其读出,每 20000 个数作图,拟合后输出结果。解决# -*- codin
- 默认情况下,Python DB API会返回不带字段的结果,这意味着你得到的是一个列表,而不是一个字典。花费一点性能代价之后,你可以返回一个
- 症状 在 Service Pack 4 (SP 4) 运行 Microsoft Windows Server 2003、 Microsoft
- 以下各种方式仅供参考,本人亲测只有官方提供的方式比较靠谱。1. 使用多个进程启动多个Tornado实例import tornado.http
- 建立池连接可以显著提高应用程序的性能和可缩放性。SQL Server .NET Framework 数据提供程序自动为 ADO.NET 客户
- 前言:在自动化测试中,经常需要查找操作文件,比如说查找配置文件(从而读取配置文件的信息),查找测试报告(从而发送测试报告邮件),经常要对大量
- spark编程python实例ValueError: Cannot run multiple SparkContexts at once;
- 关于中大型开发b/s开发中的缓存(cache),我的一些看法,有不正确的或者是有笔误的地方,请指正。thanks首先,应该了解基本的,对于缓
- 前言:MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。官网给出
- 现在jquery应用的越来越多, 有些同学在享受爽快淋漓coding时就将性能问题忽略了, 比如我. jquery虽
- 数据import numpy as npimport pandas as pddata = [{'Name': '小
- Mysql 设置boolean类型1.tinyint类型我们创建test表,并设置其bl字段为boolean类型create table t
- 前言如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有
- 使用一个遵循buffer protocol的对象就可以和numpy交互了.这个buffer_protocol要有哪些东西呢? 要有如下接口:
- 在刚学Pandas时,行选择和列选择非常容易混淆,在这里进行一下讨论和归纳本文的数据来源:https://github.com/fiveth
- 导语提到《俄罗斯方块》(Tetris),那真是几乎无人不知无人不晓。其历史之悠久,可玩性之持久,能手轻轻一挥,吊打一 * 游戏。对于绝大多数小
- 一、前言在调用函数时,大多数情况下,主调函数和被调函用之间有数据传递关系,这就是有参数的函数形式。函数参数的作用是传递数据给函数使用,函数利