用Ruby簡書爬蟲統計用戶文章信息

思沃大講堂培訓,要求我們把自己學習的心得感悟輸出在簡書上,公司還會統計大家的文章,包括文章數量、評論量、被喜歡量等等。這么多人,人工統計起來自然很麻煩,當然程序員會把這么艱巨光榮繁瑣的工作交給代碼,于是他們就寫了一個爬蟲。適值極客人正在學習Ruby,所以就突發奇想寫了一個Ruby爬蟲統計簡書用戶的文章,帶動自己的Ruby學習。

如果讓我抓取一個網站的內容,我的第一想法可能會是抓取它的HTML,不過也會反過來問自己一句這個網站有沒有Rss訂閱源地址,RSS的訂閱源的內容是xml,相比html更加簡潔和高效,而且由于xml的結構穩定一點(html可能那天換一個css可能就會導致我的爬蟲用不了啦),解析起來會更加方便一點。在考察完簡書沒有提供RSS后,我就決定選擇html來暴力地抓取簡書了。

分析簡書網址

我們可以獲取用戶的關注、粉絲、文章、字數、收獲喜歡等信息

Paste_Image.png

我們可以獲取用戶文章列表,以此統計用戶文章的評論量、閱讀量等等,通過遍歷文章列表將評論量、閱讀量相加即可獲取評論總量、閱讀總量

需要指出的是,由于文章列表頁不能把用戶的文章全部列出來,而是列出10條,用戶在瀏覽器中滾動到文章列表底部會自動加載,是用js向后臺請求數據然后在前端多次拼接出來,所以想一次性地抓一次就把用戶的評論總量、閱讀總量是不行的,用戶列表頁分頁的。所以我采取分頁抓取的方式,那么怎么知道用戶文章一共有多少頁呢?我們從用戶主頁中獲取了用戶的文章總數,所以除以10加1可以獲取頁數

  • 用戶列表頁分頁的,10條/頁,其中第 m 頁URL:

http://www.lxweimin.com/users/用戶ID(暫估計這么說)/latest_articles?page=m

Paste_Image.png

抓取網頁,獲取html

Ruby提供的HTTP訪問方法十分簡潔高效,當然方法不止一種,對其他方法感興趣的同學我自行Google,在此我貼出自己的代碼:

h = Net::HTTP.new("www.lxweimin.com", 80)
resp = h.get "/users/#{authorInfo.id}/latest_articles"
latest_articles_html = resp.body.to_s

顧問生義,我想不需要解釋代碼的意思了吧
根據上面介紹的簡書網址規則,就可以通過上述代碼抓取到相應網頁的HTML

分析抓取內容的結構

獲取完相應網頁的HTML內容后要做的就是分析HTML的內容和結構。我們用眼睛很容易看出網頁上的內容,但是爬蟲看到的只有html源代碼。下面我從抓取的HTML中提取了下列有用的代碼:

  • 用于提取用戶的關注量、粉絲量、文章數、字數、收獲喜歡數
<div class="user-stats">
  <ul class="clearfix">
    <li>
      <a href="/users/ef49e6b7ec1e/subscriptions"><b>38</b><span>關注</span></a>
    </li>
    <li>
      <a href="/users/ef49e6b7ec1e/followers"><b>22</b><span>粉絲</span></a>
    </li>
    <br>
    <li>
      <a href="/users/ef49e6b7ec1e"><b>9</b><span>文章</span></a>
    </li>
    <li>
      <a><b>9938</b><span>字數</span></a>
    </li>
    <li>
      <a><b>41</b><span>收獲喜歡</span></a>
    </li>
  </ul>
</div>
  • 用于提取用戶文章評論總量、閱讀總量
<ul class="article-list latest-notes"><li>
    <div>
      <p class="list-top">
        <a class="author-name blue-link" target="_blank" href="/users/ef49e6b7ec1e">極客人</a>
        <em>·</em>
        <span class="time" data-shared-at="2016-12-12T15:39:07+08:00">4天之前</span>
      </p>
      <h4 class="title"><a target="_blank" href="/p/f11d1fca16c6">Hello,Ruby!</a></h4>
      <div class="list-footer">
        <a target="_blank" href="/p/f11d1fca16c6">
          閱讀 23
</a>        <a target="_blank" href="/p/f11d1fca16c6#comments">
           · 評論 4
</a>        <span> · 喜歡 1</span>
        
      </div>
    </div>
  </li>
  <li class="have-img">
      <a class="wrap-img" href="/p/3d43727e04a5"><img src="http://upload-images.jianshu.io/upload_images/2154287-86190de5fd3071f7.png?imageMogr2/auto-orient/strip%7CimageView2/1/w/300/h/300" alt="300"></a>
    <div>
      <p class="list-top">
        <a class="author-name blue-link" target="_blank" href="/users/ef49e6b7ec1e">極客人</a>
        <em>·</em>
        <span class="time" data-shared-at="2016-12-08T00:02:08+08:00">9天之前</span>
      </p>
      <h4 class="title"><a target="_blank" href="/p/3d43727e04a5">Html5語義化標簽的啟示</a></h4>
      <div class="list-footer">
        <a target="_blank" href="/p/3d43727e04a5">
          閱讀 182
</a>        <a target="_blank" href="/p/3d43727e04a5#comments">
           · 評論 1
</a>        <span> · 喜歡 10</span>
        
      </div>
    </div>
  </li>
.....
  
  <li>
    <div>
      <p class="list-top">
        <a class="author-name blue-link" target="_blank" href="/users/ef49e6b7ec1e">極客人</a>
        <em>·</em>
        <span class="time" data-shared-at="2016-11-28T19:35:45+08:00">18天之前</span>
      </p>
      <h4 class="title"><a target="_blank" href="/p/114c27b6456c">網站自動跳轉到Cjb.Net的驚險之旅</a></h4>
      <div class="list-footer">
        <a target="_blank" href="/p/114c27b6456c">
          閱讀 21
</a>        <a target="_blank" href="/p/114c27b6456c#comments">
           · 評論 3
</a>        <span> · 喜歡 3</span>
        
      </div>
    </div>
  </li>

</ul>

正則匹配,摳出關鍵信息

上面我已經提取出有用的關鍵的HTML,現在要做的是讓爬蟲做同樣的事情。所以我用到啦正則匹配。

  • 正則匹配出粉絲", "關注", "文章", "字數", "收獲喜歡"
#從html中加載基本用戶信息
def loadAuthorBaseInfoFromHtml(authorInfo, latest_articles_html)  
infoKeys=["粉絲", "關注", "文章", "字數", "收獲喜歡"]  
infoValues = Array.new(infoKeys.length) 
 if /<ul class=\"clearfix\">([\s\S]*?)<\/ul>/ =~ latest_articles_html  then            authorInfoHtml= $1.force_encoding("UTF-8")   
 for i in 0 .. infoKeys.length-1     
 if /#{"<b>([0-9]*)</b><span>#{infoKeys[i]}</span>".force_encoding("UTF-8")}/=~ authorInfoHtml        
infoValues[i]= $1      
     end    
   end 
 end  
authorInfo.setBaseInfo(infoValues[0], infoValues[1], infoValues[2], infoValues[3], infoValues[4])
end

其他匹配代碼請參看源代碼

整合信息,多樣化地輸出成果物

當統計出用戶的文章信息后,就是把統計信息輸出來。為了讓輸出的產物更加豐富和自定義程度更高,所以我采取了渲染模板的方式,將數據和界面分離。
模板文件:

<body>
<section>
    <header>
        <h1>@{title}</h1>
        <section>統計時間:@{time}</section>
    </header>
    <section id="content">
    <table>
        <thead>
        <tr>
            <th>序號</th>
            <th>姓名</th>
            <th>文章數</th>
            <th>字數</th>
            <th>閱讀量</th>
            <th>收到評論</th>
            <th>收到喜歡</th>
            <th>小buddy姓名</th>
        </tr>
        </thead>
        <tbody>
        @{content}
        </tbody>
    </table>
    </section>
    <footer>@{footer}</footer>
</section>
</body>

然后在Ruby代碼中加載模板文件,并將@{title}、@{time}、 @{content}、 @{content}替換真實的統計信息

  def out2Html(title)
    tplFile = open @tpl
    tplContent = tplFile.read
    tplFile.close
    content =""
    for i in 0 .. @authorList.length-1
      author = @authorList[i]
      content+=format(" <tr>
            <td>%s</td>
            <td><a target= \"_blank\" href=\"http://jianshu.com/users/%s\">%s</a></td>
            <td>%s</td>
            <td>%s</td>
            <td>%s</td>
            <td>%s</td>
            <td>%s</td>
            <td>%s</td>
        </tr>", i, author.id, author.name, author.post_count, author.word_count, author.read_count, author.comment_count, author.liked_count, author.buddy)
    end

    today = Time.new;
    timeStr= today.strftime("(%Y-%m-%d %H:%M:%S)");
    footer="Powered By <a target=\"_blank\" href=\"http://wangbaiyuan.cn\">BrainWang@ThoughtWorks</a>"
    out = tplContent.gsub(/@\{title\}/, title)
    out = out.gsub(/@\{content\}/, content)
    out = out.gsub(/@\{footer\}/, footer)
    out = out.gsub(/@\{time\}/, timeStr)
    timeStr= today.strftime("(%Y-%m-%d)");
    file=open("output/#{title+timeStr}.html","w")
    file.write out
    print "\n輸出文件位于", Pathname.new(File.dirname(__FILE__)).realpath,"/",file.path
    file.close

  end

當然,那天只要加一個out2json就可輕松做一個API,實現更高的定制化效果啦

項目主頁

https://github.com/geekeren/jianshu_spider

使用方法

  • 下載項目代碼并運行
cd jianshu_spider/
 ruby main.rb

更詳細的項目介紹請移步Github項目主頁

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,093評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內容