1. 程式人生 > >使用python爬取12306上面所有車次資料

使用python爬取12306上面所有車次資料

在爬取12306之前需要做的工作就是: 1,分析請求過程 2,分析是否需要處理cookie 3,編寫程式碼 4,測試爬取網站是否有訪問次數限制 5,部署到正式伺服器上 這裡重點寫 如何分析請求過程: 這是12306上面查詢車次的介面,出發地目的地 是我們需要輸入的, 如果要爬取全國的所有的車次 那就需要找到全國所有的出發地到目的地的列表.
是以js 檔案的形式 載入到頁面的 ,檔案很大,裡面包含了 未來 45天 的車次資料, 但是這裡只有出發點到終點,沒有 中間站到中間站,我們可以使用這些資料 到上面的 搜尋框中搜索我們需要的資料.
下載並 處理這個檔案,方便後面使用:
#下載所有的車次資料  儲存為 train_list.txt檔案
def getTrain_list():
    requests.adapters.DEFAULT_RETRIES = 5
    response = requests.get(train_list_url, stream=True,verify=False)
    status = response.status_code
    if status == 200:
        with open('train_list.txt', 'wb') as of:
            for chunk in response.iter_content(chunk_size=102400):
                if chunk:
                    of.write(chunk)


#分析train_list.txt檔案 得出火車 出發站到終點站的資料
def trainListStartToEnd():
    global station_start_end_set
    with open('train_list.txt','rb') as of:
        text=of.readline()
        tt=text.decode("utf-8")
        ss=tt.replace("},{","}\n{").replace("2017-","\n").replace("[","\n").split("\n")
        m_list=list()
        for s in ss:
            pattern = re.compile(r'\((\w+-\w+)\)')
            match = pattern.search(s)
            if match:
                m_list.append(match.group(1))
        station_start_end_set=set(m_list)


接下來分析搜尋後 會發生什麼事 :
先會有一個初始化的過程,初始化過程中使用到了 下面的引數,北京和上海是 我們輸入的,但是目前沒有站點編碼


檢視該頁面的js時 發現 該連結中包含了 全國所有的站點對應的編碼:
處理裡面的站點和編碼 方便後面使用:

檢視cookie時 發現 在請求這個連結時 是需要傳送 cookie的 ,但是這些cookie怎麼來的呢!

但我把cookie清空後再請求,發現請求這個連結就可以收到 cookie
接著就是請求資料介面 : 連結中的 purpose_codes 表示票的型別 這是成人票
請求這個介面需要使用到上面初始化返回回來的cookie:

請求函式:
#利用出發站到終點站 爬取期間的列車資料
def getTrainNoList(back_date,train_date,from_station,from_station_name,to_station,to_station_name):
    post_data= {'back_train_date':back_date,
                '_json_att':"",'flag':'dc',
                'leftTicketDTO.from_station':from_station,
                'leftTicketDTO.to_station':to_station,
                'leftTicketDTO.from_station_name':from_station_name,
                'leftTicketDTO.to_station_name':to_station_name,
                'leftTicketDTO.train_date':train_date,
                'pre_step_flag':'index',
                'purpose_code':'ADULT'}

    init_resp=requests.post(init_url,data=post_data,headers=HEADERS,allow_redirects=True,verify=False)
    cookies=init_resp.cookies
    cookies.set('_jc_save_fromStation', from_station_name+','+from_station, domain='kyfw.12306.cn', path='/')
    cookies.set('_jc_save_toStation', to_station_name+','+to_station, domain='kyfw.12306.cn', path='/')
    cookies.set('_jc_save_fromDate', train_date, domain='kyfw.12306.cn', path='/')
    cookies.set('_jc_save_toDate', back_date, domain='kyfw.12306.cn', path='/')
    cookies.set('_jc_save_wfdc_flag', 'dc', domain='kyfw.12306.cn', path='/')
    url=query_url+"leftTicketDTO.train_date="+train_date+"&leftTicketDTO.from_station="+from_station+"&leftTicketDTO.to_station="+to_station+"&purpose_codes=ADULT"
    try:
        response = requests.get(url, headers=HEADERS, allow_redirects=True,cookies=cookies,verify=False,timeout=10)
        data=""
        if response.status_code==200:
            data=response.content
        data=data.decode("UTF-8")
        return data,cookies
    except  Exception as err:
        logger.exception('getTrainNoList error 獲取車次列表錯誤 日期'+train_date+'從'+from_station_name+'到'+to_station_name+' :%s',err)
        return None,None

之後只要再對 返回的資料進行處理就可以了 技術交流可以發郵件到 [email protected]