iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 10
3
Software Development

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

PTT 台南版置底 3C 文

定義目標

我是一個很喜歡尋寶的人,會常常看 FB 的地方二手版,看有沒有實用的東西可以撿便宜,除了 FB 以外, PTT 地方版也有大量的二手物品販售訊息,所以 PTT 台南版我也是常常逛。

ptt 台南版 3C 置底文

不過,台南版規規定,所有的 3C 商品買賣都必須放於置底文的推文,所以這些資訊的顯示方式真的是爆難看。既然是個網頁工程師,有問題就應該自己動手解決,雖然畫面不好看我們無力解決,但我們至少能轉接個 API 出來,讓有能力的設計師可以有資料去製作好看的介面。


實際探訪

探訪 put code_job

一樣是使用 PTT web 版來抓取資訊,台南版 3C 置底文的網址是 https://www.ptt.cc/bbs/Tainan/M.1464690165.A.D11.html ,看起來就是把底下推文的項目抓取出來就可以了。


分解研究

接下來觀察看看每個 item 的 html dom,看起來只要抓每個 .push 就能抓到所有的推文項目,然後再抓取每個項目的發文者、推文內容、時間。

不過我們也觀察到,因為一個推文有其字數限制,常常會有人連續發兩個推文,既然如此,那這兩筆同樣的發送人應該要被歸類在同一個項目。


實作程式碼

getItems function

先來寫個 getItem function,收個參數 callback,屆時把抓取到的項目丟給 callback。接著我們做 request 台南版 3C 至底文的網址。

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

function getItems(callback){
  request('https://www.ptt.cc/bbs/Tainan/M.1388172150.A.860.html', (err, res, body)=>{
    var $ = cheerio.load(body,  { decodeEntities: false })
    var items = []
    
  })
}

取得推文列表

再來我們來抓取推文列表,抓到之後,我們 each 所抓到的內容,並將發文者、推文內容、時間整理出來。接著我們判斷抓取的發文者是不是等於上一筆的發文者,若相同的話,就把它併入上一筆,若不是的話,就 push 進去 items。

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

function getItems(callback){
  request('https://www.ptt.cc/bbs/Tainan/M.1388172150.A.860.html', (err, res, body)=>{
    var $ = cheerio.load(body,  { decodeEntities: false })
    var items = []

    $('div.push').each((index, obj)=>{
      var seller = $(obj).find('.push-userid').html();
      var content = $(obj).find('.push-content').html().replace(': ', '');
      var time = $(obj).find('.push-ipdatetime').html().replace('\n', '');

      if (items.length && seller === items[items.length - 1].seller) {
        items[items.length - 1].content = items[items.length - 1].content + content;
      } else {
        currentUser = seller;
        items.push({
          seller: seller,
          content: content,
          time: time,
        });
      }
    })
    callback(items)
  })
}

Express 做 api service

啟動 express

接下來我們用 express 來做 web service,先暫時聽 3000 port,未來 deploy 再改 80,經過測試沒問題就大功告成了。

const express = require('express');
const app = express();

app.get('/', function (req, res) {
  getItems((items)=>{
    res.json(items)
  });
}).listen(3000)

完整程式碼

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

app.get('/', function (req, res) {
  getItems((items)=>{
    res.json(items)
  });
}).listen(3000)

function getItems(callback){
  request('https://www.ptt.cc/bbs/Tainan/M.1388172150.A.860.html', (err, res, body)=>{
    var $ = cheerio.load(body,  { decodeEntities: false })
    var items = []

    $('div.push').each((index, obj)=>{
      var seller = $(obj).find('.push-userid').html();
      var content = $(obj).find('.push-content').html().replace(': ', '');
      var time = $(obj).find('.push-ipdatetime').html().replace('\n', '');

      if (items.length && seller === items[items.length - 1].seller) {
        items[items.length - 1].content = items[items.length - 1].content + content;
      } else {
        currentUser = seller;
        items.push({
          seller: seller,
          content: content,
          time: time,
        });
      }
    })
    callback(items)
  })
}


衍伸應用

爬蟲的應用不僅僅只是在抓資料,其實很多時候我們會是當個中介者的角色。資訊這個領域開放性的觀念很重要,唯有大家願意分享和貢獻,才有可能有更多的人站在你的肩膀上往前邁進。

我不是個設計師,我設計不了很友善的畫面,憑我一個人的力量是沒辦法解決這個目標的問題,但我能貢獻我的一份能力,串起解決問題過程當中的一環,那麼這就是一件有價值的事情。


上一篇
PTT Code_job 訂閱通知
下一篇
PTT 表特版 API
系列文
爬蟲始終來自於墮性34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言