Recently, I am learning Python, so I wrote this script with Python to grab tickets for 12306, and share it with you. If there is something wrong, please correct it. Without further ado, to the point:

Before entering the topic, I would like to clarify that, due to the revision of 12306.cn, so the script has made a small change, the specific modified source code, you can go to GitHub above view… New script source

This script can only brush a car, the number of people can be multiple, support selection as a type, etc. The implementation idea is splinter. Browser simulates browser login and operation, because 12306 verification code is not automatic recognition, so, the verification code needs to be manually recognized by users, and login operation, after the matter, it can be handed over to the script operation, the following is some screenshots of my test time:

Step 1: Enter the basic information of ticket snatching as shown below



Step 2: Then enter the login page, need to manually enter the verification code, and click login operation



Step 3: After login, the page of ticket snatching will be automatically entered, as shown in the picture below



Finally: is to wait for the result of brushing tickets, as shown in the following picture, it is said that brushing tickets successfully, brushing tickets, will be SMS and email notification, please remember to pay in time to 12306, otherwise it will be robbed in vain.



Python operating environment: Python3.6 Modules used: re, splinter, time, sys, Httplib2, urllib, smtplib, email PIP install splinter The following code is the introduction of all modules used by this script:

import re
from splinter.browser import Browser
from time import sleep
import sys
import httplib2
from urllib import parse
import smtplib
from email.mime.text import MIMEText
Copy the code

To prepare the information before brushing, I mainly talk about the cookie value of the originating station and destination, because the city needs to be entered through the cookie value, and the cookie value can be accessed through 12306.cn. In the header of the request, the _jc_save_fromStation value is the cookie of the starting station. The value of _jc_save_toStation is the cookie of the destination, and then added to the cookie dictionary city_list of the city in the code. The key is the first letter of the city, and the value is in the form of the cookie value.

The login operation I simulate here will automatically fill in the account name and password of 12306. Of course, you can also change the account name and password in the open browser. The key codes are as follows:

def do_login(self):
    """Login function realization, manual identification verification code for login"""
    self.driver.visit(self.login_url)
    sleep(1)
    self.driver.fill('loginUserDTO.user_name', self.user_name)
    self.driver.fill('userDTO.password', self.password)
    print('Please enter the verification code... ')
    while True:
        ifself.driver.url ! = self.init_my_url: sleep(1)else:
            break
Copy the code

After login, is to control the various operations of the brush ticket processing, here, I will not paste the code, because the code is more, do not worry, in the end, I will post a complete code.

When the ticket is swiping successfully, I will make the double notification of SMS and email. Of course, the platform of SMS notification depends on which code you modify. I use the free SMS notification interface of the experience version of Huyi Wireless. I use SMtPLib to send mail module, and 163 mailbox to send mail server. If 163 mailbox is used, you have not set the client authorization password, remember to set the client authorization password first, it is very convenient. Here is the main implementation code:

def send_sms(self, mobile, sms_info):
    """Send a cell phone notification text message, using a test text message. - Wax wireless."""
    host = "106.ihuyi.com"
    sms_send_uri = "/webservice/sms.php? method=Submit"
    account = "C59782899"
    pass_word = "19d4d9c0796532c7328e8b82e2812655"
    params = parse.urlencode(
        {'account': account, 'password': pass_word, 'content': sms_info, 'mobile': mobile, 'format': 'json'}
    )
    headers = {"Content-type": "application/x-www-form-urlencoded"."Accept": "text/plain"}
    conn = httplib2.HTTPConnectionWithTimeout(host, port=80, timeout=30)
    conn.request("POST", sms_send_uri, params, headers)
    response = conn.getresponse()
    response_str = response.read()
    conn.close()
    return response_str

def send_mail(self, receiver_address, content):
    """Send email notification"""
    Connect to email server information
    host = 'smtp.163.com'
    port = 25
    sender = '[email protected]'  # Your sender email number
    pwd = '* * * * * *'  # not login password, is the client authorization password
    # Send a message
    receiver = receiver_address
    body = '

Reminder:

'

+ content + '</p>' msg = MIMEText(body, 'html', _charset="utf-8") msg['subject'] = 'Notice of success! ' msg['from'] = sender msg['to'] = receiver s = smtplib.SMTP(host, port) Start logging in to the mailbox and sending the email s.login(sender, pwd) s.sendmail(sender, receiver, msg.as_string()) Copy the code

Said so much, feeling is said a lot of nonsense ah, ha ha, sorry, delay your time to see me nonsense, I post everyone most concerned about the source code, please pick up the code, everyone in the process of trying to run, there is any problem, you can give me a message or private letter I, I see will be timely reply to you:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

"""You can use Splinter to swipe the 12306 train ticket to automatically fill in your account password. At the same time, you can also change your account password, manually identify the verification code, and log in. The rest of the work is done by the script. cuizy time: 2018-05-30 """

import re
from splinter.browser import Browser
from time import sleep
import sys
import httplib2
from urllib import parse
import smtplib
from email.mime.text import MIMEText


class BrushTicket(object):
    """Ticket categories and implementation methods"""

    def __init__(self, user_name, password, passengers, from_time, from_station, to_station, number, seat_type, receiver_mobile, receiver_email):
        """Define instance properties, initialize"""
        # 1206 Password of account
        self.user_name = user_name
        self.password = password
        # Passenger name
        self.passengers = passengers
        # Starting and ending stations
        self.from_station = from_station
        self.to_station = to_station
        # Travel date
        self.from_time = from_time
        # Train number
        self.number = number.capitalize()
        Td position of seat type
        if seat_type == 'Business Class':
            seat_type_index = 1
            seat_type_value = 9
        elif seat_type == 'First class':
            seat_type_index = 2
            seat_type_value = 'M'
        elif seat_type == 'Second class':
            seat_type_index = 3
            seat_type_value = 0
        elif seat_type == 'Superior Soft sleeper':
            seat_type_index = 4
            seat_type_value = 6
        elif seat_type == 'soft sleeper':
            seat_type_index = 5
            seat_type_value = 4
        elif seat_type == 'moving lie':
            seat_type_index = 6
            seat_type_value = 'F'
        elif seat_type == 'hard sleeper':
            seat_type_index = 7
            seat_type_value = 3
        elif seat_type == 'soft seat':
            seat_type_index = 8
            seat_type_value = 2
        elif seat_type == 'hard seat':
            seat_type_index = 9
            seat_type_value = 1
        elif seat_type == 'no seat':
            seat_type_index = 10
            seat_type_value = 1
        elif seat_type == 'other':
            seat_type_index = 11
            seat_type_value = 1
        else:
            seat_type_index = 7
            seat_type_value = 3
        self.seat_type_index = seat_type_index
        self.seat_type_value = seat_type_value
        # Notification message
        self.receiver_mobile = receiver_mobile
        self.receiver_email = receiver_email
        # Main page URL
        self.login_url = 'https://kyfw.12306.cn/otn/login/init'
        self.init_my_url = 'https://kyfw.12306.cn/otn/index/initMy12306'
        self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
        # browser driver information, driver download page: https://sites.google.com/a/chromium.org/chromedriver/downloads
        self.driver_name = 'chrome'
        self.executable_path = 'C:\\Users\cuizy\AppData\Local\Programs\Python\Python36\Scripts\chromedriver.exe'

    def do_login(self):
        """Login function realization, manual identification verification code for login"""
        self.driver.visit(self.login_url)
        sleep(1)
        self.driver.fill('loginUserDTO.user_name', self.user_name)
        self.driver.fill('userDTO.password', self.password)
        print('Please enter the verification code... ')
        while True:
            ifself.driver.url ! = self.init_my_url: sleep(1)else:
                break

    def start_brush(self):
        """Purchase ticket function realization"""
        self.driver = Browser(driver_name=self.driver_name, executable_path=self.executable_path)
        The size of the browser window
        self.driver.driver.set_window_size(900, 700)
        self.do_login()
        self.driver.visit(self.ticket_url)
        try:
            print('Start counting tickets... ')
            # Load ticket query information
            self.driver.cookies.add({"_jc_save_fromStation": self.from_station})
            self.driver.cookies.add({"_jc_save_toStation": self.to_station})
            self.driver.cookies.add({"_jc_save_fromDate": self.from_time})
            self.driver.reload()
            count = 0
            while self.driver.url.split('? ')[0] == self.ticket_url:
                self.driver.find_by_text('query').click()
                sleep(1)
                count += 1
                print('The %d click to query... ' % count)
                try:
                    car_no_location = self.driver.find_by_id("queryLeftTable")[0].find_by_text(self.number)[1]
                    current_tr = car_no_location.find_by_xpath(". /.. /.. /.. /.. /..")
                    if current_tr.find_by_tag('td')[self.seat_type_index].text == The '-':
                        print('No seat type for sale, current brushing has ended, please reopen! ')
                        sys.exit(1)
                    elif current_tr.find_by_tag('td')[self.seat_type_index].text == 'no':
                        print('No tickets, keep trying... ')
                    else:
                        # Tickets available, try to book
                        print('Tickets are counted (remaining votes:' + str(current_tr.find_by_tag('td')[self.seat_type_index].text) + ') and start trying to book... ')
                        current_tr.find_by_css('td.no-br>a')[0].click()
                        sleep(1)
                        key_value = 1
                        for p in self.passengers:
                            # Select user
                            print('Start selecting users... ')
                            self.driver.find_by_text(p).last.click()
                            # Select seat type
                            print('Start choosing seats... ')
                            ifself.seat_type_value ! = 0: seat_select = self.driver.find_by_id("seatType_" + str(key_value))[0]
                                seat_select.find_by_xpath("//option[@value='" + str(self.seat_type_value) + "']")[0].click()
                            key_value += 1
                            sleep(0.5)
                            if p[-1] == ') ':
                                self.driver.find_by_id('dialog_xsertcj_ok').click()
                        print('Placing orders... ')
                        self.driver.find_by_id('submitOrder_id').click()
                        sleep(2)
                        # check whether the result is normal
                        submit_false_info = self.driver.find_by_id('orderResultInfo_id')[0].text
                        ifsubmit_false_info ! =' ':
                            print(submit_false_info)
                            self.driver.find_by_id('qr_closeTranforDialog_id'Self). Click () sleep (0.2). The driver. Find_by_id ('preStep_id'). Click () sleep (0.3)continue
                        print('Confirming order... ')
                        self.driver.find_by_id('qr_submit_id').click()
                        print(Reservation successful, please pay in time...... ')
                        Send notification messages
                        self.send_mail(self.receiver_email, 'Congratulations, you have got the ticket, please go to 12306 to pay the order in time! ')
                        self.send_sms(self.receiver_mobile, 'Your verification code is 8888. Please do not divulge the captcha code to others. ')
                except Exception as error_info:
                    print(error_info)
        except Exception as error_info:
            print(error_info)

    def send_sms(self, mobile, sms_info):
        """Send a cell phone notification text message, using a test text message. - Wax wireless."""
        host = "106.ihuyi.com"
        sms_send_uri = "/webservice/sms.php? method=Submit"
        account = "C59782899"
        pass_word = "19d4d9c0796532c7328e8b82e2812655"
        params = parse.urlencode(
            {'account': account, 'password': pass_word, 'content': sms_info, 'mobile': mobile, 'format': 'json'}
        )
        headers = {"Content-type": "application/x-www-form-urlencoded"."Accept": "text/plain"}
        conn = httplib2.HTTPConnectionWithTimeout(host, port=80, timeout=30)
        conn.request("POST", sms_send_uri, params, headers)
        response = conn.getresponse()
        response_str = response.read()
        conn.close()
        return response_str

    def send_mail(self, receiver_address, content):
        """Send email notification"""
        Connect to email server information
        host = 'smtp.163.com'
        port = 25
        sender = '******@163.com'  # Your sender email number
        pwd = '* * * * * *'  # not login password, is the client authorization password
        # Send a message
        receiver = receiver_address
        body = '

Reminder:

'

+ content + '</p>' msg = MIMEText(body, 'html', _charset="utf-8") msg['subject'] = 'Notice of success! ' msg['from'] = sender msg['to'] = receiver s = smtplib.SMTP(host, port) Start logging in to the mailbox and sending the email s.login(sender, pwd) s.sendmail(sender, receiver, msg.as_string()) if __name__ == '__main__': # 12306 Username user_name = input('Please enter 12306 username:') while user_name == ' ': user_name = input('12306 username cannot be empty, please re-enter: ') # 12306 Login password password = input('Please enter 12306 login password:') while password == ' ': password = input('12306 Login password cannot be empty, please re-enter: ') # Passenger name passengers_input = input('Please enter the name of the passenger, and use the English comma ", "to connect, (e.g., single" John "or multiple" John ") :') passengers = passengers_input.split(",") while passengers_input == ' ' or len(passengers) > 4: print('At least one passenger, at most four! ') passengers_input = input('Please re-enter the name of the passenger, and use the English comma ", "to connect multiple passengers (e.g., single" John "or multiple" John ") :') passengers = passengers_input.split(",") # Travel date from_time = input('Please enter the date of travel (e.g. "2018-08-08") :') date_pattern = re.compile(r'^\d{4}-\d{2}-\d{2}$') while from_time == ' ' or re.findall(date_pattern, from_time) == []: from_time = input('Ride date cannot be empty or time format is incorrect, please re-enter:') # City Cookie Dictionary city_list = { 'bj': '%u5317%u4EAC%2CBJP'.# Beijing 'hd': '%u5929%u6D25%2CTJP'.# handan 'nn': '%u5357%u5B81%2CNNZ'.# nanning 'wh': '%u6B66%u6C49%2CWHN'.# wuhan 'cs': '%u957F%u6C99%2CCSQ'.# changsha 'ty': '%u592A%u539F%2CTYV'.# in taiyuan 'yc': '%u8FD0%u57CE%2CYNV'.# yuncheng 'gzn': '%u5E7F%u5DDE%u5357%2CIZQ'.# south guangzhou 'wzn': '%u68A7%u5DDE%u5357%2CWBZ'.# wuzhou south } # start from_input = input('Please enter the departure station, just enter the first letter (e.g. Beijing "BJ") :') while from_input not in city_list.keys(): from_input = input('Departure station cannot be empty or unsupported (please contact your administrator if necessary!) , please re-enter: ') from_station = city_list[from_input] # the terminal to_input = input('Please enter the destination, just enter the first letter (e.g. Beijing "BJ") :') while to_input not in city_list.keys(): to_input = input('Terminal cannot be empty or not supported by current terminal (please contact administrator if necessary!) , please re-enter: ') to_station = city_list[to_input] # Train number number = input('Please enter the train number (e.g.' G110 ') : ') while number == ' ': number = input('Train number cannot be empty, please re-enter:') # Seat type seat_type = input('Please enter seat type (e.g.' soft sleeper ') : ') while seat_type == ' ': seat_type = input('Seat type cannot be empty, please re-enter:') # Grab tickets successfully, notify the mobile phone number receiver_mobile = input('Please reserve a mobile phone number for notification (e.g. 18888888888) :') mobile_pattern = re.compile(r'^1{1}\d{10}$') while receiver_mobile == ' ' or re.findall(mobile_pattern, receiver_mobile) == []: receiver_mobile = input('Reserved mobile phone number cannot be empty or incorrectly formatted, please re-enter:') receiver_email = input('Please reserve an email address for notification (e.g. [email protected]) :') while receiver_email == ' ': receiver_email = input('Reserved mailbox cannot be empty, please re-enter:') # Start grabbing tickets ticket = BrushTicket(user_name, password, passengers, from_time, from_station, to_station, number, seat_type, receiver_mobile, receiver_email) ticket.start_brush() Copy the code