iT邦幫忙

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

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

電影場次快速查詢

  • 分享至 

  • xImage
  •  

定義目標

我看電影都是挺臨時決定的,常常興致來了並且剛好有空就會去看電影,但是每次這種狀況的時候,我都必須去每間電影院翻找時刻表,看看我想看的電影最近的一場是在哪邊、哪個時候。

我們今天的挑戰就來爬電影的時刻表,針對我想看的那部電影,吐給我最接近的電影時刻和電影院。


實際探訪

我們這次會選用開眼電影網來取得我們所需要的資料,進入網站後,我們觀察到可以在右邊的「 影片上映戲院查詢」下拉選單選擇電影和城市,然後就會就會出現這部電影在這個城市的所有時間場次,很顯然的,這對我們的目標有大的幫助。

同時我們也來觀察一下所送出的 request,只有送出一個 get request,真是非常簡潔。接下來我們來觀察一下這個 request 的 url 所代表的意義,有兩個我們看不懂的參數在網址裡面,fsen72527336a06

回到入口頁我們選擇下拉的位置,看一下 input select 的內容,可以發現 fsen72527336 其實是代表電影代碼,而 a06 是代表城市代碼。

如此一來,我們可以很容易的就組合出某部電影在某個城市的所有時間查詢的網址,那我們就接下去研究吧。


分解研究

要取得最接近的某部電影時間,那麼會拆解成以下三個步驟:

  1. 取得電影代號
  2. 取得所有場次時間
  3. 整理資料取出近五場時間

取得電影代號

我們可以從首頁這邊取得電影 select 所有 option 的 key value,然後對輸入的電影名稱做 regex 來比對,就能夠取得 film_id 了。

取得所有場次時間

取得 film_id 之後,我們用之前探訪所得到的 city_id,把這兩個數值組合成 url,然後用 postman 測試看看,確認是可以取得所有電影時刻。

整理資料取出近五場時間

我們可以用下面的程式碼來取得所有電影時間資料,接著取出大於目前的時間,再 sort 一下時間順序,就能取得可用的電影時間列表了。測試看看確定是可以拿到時間表就沒問題了。

var d = new Date()
var hour = d.getHours()
var minute = d.getMinutes()

$('#filmShowtimeBlock li')
    .filter((index, obj)=>{
        return $(obj).prop('classList').length == 0
    })
    .filter((index, obj)=>{
		var time = $(obj).text().split(':')
        return time[0]*60+time[1]*1 > hour*60+minute*1
    })
    .map((index, obj)=>{
        return{
            time: $(obj).text(),
            theater: $(obj).closest('ul').find('.theaterTitle').text()
        }
    })
    .get()
    .sort((a,b)=>{
        var a = a.time.split(':')
		var b = b.time.split(':')
        return (a[0]*60+a[1]*1 > b[0]*60+b[1]*1)? 1:-1
    })

實作程式碼

getFileID function

我們先攥寫一個 function,收兩個參數,接收我們查詢電影的關鍵字,然後將查詢到的 filmId 傳給 callback。

function getFilmId(movie, callback) {
  request('http://www.atmovies.com.tw/movie/', (err, res, body) => {
    var $ = cheerio.load(body)
    var re = new RegExp(movie,"i");
    var filmId = $('select[name=film_id] option').filter((index, obj) => {
      return re.test($(obj).text())
    }).val()
    callback(filmId)
  })
}

getMovieTimes function

接下來我們攥寫 function 收取 filmId 和 cidtId,然後取得這部電影在這個城市的所有場次,然後在對抓取出來的場次做運算和排序。

function getMovieTimes(filmId, cityId, callback) {
  request(`http://www.atmovies.com.tw/showtime/${filmId}/${cityId}/`, (err, res, body) => {
    var d = new Date()
    var hour = d.getHours()
    var minute = d.getMinutes()
    var $ = cheerio.load(body)
    var times =
      $('#filmShowtimeBlock li')
      .filter((index, obj) => {
        var time = $(obj).text().split(':')
        return time[0] * 60 + time[1] * 1 > hour * 60 + minute * 1
      })
      .map((index, obj) => {
        return {
          time: $(obj).text(),
          theater: $(obj).closest('ul').find('.theaterTitle').text()
        }
      })
      .get()
      .sort((a, b) => {
        var a = a.time.split(':')
        var b = b.time.split(':')
        return (a[0] * 60 + a[1] * 1 > b[0] * 60 + b[1] * 1) ? 1 : -1
      })
    callback(times)
  })
}

積木組合

我們先抓取 filmId 然後再取抓取場次時間,這樣就完成了。

getFilmId('star', (filmId) => {
  getMovieTimes(filmId, 'a06', (times) => {
    console.log(times);
  })
})

完整程式碼

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


getFilmId('star', (filmId) => {
  getMovieTimes(filmId, 'a06', (times) => {
    console.log(times);
  })
})

function getFilmId(movie, callback) {
  request('http://www.atmovies.com.tw/movie/', (err, res, body) => {
    var $ = cheerio.load(body)
    var re = new RegExp(movie, "i");
    var filmId = $('select[name=film_id] option').filter((index, obj) => {
      return re.test($(obj).text())
    }).val()
    callback(filmId)
  })
}

function getMovieTimes(filmId, cityId, callback) {
  request(`http://www.atmovies.com.tw/showtime/${filmId}/${cityId}/`, (err, res, body) => {
    var d = new Date()
    var hour = d.getHours()
    var minute = d.getMinutes()
    var $ = cheerio.load(body)
    var times =
      $('#filmShowtimeBlock li')
      .filter((index, obj) => {
        var time = $(obj).text().split(':')
        return time[0] * 60 + time[1] * 1 > hour * 60 + minute * 1
      })
      .map((index, obj) => {
        return {
          time: $(obj).text(),
          theater: $(obj).closest('ul').find('.theaterTitle').text()
        }
      })
      .get()
      .sort((a, b) => {
        var a = a.time.split(':')
        var b = b.time.split(':')
        return (a[0] * 60 + a[1] * 1 > b[0] * 60 + b[1] * 1) ? 1 : -1
      })
    callback(times)
  })
}


衍伸應用

我們可以把 web service 裝上去,然後用 get query string 來收欲查詢的電影,這樣就能快速的部署一個電影場次查詢 api。

其實這次的主題可以發現,這樣的功能有八成的資料是別人提供的,但可惜的就是他是一種網頁 service,而我們透過爬蟲就能將他們的服務轉成是 open api,那就能夠大幅杜的提升應用層面。


上一篇
ibon 上傳文件
下一篇
Facebook 好友生日列表
系列文
爬蟲始終來自於墮性34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言