Python爬虫之12306-买票器小白源码

研究不易

 

import requests
import re
import urllib.parse
import json
import datetime
from collections import OrderedDict
self=requests.session()
self.verify=False
self.headers={
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding':'gzip, deflate, br',
    'Accept-Language':'zh-CN,zh;q=0.9',
    'Connection':'keep-alive',
    'Host':'kyfw.12306.cn',
    'Cache-Control':'no-cache',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
    }
def dow():
    url='https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand'
    requests.packages.urllib3.disable_warnings()
    res=self.get(url)
    print(res.status_code)
    if res.status_code==200:
       with open('login.jpg','wb') as f:
          f.write(res.content)
    else:
        dow()
#验证
def yanzhengma():
     #获取验证码
     dow()
     # 1 2 3 4 5 6 7 8
     xylist=['35,35','105,35','175,35','245,35','35,105','105,105','175,105','245,105']
     print('请依次输入验证码的位置并换行,0表示结束')
     ilist=[]
     while True:
        i=input()
        if i=='0':
            break
        ilist.append(xylist[int(i)-1])
     xy=','.join(ilist)
     print(xy)

     data={
         'answer':xy,
         'login_site':'E',
         'rand':'sjrand'
     }
     url='https://kyfw.12306.cn/passport/captcha/captcha-check'
     requests.packages.urllib3.disable_warnings()
     res=self.post(url,data=data)
     print(res.url)
     print(res.text)
     code=re.search('_code.*?(\d)',res.text,re.S).group(1)

     print(code)

     # 成功返回True,失败递归调用
     if code=='4':
         print('验证成功,请登陆')

     elif code=='5':
         print('验证错误')
         yanzhengma()
     elif code=='7':
         print('验证超时')
         yanzhengma()
     else:
         print('验证失败')
         yanzhengma()
def login():
     yanzhengma()#验证码
     data={
         'username':'账号,
         'password':'密码,
         'appid':'otn'
     }
     url='https://kyfw.12306.cn/passport/web/login'
     requests.packages.urllib3.disable_warnings()
     res=self.post(url,data=data)
     print(res.text)
     code=re.search('_code.*?(\d)',res.text,re.S).group(1)


     # 成功返回True,失败递归调用
     if code=='0':
         yzdata={
         'appid':'otn'
         }
         tk_url='https://kyfw.12306.cn/passport/web/auth/uamtk'
         resp3=self.post(tk_url,data=yzdata)
         print('-----------------第一次验证-----------------')
         print(resp3.text)
         login_message=resp3.json()['newapptk']
         print('loginMessage=',login_message)
         yz2data={
             'tk':login_message
         }
         client_url='https://kyfw.12306.cn/otn/uamauthclient'
         resp4=self.post(client_url,data=yz2data)
         print('-----------------第二次验证-----------------')
         print(resp4.text)
         print('登陆成功,可以开始购票')

     elif code=='1':
         print('密码输入错误。如果输错次数超过4次,用户将被锁定。')
         login()
     else:

         print('登录失败')
         login()
def shoppiao():

    data={
       'leftTicketDTO.train_date':'2018-10-15',#时间
        'leftTicketDTO.from_station':'BJQ',#出发站码
        'leftTicketDTO.to_station':'CBN',#目的地码
        'purpose_codes':'ADULT'#票类型ADULT成人,STUDENT学生
    }
    url='https://kyfw.12306.cn/otn/leftTicket/queryA?'
    requests.packages.urllib3.disable_warnings()
    res=self.get(url,params=data)
    print(res.status_code)
    print(res.text)
    dictr=json.loads(res.text)
    pklist=dictr.get('data').get('result')
    for item in pklist:
        sp_item = item.split('|')
        for index, item in enumerate(sp_item,0):

            print('{}:\t{}'.format(index, item))
        '''
        通过分析
        0:列车信息(订票时候需要) 1:信息 2:火车编号
        3:列车号 4:始发站   5:终点站   6:起始站  7:目标站    8:出发时间       9:到达时间
        10:行车时间
        11:有3种状态:Y, N, IS_TIME_NOT_BUY 分别对应,可以预定,不可以预定,其他原因----对应的是第1项
        12:参数leftTicket
        13:日期
        14:
        15:参数train_location
        21:高级动卧   22:        23:软卧 24:软座  25:特等座  26:无座 28:硬卧  29:硬座  30:二等座  31:一等座  32:商务座 33:动卧
       '''
        if sp_item[11]=='Y':#可以买票,开始订票
            if sp_item[30]!='无':#买二等座
                print(sp_item[30])
                if vel_longin_2():#验证登陆
                   print('已经登陆可以开始下单')
                   self.headers['X-Requested-With']='XMLHttpRequest'
                   secretStr=urllib.parse.unquote(sp_item[0])


                   self.headers['Referer'] = 'https://kyfw.12306.cn/otn/leftTicket/init'

                   submitOrderRequest(secretStr)

                   data = OrderedDict()
                   data["_json_att"] =''
                   data["fromStationTelecode"] =sp_item[6]
                   data["leftTicket"] = sp_item[12]
                   data['purpose_codes']='00'
                   data['REPEAT_SUBMIT_TOKEN']=''
                   data["seatType"] = 'O'
                   data["stationTrainCode"] = sp_item[3]
                   data["toStationTelecode"] =sp_item[7]
                   data["train_date"] = str(datetime.datetime.strptime(sp_item[13], '%Y%m%d').strftime('%a %b %d %Y %H:%M:%S GMT+0800'))
                   data["train_location"] = sp_item[15]
                   data["train_no"] =sp_item[2]

                   '''
                   data={
                        'train_date':str(datetime.datetime.strptime(sp_item[13], '%Y%m%d').strftime('%a %b %d %Y %H:%M:%S GMT+0800')),
                        'train_no':sp_item[2],#火车编号
                        'stationTrainCode':sp_item[3],#列车号
                        'seatType':'O',#座位类型 1是硬座(无座),2是软座,3是硬卧,4是软卧,  O 大写字母  是高铁二等座,M是高铁一等座,商务座(9),特等座(P),高级软卧(6)
                       'fromStationTelecode':sp_item[6],#起始站编号
                        'toStationTelecode':sp_item[7],#目标站编号
                        'leftTicket':sp_item[12],
                        'train_location':sp_item[15],#15项Q6
                   }
                '''
                   shopdin(data)

                else:
                    login()
                    shoppiao()
        break

def submitOrderRequest(secretStr):
    data = OrderedDict()
    data["secretStr"] = secretStr
    data["train_date"] = '2018-09-20'
    data["tour_flag"] = "dc"
    data["purpose_codes"] = "ADULT"
    data["query_from_station_name"] ='深圳'
    data["query_to_station_name"] = '赤壁'
    data["undefined"] = ''
    url='https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest'
    res=self.post(url,data=data)
    print(res.text)
#开始下单
def shopdin(data1):
    #获取1个参数
    liop=initDc()
     #改变Headers
    self.headers['Referer'] = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    self.headers['Origin']='https://kyfw.12306.cn'
    print(self.headers)
    #请求并获取联系人参数
    pasdir=PassengerDTOs(liop[0])
    print(type(pasdir))
    # 二等座 0  (车票类型:ticket_type_codes 成人票1)      ,1,张三(passenger_name),   1(证件类型:passenger_id_type_code),320xxxxxx(passenger_id_no),151xxxx(mobile_no),N
    passengerTicketStr=data1['seatType']+ ',0,'+pasdir['passenger_type']+','+pasdir['passenger_name']+','+pasdir['passenger_id_type_code']+','+pasdir['passenger_id_no']+','+pasdir['mobile_no']+',N'
    #张三(passenger_name),1(证件类型:passenger_id_type_code),320xxxxxx(passenger_id_no),1(passenger_type)_
    oldPassengerStr=pasdir['passenger_name']+','+pasdir['passenger_id_type_code']+','+pasdir['passenger_id_no']+','+pasdir['passenger_type']+'_'
    data = OrderedDict()
    data["_json_att"] =''
    data["ed_level_order_num"] ='000000000000000000000000000000'
    data["cancel_flag"] ='2'
    data["oldPassengerStr"] = oldPassengerStr
    data["passengerTicketStr"] = passengerTicketStr
    data["randCode"] =''
    data["tour_flag"] ='dc'
    data["whatsSelect"] ='1'
    '''
    data={
        'cancel_flag':'2',#固定
        'ed_level_order_num':'000000000000000000000000000000',#固定
        'passengerTicketStr':passengerTicketStr,#联系人
        'oldPassengerStr':oldPassengerStr,#联系人
        'tour_flag':'dc',#单程
        'randCode':'',#空
        'whatsSelect':'1',#是否选择了联系人,
    }
    '''
    OrderInfo(data)
    data1['REPEAT_SUBMIT_TOKEN']=liop[0]
    #提交订单
    getQueueCount(data1)
    data2= OrderedDict()
    data2["_json_att"] =''#空
    data2["choose_seats"] =''#空
    data2["dwAll"] ='N'#固定
    data2["key_check_isChange"] =liop[1]#页面找
    data2["leftTicketStr"] = data1['leftTicket']#列车
    data2["oldPassengerStr"] =oldPassengerStr#联系人
    data2["passengerTicketStr"] =passengerTicketStr#联系人
    data2["purpose_codes"] ='00'#
    data2["randCode"] =''#随机数 空
    data2["REPEAT_SUBMIT_TOKEN"] =liop[0]
    data2["roomType"] ='00'#固定
    data2["seatDetailType"] ='000'#选铺 暂不支持 默认参数
    data2["train_location"] = data1['train_location']#q6
    data2["whatsSelect"] ='1'#固定
    tijiao(data2)
def tijiao(data):
    url='https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue'
    res=self.post(url,data=data)
    print(res.status_code)
    print(res.text)
#获取联系人
def PassengerDTOs(REPEAT_SUBMIT_TOKEN):
    data={
        '_json_att':'',#空
        'REPEAT_SUBMIT_TOKEN':REPEAT_SUBMIT_TOKEN#页面找
    }
    url='https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'
    res=self.post(url,data=data)
    #print(res.text)
    passen=res.json().get('data').get('normal_passengers')[1]
    print(passen)
    return passen

#订单页面----获取参数
def initDc():
    url='https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    res=self.post(url,data={'_json_att':''})
    REPEAT_SUBMIT_TOKEN=re.search('globalRepeatSubmitToken = .(.*?).;',res.text,re.S).group(1)
    ticketInfoForPassengerForm_name = re.compile(r'var ticketInfoForPassengerForm=(\{.+\})?')
    order_request_params_name = re.compile(r'var orderRequestDTO=(\{.+\})?')
    re_tfpf = re.findall(ticketInfoForPassengerForm_name, res.text)
    re_orp = re.findall(order_request_params_name, res.text)
    key_check_isChange=re.search('key_check_isChange.:.(.*?).,',res.text,re.S).group(1)
    return [REPEAT_SUBMIT_TOKEN,key_check_isChange]
 #选乘客票种提交
def OrderInfo(data):
    url='https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo'
    res=self.post(url,data=data)
    print(res.status_code)
    print(res.text)
#提交订单列车余票。
def getQueueCount(data):
    url='https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount'
    res=self.post(url,data=data)
    print(res.status_code)
    print(res.text)
def vel_longin_2():
    url='https://kyfw.12306.cn/otn/login/checkUser'
    requests.packages.urllib3.disable_warnings()
    res=self.post(url,data={'_json_att':''})
    login_vel=res.json().get('data')['flag']

    return login_vel
if __name__ == '__main__':
    #yanzhengma()
    shoppiao()
    vel_longin_2()

 

  

 

posted @ 2018-09-28 07:50  跑着的小强  阅读(3253)  评论(1编辑  收藏  举报