春节临近了,小伙伴们都在忙着抢票了,很多人总是被各种乱七八糟的抢票程序误导,诱骗,不如自己用python写一个12306抢票脚本好了。

言归正传,有了需求自然就要实现。技术部分,抢票程序由selenium驱动chrome进行,主要分为几下几部分。(别问我为什么不直接用requests买,有点难0-0)

1.安装selenium和chromedriver

selenium包直接使用pip安装即可

    pip install selenium

安装chromedriver,进入http://chromedriver.storage.googleapis.com/index.htmlx下载最新内核,目前最新版本为2.45,下载解压缩并放在PATH下,windows直接放在C:/Windows/System32下,linux放在/usr/local/bin下即可,接下来使用下列python命令测试。 

    #!env python
    from selenium import webdriver
    import time
    browser = webdriver.Chrome()#如果不在环境变量中,括号里写上绝对路径也行
    browser.get("https://www.bobobk.com")
    print(u"5秒后关闭程序")
    time.sleep(5)
    browser.close() 

《python3搭配selenium实现12306抢票程序》

可以看到浏览器已经成功打开指定页面

2.selenium登陆12306抢票

直接上代码

    #######导入需要库
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    import time,re,requests,json,random

    ####基本信息
    username = u"username"
    password = u"password"
    from_station = u"鹰潭"
    to_station = u"上海"
    from_date = u"2019-02-13"
    order = 0
    student = "0X00"
    ticketer = u"yourname"
    login_url = "https://kyfw.12306.cn/otn/login/init"

    ########登录函数
    def login():
        global browser
        #点击当前页面的"登录"
        browser.get(login_url)
        time.sleep(1)
        if browser.current_url == login_url:
        #fill填充搜索框的内容,username。name=loginUserDTO.user_name的元素。
            browser.find_element_by_id("username").send_keys(username)
            browser.find_element_by_id("password").send_keys(password)

            print(u"等待验证码,自行输入...")
        #登录手动输入验证码,并登录系统fromStationText
            for i in range(30):
                time.sleep(5)
                if ticketer in browser.page_source :

                    return True
                    break
                i+=1
            return False
        else:
            return True
    #######主函数
    def main():

        log_or_not = login()
        while not log_or_not:
            log_or_not = login()

        browser.get("https://kyfw.12306.cn/otn/leftTicket/init")
        try:
            browser.find_element_by_id("fromStationText").click()
            browser.find_element_by_id("fromStationText").send_keys(Keys.BACKSPACE)
            browser.find_element_by_id("fromStationText").send_keys(from_station)
            browser.find_element_by_id("fromStationText").send_keys(Keys.ENTER)
            browser.find_element_by_id("toStationText").click()
            browser.find_element_by_id("toStationText").send_keys(Keys.BACKSPACE)
            browser.find_element_by_id("toStationText").send_keys(to_station)
            browser.find_element_by_id("toStationText").send_keys(Keys.ENTER)
        except:
            pass
        if student != "ADULT":
            browser.find_element_by_id("sf2").click()
        time.sleep(5)
        browser.find_element_by_id("query_ticket").click()
        time.sleep(2)
        ticket = re.findall(r'id="(ticket_\w{10,16})"',browser.page_source)

        che_list = []
        for i in ticket:
            che_list.append(re.search('([KGTZ]\d+\w+)',i).group(1)[:-2])
       #     print(browser.find_element_by_id("ZE_"+ i.split("_")[1]).text)
       #     print(browser.find_element_by_id("YW_"+ i.split("_")[1]).text)
        print("请选择你想要买的车次编号")
        my_car_list = ["G1346","G1584","G1350","G1370","G1390","G1322","G1378","G1388","G1372"]
        my_ticket = []
        for i in range(len(ticket)):
            for j in my_car_list:
                if j in ticket[i]:
                    my_ticket.append(ticket[i])
        print(my_ticket)
        count_query = 0
        while True:
            count_query += 1
            if count_query%500 == 0:
                browser.get("https://kyfw.12306.cn/otn/leftTicket/init")
            print("已经查询次数:%d" % count_query)
            try:
                if browser.current_url != "https://kyfw.12306.cn/otn/leftTicket/init":
                    browser.get("https://kyfw.12306.cn/otn/leftTicket/init")
                if student != "ADULT":
                    browser.find_element_by_id("sf2").click()
                browser.find_element_by_id("query_ticket").click()
                time.sleep(0.1)

                browser.execute_script("window.scrollTo(0,%d)" % (600+random.randint(0,100)))
                time.sleep(0.01)
                for i in my_ticket:
                #chec,i = i[1],i[0]
                    tic_num = i.split("_")[1]
               # print(tic_num)
    #########判断余票信息,我这里是买二等座,硬卧,硬座
                    ger = browser.find_element_by_id("ZE_"+tic_num).text !="--" and browser.find_element_by_id("ZE_"+tic_num).text!='无'

                    yingwo = browser.find_element_by_id("YW_"+tic_num).text !="--" and browser.find_element_by_id("YW_"+tic_num).text!='无'
                    yingzuo = browser.find_element_by_id("YZ_"+tic_num).text !="--" and browser.find_element_by_id("YZ_"+tic_num).text!='无'
                    if ger or yingwo or yingzuo:

                        print("if going here:%s" % tic_num)
                        browser.find_element_by_id(i).find_element_by_class_name("btn72").click()
                        time.sleep(0.01)
                        browser.find_element_by_id("normalPassenger_0").click()
                        time.sleep(0.01)
                        try:
                            if student=="ADULT":
                                browser.find_element_by_id("dialog_xsertcj_cancel").click()
                            else:
                                browser.find_element_by_id("dialog_xsertcj_ok").click()
                        except:
                            pass
                        browser.find_element_by_id("submitOrder_id").click()
                        time.sleep(0.01)
                        break

                browser.execute_script("var q=document.documentElement.scrollTop=0")
            except:
                pass
    #########打开浏览器抢票
    browser = webdriver.Chrome() 
    main()

《python3搭配selenium实现12306抢票程序》

总结

本程序使用selenium直接调用浏览器实现了12306刷票抢票的基本要求,在用户正确填写信息后就会自动刷新浏览器并在给定的车次和坐席间购买车票。

待提高:由于使用浏览器刷新,刷新频率受到js控制,想办法看能不能分流,在其他地方刷新页面,这里购买。后面会增加用户配置内容,而不是写进程序里,如果有其他建议,欢迎留言。