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()

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM