这次我总算是没有鸽,花了几天做了个脚本
原理:
1,通过selenium做UI方面的点击等待事件
2,使用request来判断出登录时的验证码识别事件
功能:
由于时间太短了,所以做的比较简陋,主要是做了,
1,区分车次,GXXXX,DXXXX等
2,几等座(测试时已二等座为例,穷b只能买得起二等座了…这里提供了所有座位类型判定)
3,,选择联系人(这个很多脚本里没写,个人觉得这个蛮重要的,因为默认都是第一个,但是这里提供了可以选择其他位置的人)
4,出发日期,这个就不说了
用途:
1,买的上,直接到抢票成功,支付方式里
2,试着抢票,抢了100次,没出现异常情况,一般我们抢票也差不多了,多的没时间去测试…
话不多说,直接上代码
login_for_cookie.py
因为12306在多次登录时,会出现限制你再次登录
所以这里直接用一次登录获取cookie,然后在调试期间都是直接用cookie登录
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from Code import Code
import time
class Login():
def __init__(self, driver):
self.driver = driver
self.login_url = 'https://kyfw.12306.cn/otn/login/init'
self.login_success_url = 'https://kyfw.12306.cn/otn/view/index.html'
self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
self.person_info_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
def get_login_info(self):
with open('info.txt', 'r') as f:
lines = f.readlines()
username = lines[0].split()
password = lines[1].split()
f.close()
return [username, password]
def login_step(self):
username = self.get_login_info()[0]
password = self.get_login_info()[1]
self.driver.get(self.login_url) # 进入登录界面
self.driver.maximize_window() # 最大化
u = self.driver.find_element_by_id('username') # 用户名
p = self.driver.find_element_by_id('password') # 密码
button = self.driver.find_element_by_id('loginSub') # 登录
u.clear()
u.send_keys(username) # 输入用户名
p.clear()
p.send_keys(password) # 输入密码
Code(self.driver).main() # 调用识别验证码
button.click() # 点击登录界面
time.sleep(2)
cookie = self.driver.get_cookie('tk')
print(cookie)
with open('cookie.txt', 'w') as f:
f.write(str(cookie))
def login(self):
self.login_step() # 登录
while True:
if self.driver.current_url == self.login_success_url:
print('----------->登录成功')
self.driver.quit()
break
else:
print('----------->正在等待跳转')
if __name__ == '__main__':
login = Login(driver=webdriver.Chrome())
login.login()
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-image')
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):
pic_name = 'captcha.png'
response=requests.request("POST", self.verify_url, files={'pic_xxfile': open(pic_name, 'rb')})
time.sleep(5)
num = response.text.split('')[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()
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
# value_tostation = '%u65E0%u9521%u4E1C%2CWGH' # 终点站(无锡东)
# value_fromstation = '%u5357%u660C%u897F%2CNXG' # 始发站(南昌西)
value_fromstation = '%u65E0%u9521%u4E1C%2CWGH' # 终点站(无锡东)
value_tostation = '%u5357%u660C%u897F%2CNXG' # 始发站(南昌西)
class BuyTickets():
def __init__(self, driver,sit_type ,train, set_man_index, data):
self.driver = driver
self.login_url = 'https://kyfw.12306.cn/otn/login/init'
self.login_success_url = 'https://kyfw.12306.cn/otn/view/index.html'
self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
self.person_info_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
self.pay_page = 'https://kyfw.12306.cn/otn//payOrder'
self.train = train # 车次
self.set_man_index = set_man_index # 乘坐人是你默认的第几个位置
self.sit_type = sit_type # 一等座二等座等
self.data = data
def get_login_info(self):
with open('info.txt', 'r') as f:
lines = f.readlines()
username = lines[0].split()
password = lines[1].split()
f.close()
return [username, password]
def get_cookie(self):
with open('cookie.txt', 'r') as f:
cookie = f.read()
f.close()
print(cookie)
return eval(cookie)
def login_by_cookie(self):
self.driver.get(self.login_url)
self.driver.maximize_window() # 最大化
cookie = self.get_cookie()
self.driver.add_cookie(cookie)
self.driver.refresh()
while True:
if self.driver.current_url == self.login_success_url:
print('----------->登录成功')
break
else:
print('----------->正在等待跳转')
def search_tickets(self):
self.driver.get(self.ticket_url) # 点击订票网页
self.driver.add_cookie({"name": "_jc_save_fromStation", "value": value_fromstation}) # 出发站
self.driver.add_cookie({"name": "_jc_save_toStation", "value": value_tostation}) # 目的地
self.driver.add_cookie({"name": "_jc_save_fromDate", "value": self.data}) # 时间
self.driver.refresh() # 刷新
def buy_ticket(self):
i = 0
flag = True
while flag:
time.sleep(1)
WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH, '//a[@id="query_ticket"]')))
self.driver.find_element_by_id('query_ticket').click()
try: # 判断车次
WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH,"//a[text()='%s']" % self.train)))
except:
if self.driver.find_element_by_xpath("//p[text()='查询超时,请稍后再试!']"):
continue
else:
print('兄弟你是不是填错了车次了,没找到车次%s' % self.train)
flag = False
sit = {'商务座':'2', # 判断一等座二等座等
'一等座':'3',
'二等座':'4',
'高级软卧':'5',
'软卧一等卧':'6',
'动卧':'7',
'硬卧二等卧':'8',
'软座':'9',
'硬座':'10',
'无座':'11',
'其他':'12',
}
for name, value in sit.items():
if name == self.sit_type:
text = self.driver.find_element_by_xpath("//a[text()='%s']/../../../../../td[%s]" % (self.train, value)).text
print('你关注的票的状态是%s' % text)
if text == '*' or text == '无' or text == '候补':
continue
elif text == '--':
print('该车次没有这个座位类型吧')
flag = False
else:
book_button = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located(
(By.XPATH, "//a[text()='%s']/../../../../..//a[@class='btn72']" % self.train)))
book_button.click() # 点击预定
print('-------------------->抢到票了,正在进入填写乘客信息界面')
flag = False
i = i + 1
print('抢票%s次' %i)
while True:
if self.driver.current_url == self.person_info_url:
print('页面成功跳转到乘客信息界面')
break
else:
print('等待进入填写乘客信息界面....')
set_index = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH,"//input[@id='normalPassenger_%s']" % self.set_man_index)))
set_index.click() # 选中乘坐人的次序
self.driver.find_element_by_id('seatType_1') # 选择座位
self.driver.find_element_by_xpath("//option[contains(text(),'%s')]" % self.sit_type) # 选择
self.driver.find_element_by_xpath('//*[@id="submitOrder_id"]').click() # 提交订单
WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.XPATH, "//a[@class='btn92s' and @id='qr_submit_id']")))
self.driver.find_element_by_xpath("//a[@class='btn92s' and @id='qr_submit_id']").click()
print('成功抢票')
while True:
if self.pay_page in self.driver.current_url:
print('老铁,需要你付款了!')
break
else:
print('正在跳转到付款界面....')
def main(self):
self.login_by_cookie()
self.search_tickets()
self.buy_ticket()
if __name__ == '__main__':
# 分别填写“几等座”
# 车次
# 坐车的是在联系人里排第几
# 出发日期
buy = BuyTickets(webdriver.Chrome(),'二等座', 'G1377', '0', '2019-10-04')
begin = time.time()
buy.main()
end = time.time()
print('耗时%s' % (end-begin))
除此之外,还有info.txt文件,里面保存了自己12306里的用户名和密码,这里我就不贴出来了。。。
还有个cookie.txt文件,里面保存的是12306的登录cookie
前提条件:
1,不能输错火车车次
2,联系人排位置从0开始,不能输错
3,座位分一等座二等座还有硬座硬卧巴拉巴拉不能填错
4,此脚本没有选择学生座,也没有选ABCDE座位号
运行方式:
1,先运行login_for_cookie.py进行相关登录获取cookie
2,再运行BuyTocket.py进行抢票购票