iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 9
0

定義目標

除了要處理各種工作室奇怪的問題之外,我其實是一名接案工程師,雖然目前已經不會再主動求案,但在早之前,其實都是必須在網路上四處找案子的。而為了避免淪為廉價奴工,所以我不太會去一些數字型外包網站,大部分的來源會是在 FB 社群或者 PTT code_job 版。

正所謂時間就是金錢,常常有人做版上發了是我有興趣的案子,但因為在忙較晚看到就變成「已發案」狀態了。所以那時候就寫了一隻爬蟲,每隔一段時間就去幫我查查看有沒有新發案,有的話就自動寄信給我,從此之後我考試每科都得 100 分,案子永遠第一個聯絡...


實際探訪

要探訪 PTT 基本上就是走 telnet,但小弟不學好,所以那部分就沒有涉獵了,好在 ptt 有網頁版,雖然會 delay 些時間,不過大致上還是可以接受的。

探訪 ptt code_job

Code_job 版網址是 https://www.ptt.cc/bbs/CodeJob/index.html ,看起來挺容易爬的,雖然有分頁,但 index 預設就是最新的。

方法探索

這時腦中就在思考,我如何才能取得最新的文章呢?把公告濾掉,然後直接抓最後一篇或許是個直覺的方法,但考量到可能新發案會突然短時間發出兩、三篇,所以這個方式並不完整。

接著又想,若我能去記錄上一次爬蟲拿到的最後一篇文章,就能知道這次爬蟲新抓取的篇數。這樣確實可行,但不簡潔,至少我要有個地方去記錄上次文章,要嘛就是 database,要嘛就是存 file,兩種都還要額外的心力去處理。

接著又想,若上面有時間的話,那我可以去比對時間,例如爬蟲五分鐘爬一次,那我就能去算五分鐘內生成的文章有多少。但事情看起來沒那麼簡單,畫面上只有日期,日期範圍又太大了。

觀察物件

觀察物件

持續觀察上面有的物件,突然瞄到一個有趣的東西,文章的連結。這個連結中,有一個 10 位數又 15 開頭的數字,憑著工程師強烈的第六感,這肯定就是 timestamp。

驗證 timestamp

趕快驗證一下...
Bingo!那麼剩下都小事了...


分解研究

我們把動作分解成幾個:

  1. 抓取網頁
  2. 將文章列表抓出
  3. filter 5 分鐘內的文章

抓取 dom

因為單純是 get request,我想應該也沒有研究的必要了XDDD,就直接來研究抓取 dom 就可以了。確認可以抓到文章列表,那剩下的就是 filter 的事情了。


實作程式碼

Define 抓取時間

先 define 一個 crontab 會抓取的時間數值

const CrontabPeriod = 60 * 60 * 24 * 3 // 先預設三天做測試,完成後再改回五分鐘

取得文章列表

然後直接用 request 來抓取 code_job 版,然後再把文章 list 抓出來

request('https://www.ptt.cc/bbs/CodeJob/index.html', (err, res, body) => {
  var $ = cheerio.load(body)

  // 抓取文章列表
  var list = $('.r-ent a').map((index, obj) => {
    return {
      title: $(obj).text(),
      link: $(obj).attr('href'),
      timestamp: $(obj).attr('href').substr(15, 10),
    }
  }).get()
  console.log(list);
})

filter

最後加入 timestamp 的 filter

// filter 時間
list = list.filter((post)=>{
  return post.timestamp > (Date.now() / 1000 - CrontabPeriod)
})

完整程式碼

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

const CrontabPeriod = 60 * 5 // 五分鐘抓一次

request('https://www.ptt.cc/bbs/CodeJob/index.html', (err, res, body) => {
  var $ = cheerio.load(body)

  // 抓取文章列表
  var list = $('.r-ent a').map((index, obj) => {
    return {
      title: $(obj).text(),
      link: $(obj).attr('href'),
      timestamp: $(obj).attr('href').substr(15, 10),
    }
  }).get()

  // filter 時間
  list = list.filter((post)=>{
    return post.timestamp > (Date.now() / 1000 - CrontabPeriod)
  })

  console.log(list);
})

衍伸應用

我們可以透過 crontab 來設定每五分鐘 trigger 一次,同時加上 email server 來達到主動通知寄信,mail server 我們可以使用平常收發信用的 smtp,或者使用第三方的 service 像是 mailgun 之類的。

其實玩爬蟲並不是要多高深的技術或者,或多絢麗的技巧,真正有價值的是在於解決問題和省下時間。像是這次介紹的 ptt code_job 主動發文通知,就是一種很簡單,實作不困難,但卻能為我們省下許多的時間,而技術本意本該就是如此。


上一篇
台彩的銷售地點
下一篇
PTT 台南版置底 3C 文
系列文
爬蟲始終來自於墮性34

1 則留言

0
King Tzeng
iT邦新手 5 級 ‧ 2017-12-13 21:47:50

天啊好酷喔~我深深地被爬蟲吸引了~~/images/emoticon/emoticon24.gif

Howard iT邦新手 5 級‧ 2017-12-13 22:13:26 檢舉

爬蟲很好玩的,任何自動化都能做,就怕你想不到爾已

真的好實用喔!!ptt 都是我的世界(我的世界都是ptt)

我要留言

立即登入留言