基于Python2.7实现的2017年春运抢票脚本

文章首发:我的博客

又到一年一度春运大会,2017年春运抢火车票还是那么难,各大互联网公司都推出抢票服务,只要加钱给服务费就可以增加抢到票的几率,有些代售火车票点,说给100元服务费,可以帮抢到,看来这水很深啊!

下面我们利用自己学的技术来自动抢票,本次脚本基于Python2.7+selenium来实现

首先介绍一下selenium的使用

selenium操作chrome浏览器需要有ChromeDriver驱动来协助。
什么是ChromeDriver?
ChromeDriver是Chromium team开发维护的,它是实现WebDriver有线协议的一个单独的服务。ChromeDriver通过chrome的自动代理框架控制浏览器,ChromeDriver只与12.0.712.0以上版本的chrome浏览器兼容。
那么要想selenium成功的操作chrome浏览器需要经历如下步骤:

  • 1、下载ChromeDriver驱动包(下载地址: http://chromedriver.storage.googleapis.com/index.htmlpath=2.7/
    注意阅读note.txt下载与自己所使用浏览器一致版本的驱动包。
  • 2、指定ChromeDriver所在位置和设置环境变量
    1)把ChromeDriver.exe放到Chrome浏览器的安装位置application的目录下
    2)通过配置ChromeDriver.exe位置到path环境变量实现。

实现思路

1.流程分析
  • 首先我们要登录12306网站,登录的时候遇到很蛋疼的图片验证码,然后选择出发地点和目的地点,接着选择时间,选择车次类型,然后查询,再选择班次购票,选择乘车人,提交订单,再次选择蛋疼的图片验证码。最后才会帮我们锁住座位。** 按照这样的流程手动点击走下来,估计票都没有了🤣**
2.预期实现目标
  • 整个流程全自动,实现自动登录,自动查询,自动订票,自动提交订单** (暂时不实现自动点击验证码,验证码成功几率比较低,所以暂时不集成进去,可以参考破解12306验证码)**
3.实现代码
  • 抢票代码
# -*- coding: utf-8 -*-
'''2017年春运火车票抢票
火车票预订时间对照:
1月25日(廿八) 12月27日
1月26日(廿九) 12月28日
1月27日(除夕) 12月29日
2月1日(初四)1月3日
2月2日(初五)1月4日
2月3日(初六)1月5日
2月4日(初七)1月6日
'''

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait  # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC  # available since 2.26.0
import time

value_fromstation = '%u6DF1%u5733%u5317%2CIOQ'  # 始发站(深圳北)
value_tostation = '%u4E91%u6D6E%u4E1C%2CIXQ'  # 终点站(云浮东)
value_date = '2017-01-25'  # 出发时间


def login_proc(username, password):
    # 打开登录页面
    sel = webdriver.Chrome('C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe')
    # sel=webdriver.Firefox()
    sel.implicitly_wait(30)
    login_url = 'https://kyfw.12306.cn/otn/login/init'
    sel.get(login_url)
    # sign in the username
    try:
        user_input = sel.find_element_by_id("username")
        user_input.clear()
        user_input.send_keys(username)
        print 'user-id write success!'
    except:
        print 'user-id write error!'
    # sign in the pasword
    try:
        pwd_input = sel.find_element_by_id("password")
        pwd_input.clear()
        pwd_input.send_keys(password)
        print 'pw write success!'
    except:
        print 'pw write error!'

    # Check for Login success
    while True:
        curpage_url = sel.current_url
        if curpage_url != login_url:
            if curpage_url[:-1] != login_url:  # choose wrong verify_pic
                print 'Login finished!'
                break
        else:
            time.sleep(5)
            print u'------------>等待用户图片验证'
    return sel


def search_proc(sel, train_type='', timer=False):
    print u'--------->选择车次类型', train_type
    # 定时抢票时间点
    if timer == True:
        while True:
            current_time = time.localtime()
            if ((current_time.tm_hour == 14) and (current_time.tm_min >= 25) and (
                        current_time.tm_sec >= 00)):
                print u'开始刷票...'
                break
            else:
                time.sleep(5)
                if current_time.tm_sec % 30 == 0:
                    print time.strftime('%H:%M:%S', current_time)

    # 打开订票网页
    book_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
    sel.get(book_url)
    # 始发站
    # sel.find_element_by_id('fromStationText').click()
    # from_station = sel.find_element_by_xpath('//*[@id="ul_list1"]/li[32]') # 深圳
    # from_station.click()
    sel.add_cookie({"name": "_jc_save_fromStation", "value": value_fromstation})
    # 终点站
    # sel.find_element_by_id('toStationText').click()
    # sel.find_element_by_id('nav_list3').click()#点击事件
    # tation = sel.find_element_by_xpath('//*[@id="ul_list1"]/li[9]') # 广州
    # to_station.click()
    sel.add_cookie({"name": "_jc_save_toStation", "value": value_tostation})
    # 出发日期
    # date_sel = sel.find_element_by_id('train_date')
    # js = "document.getElementById('train_date').removeAttribute('readonly')" # del train_date readonly property
    # sel.execute_script(js)
    # date_sel.clear()
    # date_sel.send_keys(leave_date)
    sel.add_cookie({"name": "_jc_save_fromDate", "value": value_date})
    sel.refresh()
    # 车次类型选择
    train_type_dict = {'T': '//input[@name="cc_type" and @value="T"]',  # 特快
                       'G': '//input[@name="cc_type" and @value="G"]',  # 高铁
                       'D': '//input[@name="cc_type" and @value="D"]',  # 动车
                       'Z': '//input[@name="cc_type" and @value="Z"]'}  # 直达
    if train_type == 'T' or train_type == 'G' or train_type == 'D' or train_type == 'Z':
        sel.find_element_by_xpath(train_type_dict[train_type]).click()
    else:
        print u"车次类型异常或未选择!(train_type=%s)" % train_type


def book_proc(sel, refresh_interval=0):
    # 等待状态查询
    query_times = 0
    time_begin = time.time()
    while True:
        # 循环查询
        time.sleep(refresh_interval)
        # 开始查询 @id="ZE_6c000D281201"
        search_btn = WebDriverWait(sel, 10).until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="query_ticket"]')))
        search_btn.click()
        # 扫描查询结果
        try:
            # T17
            tic_tb_item = WebDriverWait(sel, 20).until(
                EC.presence_of_element_located((By.XPATH, '//*[@id="ZE_6i000G291204"]')))
            # G381
            # tic_tb_item = WebDriverWait(sel,20).until(EC.presence_of_element_located((By.XPATH, '//*[@id="ZE_240000G38107"]')))
            tic_ava_num = tic_tb_item.text
        except:  # 应对查询按钮一次点击后,网站未返回查询结果
            search_btn.click()
            # T17
            tic_tb_item = WebDriverWait(sel, 5).until(
                EC.presence_of_element_located((By.XPATH, '//*[@id="ZE_6i000G291204"]')))
            # G381
            # tic_tb_item = WebDriverWait(sel,20).until(EC.presence_of_element_located((By.XPATH, '//*[@id="ZE_240000G38107"]')))
            tic_ava_num = tic_tb_item.text

        if tic_ava_num == u'无' or tic_ava_num == u'*':  # 无票或未开售
            query_times += 1
            time_cur = time.time()
            print u'第%d次查询,总计耗时%s秒' % (query_times, time_cur - time_begin)
            continue
        else:
            # 订票 @id="ticket_6c000D281201"
            sel.find_element_by_xpath('//*[@id="6i000G291204_IOQ_IXQ"]/td[13]/a').click()  # T17
            # sel.find_element_by_xpath('//*[@id="ticket_240000G38107"]/td[13]/a').click()  # G381
            break
    # 判断页面跳是否转至乘客选择页面
    cust_sel_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
    while True:
        if (sel.current_url == cust_sel_url):
            print u'页面跳转成功!'
            break
        else:
            print u'等待页面跳转...'
    # 乘车人选择
    while True:
        try:
            # sel.find_element_by_xpath('//*[@id="normalPassenger_0"]').click()
            sel.find_element_by_xpath('//*[@id="normalPassenger_1"]').click()
            break
        except:
            print u'等待常用联系人列表...'

    # 席别选择
    # 提交订票
    sel.find_element_by_xpath('//*[@id="submitOrder_id"]').click()
    # 确认订票信息
    while True:
        try:
            sel.switch_to.frame(sel.find_element_by_xpath('//*[@id="body_id"]/iframe[2]'))
            print
            sel.find_element_by_xpath('//*[@id="qr_submit_id"]').click()
            print 'Pass!'
            break
        except:
            print u'请手动通过图片验证码'
            time.sleep(5)
            break
    return 'yeah'


if __name__ == '__main__':
    # 变量定义
    leave_date = '2016-12-23'
    train_type = 'G'
    refresh_interval = 0.1
    timer = False

    sel = login_proc('****************', '***********')
    search_proc(sel, train_type, timer)
    book_proc(sel, refresh_interval)
  • 全局配置
#-*- coding: utf-8 -*-
# 对抗12306多次查询后,会出现服务器繁忙问题

from auto_book import login_proc,search_proc,book_proc
import configparser

config=configparser.ConfigParser()
config.read('user.cfg')

result = 'gogogo'
username=config.get('user','username')
password=config.get('user','password')
begin_time = '15:35:00'
refresh_interval = 0.1
timer=False
type='G'

for i in range(1,5):
    if result == 'gogogo':
        try:
            sel = login_proc(username,password)
            search_proc(sel,type,timer)
            book_proc(sel,refresh_interval)
        except:
            continue
    else:
        print result
        break

  • 配置登录个人信息
[user]
username = yourname(输入你的账号)
password = yourpassword(输入你的密码)
4.使用
  • 下载ChromeDrive并放到正确位置和配置好环境变量
  • 安装selenium模块
    pip install selenium
  • uesr.cfg文件配置个人信息
  • auto_book.py修改乘车始点站、终点站,乘车时间
  • wrapper.py设置车次类型和是否定时抢票
  • 最后运行python wrapper.py

** 项目地址**

** 更多文章请关注我的blog:https://karmalove.github.io/ **

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容