python12306买票_Python 使用 selenium 实现半自动购买12306火车票

实现原理:

1. 使用 selenium 模拟自动打开 chrome浏览器;

2. (浏览器打开后)会自动填写账号密码,手动选择验证码并提交;

3. 自动跳转选择“预定”及其单程购票设置;

4. 循环查询余票:先按顺序查询所有车次二等座,没有再按顺序查询无座,如此循环;

5. 发现余票后自动预定,并选择第一个乘客提交订单。

注意:提交订单后若没有余票,不会自动返回(没写完整)。此外,如果失败,又得重头再来,尝试多次频繁登录会导致账号短时间内不能登录。

验证码功能虽然没有实现,不过也大概了解了其验证原理:

验证码图片实为一张图(如下图),图片是动态的,地址为:

该图片分上下两块区域:上部分为文字,下部分为各图片组合。(可判断这图片是固定的,可爬取所有验证码下来做自动识别)

当我们点选下面的答案中的小图时,页面脚本会识别选择点的像素位置,生成一个 div 标签行,添加到表单中(即添加在验证码图片div内),如下图。

点击登录,首先进行验证码校验,后台有相应的接口来返回验证结果,校验成功才进行登录表单提交。

暂时只能人工识别验证码,主要是速度快,方便自己而已。如果需要特定的其他查询选择,则需要更完善些。这里没有这么完善。

#-*- coding: utf-8 -*-

# python 3.5.0

import re

import time

from selenium import webdriver

from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

class Main(object):

def __init__(self):

self.username = "账号"

self.password = "密码"

self.fromStation = "深圳"

self.toStation = "南宁"

self.train_date = "2018-02-14"

self.train = ['G2912','G2914','G2916'] #优先顺序

self.loginurl = "https://kyfw.12306.cn/otn/login/init"

#_chromedriver = "D:/Python35/selenium/phantomjs/bin/phantomjs.exe"

#driver = webdriver.PhantomJS(_chromedriver)

self.chromedriver = 'D:/Python35/selenium/webdriver/chromedriver/chromedriver.exe'

self.driver = webdriver.Chrome(self.chromedriver)

def setUrl(self,url):

self.loginurl = url

def getUrl(self):

print("[0]打开浏览器")

self.driver.get(self.loginurl)

time.sleep(2)

def setUserPwd(self):

print("[1]设置登录账号")

self.driver.find_element_by_id("username").send_keys(self.username)

self.driver.find_element_by_id("password").send_keys(self.password)

#此处在浏览器界面手动点击验证码并登录!

def waitingNewPage(self):

print("[2]请手动点击登录")

while self.loginurl == self.driver.current_url:

print("[*]login waiting……")

time.sleep(3)

def selectYuding(self):

print("[3]点击车票预订")

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID,'selectYuding'))).click()

time.sleep(1)

def selectOptions(self):

print("[4]点击单程")

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID,'dc_label'))).click()

print("[5]点击普通票")

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID,'query_ticket'))).click()

def setQueryLeftForm(self):

print("[6]设置信息")

#出发地

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID,'fromStation_icon_image'))).click()

self.driver.find_element_by_xpath("//li[@title='%s'][@data='SZQ']" % self.fromStation).click()

#目的地

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID,'toStation_icon_image'))).click()

self.driver.find_element_by_xpath("//li[@title='%s'][@data='NNZ']" % self.toStation).click()

#出发日

year = self.train_date.split('-')[0]

month = self.train_date.split('-')[1]

day = self.train_date.split('-')[2]

y = 4 if year == "2017" else 5 if year == "2018" else 6

#m = int(month) - 1

#d = int(day)-1

m = int(month)

d = int(day)

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID,'date_icon_1'))).click()

self.driver.find_element_by_xpath("//div[@class='year']/input").click()

self.driver.find_element_by_xpath("//div[@class='year']/div/ul/li[%s]" % y).click()

self.driver.find_element_by_xpath("//div[@class='month']/input").click()

self.driver.find_element_by_xpath("//div[@class='month']/ul/li[%s]" % m).click()

self.driver.find_element_by_xpath("//div[@class='cal']/div[@class='cal-cm']/div[%s]/div" % d).click()

def queryTicket(self):

print("[7]点击查询")

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID,'query_ticket'))).click()

time.sleep(1)

#总车次数

def getTraiNum(self):

#self.driver.find_element_by_xpath("//div[@class='sear-result']/p[1]/strong[2]").text.strip()

return self.driver.find_element_by_id('trainum').text.strip()

def click(self,xpath):

self.driver.find_element_by_xpath(xpath).click()

def checkTicket(self,tx,zuo,name):

#是否是自己选择的车次,是则检查是否有二等座,有则预订

for t in self.train:

if re.match(t, tx):

if zuo == "--" or zuo == "无":

pass

else:

print("【可预订车次】%s [%s]" % (tx,name))

return 1

else:

pass

return 0

#遍历车次

def checkTicketAll(self):

click_xpath = ""

mark = 0

trainum = self.getTraiNum()

print("【共计 %s 个车次】" % trainum)

id = 1

while id <= 2*int(trainum): #第一次遍历所有车次的二等座

xpath = "//tbody[@id='queryLeftTable']/tr[%s]" % id

tx = self.driver.find_element_by_xpath(xpath + "/td[1]").text.strip().replace('\n', ',') #车次信息

ze = self.driver.find_element_by_xpath(xpath + "/td[4]").text.strip() #二等座

mk = self.checkTicket(tx,ze,"二等座")

click_xpath = xpath + "/td[13]/a"

id = id + 2

if mk == 1:

mark = 1

return mark,click_xpath

id = 1

while id <= int(trainum): #第二次遍历所有车次的无座

xpath = "//tbody[@id='queryLeftTable']/tr[%s]" % id

tx = self.driver.find_element_by_xpath(xpath + "/td[1]").text.strip().replace('\n', ',') #车次信息

wz = self.driver.find_element_by_xpath(xpath + "/td[11]").text.strip() #无座

mk = self.checkTicket(tx,wz,"无座")

click_xpath = xpath + "/td[13]/a"

id = id + 2

if mk == 1:

mark = 1

return mark,click_xpath

return mark,click_xpath

def checkTicketLoop(self):

click_xpath = ""

mark = 0

mark,click_xpath = self.checkTicketAll()

while mark == 0:

self.queryTicket()

time.sleep(2) #几秒刷新一次??

mark,click_xpath = self.checkTicketAll()

print("--------------------------------------------------")

#点击预订

if mark == 1:

print("[8]点击预定")

self.click(click_xpath)

#选择乘客,提交订单

def submitOrder(self):

try:

print("[9]选择乘客")

passenger = WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.ID, 'normalPassenger_0')))

passenger.click()

print("[10]提交订单")

submit = WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.ID, 'submitOrder_id')))

submit.click()

except TimeoutException:

print("Loading took too much time!")

time.sleep(1)

#检查余票

def checkTicketNum(self):

ze = self.driver.find_element_by_xpath("//p[@id='sy_ticket_num_id']/strong[1]").text.strip()

wz = self.driver.find_element_by_xpath("//p[@id='sy_ticket_num_id']/strong[1]").text.strip()

if int(ze) == 0 and int(wz) == 0 :

return 0

else:

return 1

def submitOrderConfirm(self):

print("[11]确认提交订单!")

self.driver.find_element_by_id("qr_submit_id").click()

if __name__ == "__main__":

main = Main()

sub = 0

#main.setUrl("https://kyfw.12306.cn/otn/leftTicket/init")

main.getUrl()

main.setUserPwd()

main.waitingNewPage()

main.selectYuding()

main.selectOptions()

main.setQueryLeftForm()

main.queryTicket()

main.checkTicketLoop()

main.submitOrder() #订单提交

sub = main.checkTicketNum()

while sub == 0:

print("[11]返回修改~")

main.setUrl("https://kyfw.12306.cn/otn/leftTicket/init")

main.getUrl()

main.selectYuding()

main.selectOptions()

main.setQueryLeftForm()

main.queryTicket()

main.checkTicketLoop()

main.submitOrder() #订单提交

sub = main.checkTicketNum()

if sub == 1:

main.submitOrderConfirm() #确认订单提交

"""

while True:

time.sleep(5)

"""

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值