iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 13
2

定義目標

好想工作室每天都有很多學員或社群夥伴到這邊來,也因為他在大橋火車站旁邊,所以很多人都是直接搭電車過來。常常聊得太開心,一不小心就錯過了末班車,所以每天都會時常查詢台鐵時刻表,今天就來做一隻爬蟲,讓我們能夠知道最近幾班的台鐵電車時刻。

ps. 不過台鐵時刻這個議題其實已經有很多人實做過,甚至有 open data 或 open api,不過我們會以最原始的網頁爬蟲來實作最基礎的做法。


實際探訪

台鐵的網站是 http://twtraffic.tra.gov.tw/twrail/TW_Quicksearch.aspx ,打開後真的是滿滿的大平台。先選擇啟程站,先點選台南區域再點選大橋車站,再選擇到達車站,選擇沙崙支線的沙崙站,然後再點選時間部分,其他項目我們就先留預設就好。(老實說,這個步驟真的很麻煩)

查詢完後,我們就會得到列車的資訊,這部分看起來就是 select dom 爾已,感覺應該沒什麼問題,我們就開始研究吧。


分解研究

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

  1. 準備預設資訊
  2. 查詢 request
  3. 查詢結果解析

準備預設資訊

我們先來觀察一下查詢的 request 會送出什麼。參數看起來基本上都還蠻直覺的,比較值得注意的,大概就是 FromStation、ToStation、TrainClass、searchdate、FromTimeSelect、ToTimeSelect、Timetype 這幾個。若不知道他是什麼意思,我們也能直接從網頁物件來做檢查,這樣就能 match 參數的意義。根據我們的需求來看,我們可以很容易的將參數組合出來,比較需要注意的大概就只有日期和時間,因為我們要送的是當下查詢的時間。

查詢 request

接下來我們用 postman 來測試看看,咦?乍看之下以為沒有得到列車班表,但凡事不能看表面,其實是有資料吐回來的。再仔細觀察一下,發現他把查詢結果寫在 html 裡面的 javascript,也就是說,我們必須模擬這個畫面的 js 才能取得這個變數。

查詢結果解析

既然他給我們的 data 是 json format,那也就不用解析了,只需要了解各個 key 所代表的現實意義就可以了。而知道他其實是用前端 render 的方式來組合 result table,那我們也可以根據一些 keyword 來查詢看看 render 的程式碼在哪邊,進而更切確的知道欄位對應的狀況。


實作程式碼

default data

我們先準備好我們要做查詢的資料,包含站名、車種、方向等等,同時我們使用 moment 來抓取現在的時間,時間區間為一個小時。(若你在半夜看到這篇爬蟲並且跟著做,那你將拿不到查詢資料...因為這個時間沒有火車啊啊啊!)

var data = {
  FromCity: 9,
  FromStation: 1239,
  FromStationName: 0,
  ToCity: 18,
  ToStation: 5102,
  ToStationName: 0,
  TrainClass: 2,
  searchdate: moment().format('YYYY - MM - DD'),
  FromTimeSelect: moment().format('HHmm'),
  ToTimeSelect: moment().add(1, 'hours').format('HHmm'),
  Timetype: 1
}

執行 request

接下來我們 post request,拿到查詢的回傳頁面。

var options = {
  url: 'http://twtraffic.tra.gov.tw/twrail/TW_SearchResult.aspx',
  method: 'POST',
  form: data,
}
request(options, (err, res, body)=>{
    console.log(body)
})

解析資料

就我們剛剛研究的結果,發現 data 是在回傳頁面的內容裡面,因此需要模擬 js 的執行才會有 data,所以我們會使用 jsdom 這個 library 來模擬,並且要加上 {runScripts: "dangerously"} 這個參數,這樣他才會執行裡面的 js。

request(options, (err, res, body)=>{
  var dom = new JSDOM(body, { runScripts: "dangerously" });
  console.log(dom.window.JSONData);
})

完整程式碼

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

const jsdom = require("jsdom");
const { JSDOM } = jsdom;

var data = {
  FromCity: 9,
  FromStation: 1239,
  FromStationName: 0,
  ToCity: 18,
  ToStation: 5102,
  ToStationName: 0,
  TrainClass: 2,
  searchdate: moment().format('YYYY-MM-DD'),
  FromTimeSelect: moment().format('HHmm'),
  ToTimeSelect: moment().add(1, 'hours').format('HHmm'),
  Timetype: 1
}

var options = {
  url: 'http://twtraffic.tra.gov.tw/twrail/TW_SearchResult.aspx',
  method: 'POST',
  form: data,
}
request(options, (err, res, body)=>{
  var dom = new JSDOM(body, { runScripts: "dangerously" });
  console.log(dom.window.JSONData);
})


衍伸應用

台鐵的網站其實有很多優化的方向,但因為我們不是台鐵的 IT 人員,所以我們並沒有辦法直接修改他們的網頁,可是我們可以透過很多方式來讓整個服務提升,像是我們製作出 api 出來供其他服務應用,或是我們製作 browser extension 來改善使用體驗也行。

若你在生活上覺得有什麼不方便的,作為一個自幹型工程師,那你該做的不是去習慣它,而是應該動手解決它。


上一篇
591 出租網爬蟲
下一篇
高鐵、台鐵轉乘查詢
系列文
爬蟲始終來自於墮性34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言