iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 30
5
Software Development

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

Udemy 免費課程訂閱

  • 分享至 

  • xImage
  •  

定義目標

我很喜歡 Soft & Share 特價課程與學習資訊分享 這個社團,因為他分享了許多免費學習的資訊,很多課程都令人愛不釋手。而我們到 Udemy 的搜尋裡面,也能輕易地找出許多免費課程,不過這個跟 Soft & Share 社團所分享的不太一樣,因為社團所分享的是包含透過 coupon 所拿到的免費課程。那麼我們今天的就來試試看有沒有什麼方式能夠取得 frees coupon course,然後做一個訂閱限時免費課程的服務。


實際探訪

我們先 google 看看 「udemy free coupon」,當然就會看到許多 coupon 網站,在查看結果的過程中眼尖發現到 reddit 這個國外最大的論壇。若說台灣資訊流竄最快的肯定是 ptt,那麼在國外肯定就是 reddit,那麼我們就去 reddit 看看有沒有適合的看板。

直接搜尋 udemy 會看到三個看板,第一個比較像是 Udemy 的討論論壇,而第二、三個就是我們想要的 free coupon course。點進去看看,沒錯,就是我們想要的,若我們能夠定期的取得最新的,我們就可以將著個服務建立起來。

接著繼續觀察每一個項目,很幸運的,每個 dom 都有包含 timestamp,也就是說,我們能夠制定我們的 cron job,在間隔一段時間抓取這個時間區間內的新文章,如此一來應該就能完成訂閱服務。


分解研究

若要抓取所有區間內的新文章,我們需要做以下兩個步驟:

  1. 抓取文章列表
  2. 篩選時間內的文章

抓取文章列表

我們先用 postman 對看板的 url 抓看看,確定是可以拿到列表,然後用 select 選取看看,確認是可以把文章列表抓出來。

篩選時間內的文章

接下來來對文章列表做篩選,我們先假設爬蟲三天執行一次,所以預設先抓取三天內的文章,試著 filter 看看,確定是可以篩選出時間內的文章。


實作程式碼

getNewPost function

我們先來撰寫取得文章列表的 function,接受一個 url 參數,用 request 取得列表,整理一下資料,再做 timestamp filter,最後用 promise resolve 我們取得的文章。另外我們也設定一下 const PERIOD,方便我們未來做調整。

const PERIOD = 60 * 60 * 24 * 3 * 1000;

function getNewPost(url) {
  return new Promise(done => {
    request(url, (err, res, body) => {
      var $ = cheerio.load(body)
      var posts = $('.thing').map((index, obj) => {
        return {
          title: $(obj).find('a.title').text(),
          link: $(obj).find('a.title').attr('href'),
          timestamp: $(obj).attr('data-timestamp'),
        }
      }).get().filter((obj) => {
        return obj.timestamp > (Date.now() - PERIOD)
      })
      done(posts)
    })
  })
}

積木組合

因為有兩個看板,所以我們用 promise.all 來取得時間區間內的文章列表,然後在做 array flat,這樣就完成了。

Promise.all([
  getNewPost('https://www.reddit.com/r/udemyfreecourses/'),
  getNewPost('https://www.reddit.com/r/udemyfreebies/')
]).then(results => {
  console.log([].concat.apply([], results));
});

完整程式碼

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

const PERIOD = 60 * 60 * 24 * 3 * 1000;


Promise.all([
  getNewPost('https://www.reddit.com/r/udemyfreecourses/'),
  getNewPost('https://www.reddit.com/r/udemyfreebies/')
]).then(results => {
  console.log([].concat.apply([], results));
});

function getNewPost(url) {
  return new Promise(done => {
    request(url, (err, res, body) => {
      var $ = cheerio.load(body)
      var posts = $('.thing').map((index, obj) => {
        return {
          title: $(obj).find('a.title').text(),
          link: $(obj).find('a.title').attr('href'),
          timestamp: $(obj).attr('data-timestamp'),
        }
      }).get().filter((obj) => {
        return obj.timestamp > (Date.now() - PERIOD)
      })
      done(posts)
    })
  })
}


衍伸應用

許多的資訊都是藉由論壇或社群所討論出來,但這類的資料通常都缺乏整理,所以幾乎都是散亂的,而我們可以利用爬蟲做定期整理,就有機會將這些討論串變成很有用的資料。

除了把文章列表拿取出來以外,我們還可以對文章內容做格式整理,或者在關鍵字訂閱,這樣也能夠做成很有用的服務。若更近一步,我們可以自動將這些課程加入我們的 Udemy 的帳號,那就能做到完全自動化訂閱限時免費的課程。


上一篇
NBA 新聞爬取
系列文
爬蟲始終來自於墮性34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
john_old_man
iT邦新手 5 級 ‧ 2019-05-09 07:40:03

大大的爬蟲教學看下來
發現比source code 更寶貴的是
文章融入了
如何發現問題—>解決問題的思維
受益良多

allenchen iT邦新手 3 級 ‧ 2019-06-13 16:00:53 檢舉

Good job 謝謝分享

0
silenus
iT邦新手 5 級 ‧ 2019-11-29 14:14:10

後續補充:

由於reddit網站更新改版的緣故,需將以下程式碼
Promise.all([
getNewPost('https://www.reddit.com/r/udemyfreecourses/'),
getNewPost('https://www.reddit.com/r/udemyfreebies/')
]).then(results => {
console.log([].concat.apply([], results));
});
改為
Promise.all([
getNewPost('https://old.reddit.com/r/udemyfreecourses/'),
getNewPost('https://old.reddit.com/r/udemyfreebies/')
]).then(results => {
console.log([].concat.apply([], results));
});
方能爬得到資料哦!

0
阿展展展
iT邦好手 1 級 ‧ 2020-02-18 08:45:11

我要成為爬蟲王!!! /images/emoticon/emoticon37.gif

我要留言

立即登入留言