12306

作者: 52_St | 来源:发表于2018-02-05 15:54 被阅读203次
    • train.py
    import configparser
    import json
    import os
    import re
    import time
    from urllib.parse import quote
    from urllib.parse import unquote
    
    import requests
    
    from my_12306.captcha import jsdati
    
    '''
    创建一个火车类
    '''
    
    
    class Train:
    
        def __init__(self):
            # 加载配置文件
            self.__conf = configparser.ConfigParser()
            self.__conf.read('conf.ini', encoding='utf-8')
            # 出发地
            self.__from_station = self.__conf.get('ticket', 'from_station')
            # 目的地
            self.__to_station = self.__conf.get('ticket', 'to_station')
            # 出发日
            self.__train_date = self.__conf.get('ticket', 'train_date')
            # 车站代码 截止2018-05-14 版本号: 1.9053
            with open('station_code.json', 'r', encoding='utf-8') as f:
                self.__station_code = json.load(f)
            self.img_path = os.path.join(os.path.dirname(__file__), 'code.png')
            # 模拟浏览器
            self.__headers = {
                'User-Agent': self.__conf.get('headers', 'user_agent'),
                'Referer': self.__conf.get('headers', 'referer'),
                'Host': self.__conf.get('headers', 'host'),
            }
            # 禁用警告
            requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
            # 创建 Session
            self.__TicketSession = requests.Session()
            self.__TicketSession.headers = self.__headers
            self.__TicketSession.verify = False
    
            self.__seat_type = '1'
    
        def get_train(self):
            temp_str = self.__TicketSession.get('https://kyfw.12306.cn/otn/leftTicket/init').text
            pre_url = re.compile("CLeftTicketUrl = '(.*?)'").search(temp_str).group(1)
            get_train_url = 'https://kyfw.12306.cn/otn/{}'.format(pre_url)
            get_train_params = {
                'leftTicketDTO.train_date': self.__train_date,
                'leftTicketDTO.from_station': self.__station_code[self.__from_station],
                'leftTicketDTO.to_station': self.__station_code[self.__to_station],
                'purpose_codes': 'ADULT'
            }
            response = self.__TicketSession.get(url=get_train_url, params=get_train_params)
            if response.status_code == 200:
                return response.json()
    
        def query_ticket_info(self):
            js_info = self.get_train()
            if not js_info['status']:
                print('65 -> 查询余票失败!')
                return
            trains_list = js_info['data']['result']
            for i in trains_list:
                lst = i.split('|')
                if lst[11] != 'Y':
                    continue
                with open('conf.ini', 'w', encoding='utf-8') as f:
                    self.__conf.set('query_ticket_info', 'secretstr', unquote(lst[0]))
                    self.__conf.set('query_ticket_info', 'train_no', lst[2])
                    self.__conf.set('query_ticket_info', 'station_train_code', lst[3])
                    self.__conf.set('query_ticket_info', 'leftticket', unquote(lst[12]))
                    self.__conf.set('query_ticket_info', 'location_code', lst[15])
                    self.__conf.write(f)
                return
    
        def init_dc(self):
            url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
            data = {
                '_json_att': '',
            }
            response = self.__TicketSession.post(url=url, data=data)
            if response.status_code == 200:
                html = response.text
                # 获取REPEAT_SUBMIT_TOKEN
                regex = re.compile("var globalRepeatSubmitToken = '(\w+)'")
                repeat_submit_token = re.findall(regex, html)[0]
                # 获取key_check_isChange
                key_check_is_change = re.findall("key_check_isChange':'(\w+)','leftDetails'", html)[0]
                with open('conf.ini', 'w', encoding='utf-8') as f:
                    self.__conf.set('special', 'repeat_submit_token', repeat_submit_token)
                    self.__conf.set('special', 'key_check_ischange', key_check_is_change)
                    self.__conf.write(f)
    
        def get_passenger(self):
            url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'
            data = {
                '_json_att': '',
                'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
            }
            response = self.__TicketSession.post(url=url, data=data)
            # if response.status_code == 200:
            #     result = response.json()
            #     return result['data']['normal_passengers']
    
        def get_img(self):
            """
           获取验证码图片 -> 保存图片
           """
            img_url = 'https://kyfw.12306.cn/passport/captcha/captcha-image'
            img_data = {
                'login_site': 'E',
                'module': 'login',
                'rand': 'sjrand',
            }
            response = self.__TicketSession.get(url=img_url, params=img_data)
            if response.ok:
                with open(self.img_path, 'wb') as f:
                    f.write(response.content)
    
        def check_img(self):
            """
            利用打码平台自动识别验证码
            验证码正确 -> 执行 登陆
            验证码错误 -> 重新获取验证码图片
            """
            # 利用打码平台自动识别验证码
            self.get_img()
            print('正在识别验证码...')
            code = jsdati.decode(self.img_path)
            print(code)
            check_img_url = 'https://kyfw.12306.cn/passport/captcha/captcha-check'
            check_img_data = {
                'answer': code,
                'login_site': 'E',
                'rand': 'sjrand'
            }
            response = self.__TicketSession.post(url=check_img_url, data=check_img_data)
            if response.status_code == 200:
                result = response.json()
                print('146 - >', result['result_message'])
                if result['result_code'] == '4':
                    self.login()
                elif result['result_code'] == -4:
                    exit(1)
                else:
                    jsdati.report_error()
                    time.sleep(1)
                    self.check_img()
    
        def login(self):
            """
            登陆12306
            登陆成功 -> 执行 验证登陆
            """
            login_url = 'https://kyfw.12306.cn/passport/web/login'
            login_data = {
                'username': self.__conf.get('user_info', 'username'),
                'password': self.__conf.get('user_info', 'password'),
                'appid': 'otn',
            }
            response = self.__TicketSession.post(url=login_url, data=login_data)
            if response.status_code == 200:
                response.encoding = 'utf-8'  # 这里必须加, 否则抛出异常 JSONDecodeError
                result = response.json()
                print('170  ->', result['result_message'])
                if result['result_code'] == 0:
                    self.check_login()
    
        def check_login(self):
            """
            验证登陆 -> 验证通过 newapptk -> 验证通过 username=自己的姓名 -> 再次 检测登陆
            :return:
            """
            check_login_url = 'https://kyfw.12306.cn/passport/web/auth/uamtk'
            check_login_data = {
                'appid': 'otn'
            }
            response = self.__TicketSession.post(url=check_login_url, data=check_login_data)
            if response.status_code == 200:
                result = response.json()
                print('186  ->', result['result_message'])
                if result['result_code'] == 0:
                    newapptk = result['newapptk']
                    check_login_url = 'https://kyfw.12306.cn/otn/uamauthclient'
                    check_login_data = {
                        'tk': newapptk
                    }
                    response = self.__TicketSession.post(url=check_login_url, data=check_login_data)
                    if response.status_code == 200:
                        print('195  ->', result['result_message'])
                        if result['result_code'] == 0:
                            self.check_user()
    
        def check_user(self):
            """
            检查用户登陆 -> 提交订单请求
            """
            check_user_url = 'https://kyfw.12306.cn/otn/login/checkUser'
            check_user_data = {
                '_json_att': ''
            }
            response = self.__TicketSession.post(url=check_user_url, data=check_user_data)
            if response.status_code == 200:
                result = response.json()
                if result['status']:
                    print('211  ->', result)
                    self.submit_order_request()
    
        def submit_order_request(self):
            self.query_ticket_info()
            url = 'https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest'
            data = {
                'secretStr': self.__conf.get('query_ticket_info', 'secretstr'),
                'train_date': self.__train_date,
                'back_train_date': time.strftime('%Y-%m-%d'),
                'tour_flag': 'dc',
                'purpose_codes': 'ADULT',
                'query_from_station_name': self.__from_station,
                'query_to_station_name': self.__to_station,
                'undefined': '',
            }
            response = self.__TicketSession.post(url=url, data=data)
            if response.status_code == 200:
                result = response.json()
                if result['status']:
                    print('231  ->', result)
                    self.check_order_info()
    
        def check_order_info(self):
            self.init_dc()
            # self.get_passenger()
            url = 'https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo'
            data = {
                'cancel_flag': '2',  # 固定值
                'bed_level_order_num': '000000000000000000000000000000',  # 固定值
                # passengerTicketStr 和oldPassengerStr 均为旅客信息字符串, 不要含有空格
                # 座位编号,0,票类型,乘客名,证件类型,证件号,手机号码,保存常用联系人(Y或N)
                'passengerTicketStr': self.__conf.get('passenger', 'passengerticketstr'),
                # 乘客名,证件类型,证件号,乘客类型
                'oldPassengerStr': self.__conf.get('passenger', 'oldpassengerstr'),
                'tour_flag': 'dc',
                'randCode': '',
                'whatsSelect': '1',
                '_json_att': '',
                'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
            }
            response = self.__TicketSession.post(url=url, data=data)
            if response.status_code == 200:
                result = response.json()
                if result['status']:
                    print('255  ->', result)
                    self.get_queue_count()
    
        def get_queue_count(self):
            url = 'https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount'
            tmp = time.strftime('%a %b %d %Y 00:00:00 %z', time.strptime(self.__train_date, '%Y-%m-%d')).split('+')
            data = {
                'train_date': tmp[0] + 'GMT+' + tmp[1] + ' (中国标准时间)',
                'train_no': self.__conf.get('query_ticket_info', 'train_no'),
                'stationTrainCode': self.__conf.get('query_ticket_info', 'station_train_code'),
                'seatType': self.__seat_type,
                'fromStationTelecode': self.__station_code[self.__from_station],
                'toStationTelecode': self.__station_code[self.__to_station],
                'leftTicket': quote(self.__conf.get('query_ticket_info', 'leftticket')),
                'purpose_codes': '00',
                'train_location': self.__conf.get('query_ticket_info', 'location_code'),
                '_json_att': '',
                'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
            }
            response = self.__TicketSession.post(url=url, data=data)
            if response.status_code == 200:
                result = response.json()
                if result['status']:
                    print('278  ->', result)
                    self.confirm_single_for_queue()
    
        def confirm_single_for_queue(self):
            url = 'https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue'
            data = {
                'passengerTicketStr': self.__conf.get('passenger', 'passengerticketstr'),
                'oldPassengerStr': self.__conf.get('passenger', 'oldpassengerstr'),
                'randCode': '',
                'purpose_codes': '00',
                'key_check_isChange': self.__conf.get('special', 'key_check_ischange'),
                'leftTicketStr': quote(self.__conf.get('query_ticket_info', 'leftticket')),
                'train_location': self.__conf.get('query_ticket_info', 'location_code'),
                'choose_seats': '',
                'seatDetailType': '000',
                'whatsSelect': '1',
                'roomType': '00',
                'dwAll': 'N',
                '_json_att': '',
                'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
            }
            response = self.__TicketSession.post(url=url, data=data)
            if response.status_code == 200:
                result = response.json()
                if result['status']:
                    print('303  ->', result)
                    self.query_wait_time()
    
        def query_wait_time(self):
            url = 'https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime'
            data = {
                'random': int(time.time() * 1000),
                'tourFlag': 'dc',
                '_json_att': '',
                'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
            }
            response = self.__TicketSession.get(url=url, params=data)
            if response.status_code == 200:
                result = response.json()
                if result['status']:
                    print('318  ->', result)
                    # response = self.__TicketSession.get(url=url, params=data)
                    # if response.status_code == 200:
                    #     result = response.json()
                    #     if result['status']:
                    #         print('323  ->', result['data']['orderId'])
                    #         self.result_order_for_queue(result['data']['orderId'])
    
        def result_order_for_queue(self, order_sequence_no):
            url = 'https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue'
            data = {
                'orderSequence_no': order_sequence_no,
                '_json_att': '',
                'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
            }
            response = self.__TicketSession.post(url=url, data=data)
            if response.status_code == 200:
                result = response.json()
                if result['status']:
                    print('337  ->', result)
    
        def buy_ticket(self):
            self.query_ticket_info()
            self.check_img()
    
    
    if __name__ == '__main__':
        train = Train()
        train.buy_ticket()
    
    
    12306.jpg

    最后更新时间:2018-05-15 0:15:23

    相关文章

      网友评论

          本文标题:12306

          本文链接:https://www.haomeiwen.com/subject/oucizxtx.html