iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 14
1
Software Development

爬蟲始終來自於墮性系列 第 17

高鐵、台鐵轉乘查詢

定義目標

與昨天的主題連貫,很多社群朋友是從台北、台中過來的,很常時候接駁台鐵搭高鐵,那我們可以來寫一個常用的高鐵時刻查詢。雖然我們能夠單純寫一個高鐵的查詢,再去串接我們昨天寫的台鐵時刻,不過在看台鐵的網站時,發現有一個還不錯用的服務叫做轉乘資訊,能夠做到我們剛剛提到的需求,那麼今天的目標就設定來查詢這頁的資訊。


實際探訪

這個頁面其實跟昨天的介面很像,都是先選擇區域再選擇車站,然後再選擇到達站和時間,接著按送出查詢。第一眼直覺應該是跟昨天一樣,我送了相關資訊,網站就會將相關資訊塞在 html 裡面給我。

但經過探訪後發現實際上並不是如昨天一樣,感覺這個服務應該是後來做的,網頁實作的方法正確許多,那對於我們抓取資料的爬蟲應該會輕鬆很多。發現按下查詢後,是發了三個 post resuests,而每一個 request 的 searchtype 都不同。

第一個 request 的 searchtype 是 tratothsr,直覺就是火車接駁高鐵的相關項目,而果然他的 response 也就是一個車站代號。

第二個 request 的 searchtype 是 traschedule,直覺看起來就是查詢火車時刻,而果然在第一個所查詢到的車站代號就會用在這邊,而這個 request 的 response 就是火車時刻表,而且還是 json format,就不用向昨天一樣還需要用 jsdon 來模擬執行。

第三個 request 的 searchtype 是 thsrschedule,直覺看起來就是查詢高鐵時刻,也不負其然的回傳高鐵時刻表,回傳也是 json format。


分解研究

我們會將這隻爬蟲分解成三個動作:

  1. 準備預設資訊
  2. 查詢 request

準備預設資訊

我們一樣先來觀察一下查詢的 request 會送出什麼。參數看起比昨天更簡單,只有 searchtype、fromstation、tostation、searchdate、fromtime,這看起來非常的直覺。

模擬 request

然後我們模擬這三個 request,看起來是能夠得到相同的內容,那麼肯定就沒問題了。


實作程式碼

雖然流程是送出三個 requsest,但實際上真正拿到時刻表的只有後面兩個 request,所以其實我們只需要製作後面兩個 request 就可以了。

getTras function

查詢台鐵時刻表 function。

function getTras(callback) {
  request({
    url: 'http://twtraffic.tra.gov.tw/twrail/Services/TransferDataServ.ashx',
    method: 'POST',
    form: {
      searchtype: 'traschedule',
      fromstation: '1239',
      tostation: '5102',
      searchdate: moment().format('YYYY-MM-DD'),
      fromtime: moment().format('HHmm'),
    }
  }, (err, res, body) => {
    callback(null, JSON.parse(body))
  })
}

getThsrc function

查詢高鐵時刻表 function。

function getThsrc(callback) {
  request({
    url: 'http://twtraffic.tra.gov.tw/twrail/Services/TransferDataServ.ashx',
    method: 'POST',
    form: {
      searchtype: 'thsrschedule',
      fromstation: '5102',
      tostation: '1324',
      searchdate: moment().format('YYYY-MM-DD'),
      fromtime: moment().format('HHmm'),
    }
  }, (err, res, body) => {
    callback(null, JSON.parse(body))
  })
}

積木組合

這次實在太簡單了,所以我們來試著用一個前系列沒出現過的 async.parallel,他的用意是同時執行所有的 async tasks,然後全部完成後再做動作。

async.parallel([getTras, getThsrc], (err, results)=>{
  console.log(results);
})

完整程式碼

const request = require('request');
const cheerio = require('cheerio');
const moment = require('moment');
const async = require('async');

async.parallel([getTras, getThsrc], (err, results)=>{
  console.log(results);
})

function getTras(callback) {
  request({
    url: 'http://twtraffic.tra.gov.tw/twrail/Services/TransferDataServ.ashx',
    method: 'POST',
    form: {
      searchtype: 'traschedule',
      fromstation: '1239',
      tostation: '5102',
      searchdate: moment().format('YYYY-MM-DD'),
      fromtime: moment().format('HHmm'),
    }
  }, (err, res, body) => {
    callback(null, JSON.parse(body))
  })
}

function getThsrc(callback) {
  request({
    url: 'http://twtraffic.tra.gov.tw/twrail/Services/TransferDataServ.ashx',
    method: 'POST',
    form: {
      searchtype: 'thsrschedule',
      fromstation: '5102',
      tostation: '1324',
      searchdate: moment().format('YYYY-MM-DD'),
      fromtime: moment().format('HHmm'),
    }
  }, (err, res, body) => {
    callback(null, JSON.parse(body))
  })
}

衍伸應用

這次的主題異常輕鬆,但其實並不是所有爬蟲都需要很費勁,主要還是看網站的製作邏輯到底好不好,若非常的「正常」,其實抓起來都是很輕鬆的,但只可惜台灣大部分的資料網站都不是很「正常」,但這又是另外一個有趣的議題了。

這邊觀察到另外一個有趣的事情,在探訪時兩個 request 查詢到的台鐵時刻和高鐵時刻是分開的,也就是說在畫面上他的呈現方式會將台鐵到達時間算好能接駁到高鐵的班次,這個肯定就是前端 render 的時候組裝畫面,若有興趣的話也能去觀察那部份的邏輯。


上一篇
台鐵時刻表
下一篇
日幣匯率訂閱
系列文
爬蟲始終來自於墮性34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言