基于Selenium
和Chrome
浏览器实现。
默认抢票类型为普通票,硬座。需求多的话可以在源码里改,我写的注释挺详细。
复制粘贴就能使用,2019年8月13日 测试可用。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait,Select
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time,sys
class robTickets(object):
def __init__(self):
'登录页、主页、抢票页'
self.login_url="https://kyfw.12306.cn/otn/resources/login.html"
self.initmy_url="https://kyfw.12306.cn/otn/view/index.html"
self.search_url="https://kyfw.12306.cn/otn/leftTicket/init"
self.driver = webdriver.Chrome()
self.hastictket=False
def run(self):
self._login()
self._order_ticket()
def _login(self):
'登录页面手动登录'
self.driver.get(self.login_url)
time.sleep(1)
self.driver.find_element_by_class_name("login-hd-account").click()
username = input("请输入 用户名/手机号/邮箱 :")
password = input("请输入 密码:")
print("请在浏览器中完成验证码并确认")
self.driver.find_element_by_id("J-userName").send_keys(username)
self.driver.find_element_by_id("J-password").send_keys(password)
WebDriverWait(self.driver,1000).until(
EC.url_to_be(self.initmy_url)
)
print("登录成功!")
self._wait_input()
self._order_ticket()
def _wait_input(self):
self.from_station=input("请输入出发地:")
self.to_station=input("请输入目的地:")
self.depart_time=input("出发时间(yyy-mm-dd):")
def _order_ticket(self):
'选票页面手动选票,自动抢票'
self.driver.get(self.search_url)
self.url = "https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%s,BJP&ts=%s,SHH&date=%s&flag=N,N,Y"%(self.from_station,self.to_station,self.depart_time)
self.driver.get(self.url)
self.order_url="https://kyfw.12306.cn/otn/confirmPassenger/initDc"
WebDriverWait(self.driver,60).until(
EC.presence_of_all_elements_located((By.XPATH,"//tbody[@id='queryLeftTable']/tr"))
)
tr_list = self.driver.find_elements_by_xpath("//tbody[@id='queryLeftTable']/tr[not(@datatran)]")
print("共搜索到 "+str(len(tr_list))+" 条结果!")
self.passengers = input("请输入乘客姓名(多个乘客的话,用英文逗号隔开):").split(",")
self.trains = input("请输入车次(多个车次,用英文逗号隔开):").split(",")
# 循环检票
TNT = int(input("抢票监测时间(秒):"))
st = time.time()
i=0
while time.time()-st<TNT:
for tr in tr_list:
train_number = tr.find_element_by_class_name("number").text
if train_number in self.trains:
self.hastictket=True
ticket = tr.find_element_by_xpath(".//td[last()-3]").text
if ticket == "有" or ticket.isdigit():
print(train_number+" "+ticket+" 票")
tr.find_element_by_class_name("btn72").click()
self._money()
if self.hastictket==False:
print("未查询到相关班次!")
self.driver.quit()
sys.exit()
# 未找到票,刷新界面
self.driver.refresh()
tr_list = self.driver.find_elements_by_xpath("//tbody[@id='queryLeftTable']/tr[not(@datatran)]")
WebDriverWait(self.driver, 60).until(
EC.presence_of_all_elements_located((By.XPATH, "//tbody[@id='queryLeftTable']/tr"))
)
i+=1
print("抢票第 %d 次"%i)
def _money(self):
'支付界面自动下单'
WebDriverWait(self.driver, 60).until(
EC.url_to_be(self.order_url)
)
WebDriverWait(self.driver, 60).until(
EC.presence_of_all_elements_located((By.XPATH, "//ul[@id='normal_passenger_id']//li"))
)
lis = self.driver.find_elements_by_xpath("//ul[@id='normal_passenger_id']//li")
x = 0
for li in lis:
# 遍历联系人寻找乘客
if li.find_element_by_xpath("./label").text in self.passengers:
li.find_element_by_xpath("./input[@class='check']").click()
x += 1
WebDriverWait(self.driver, 1000).until(
EC.visibility_of_element_located((By.ID, "seatType_%d" % x))
)
# 此处value为1代表硬座,修改此处可以更改票的类型
selectTag = Select(self.driver.find_element_by_id("seatType_%d" % x))
selectTag.select_by_value("1")
print("正在提交订单,请等待60s...")
self.driver.find_element_by_id("submitOrder_id").click()
WebDriverWait(self.driver, 20).until(
EC.element_to_be_clickable((By.ID, "qr_submit_id"))
)
# 提交并检查订单,此处限时60s
start = time.time()
while time.time() - start < 60:
try:
self.driver.find_element_by_xpath(r"//a[@id='qr_submit_id']").click()
except:
if self.driver.current_url != self.order_url:
print("订单已完成,请打开12306完成支付!")
time.sleep(1000)
else:
if self.driver.find_element_by_xpath(r"//div[@class='tit']").text == "下单成功。":
print("订单已完成,请打开12306完成支付!")
self.driver.get("https://kyfw.12306.cn/otn/view/train_order.html")
time.sleep(1000)
else:
time.sleep(0.1)
if __name__=='__main__':
print("本程序默认抓取的是普通票,硬座,想实现更多功能请在源码里修改")
spider = robTickets()
spider.run()
运行截图: