LoginSignup
11
10

More than 5 years have passed since last update.

Rails / SNSの人気順で記事を並び替えたい(カウント数を取得して保存) Facebook / Twitter / Pocket / はてな / Google+

Last updated at Posted at 2015-02-04

ブログを更新しました。元の記事はコチラ


人気の記事を表示させたいなぁと思ったけど、いざやるとなると指標を何にしていいのかわからない。
Facebookでシェアが多いものもあれば、はてなブックマークが多いものもある。

だから全部にしてみた。

  
social

取得するのは次の5種類。

  • Facebook いいね数(たぶんシェア数も?)
  • Twitter ツイート数
  • Pocket
  • Hatena はてなブックマーク件数
  • Google plus +1数

コード

rakeタスクのつもりだったけど、
コントローラーでも使うかなーと思ったのでモジュールにしました。
Nokogiriつかうので bundle install しておいてください。
  
なんだかDRYじゃない感じですが取得の仕方がそれぞれ違ってくるので、
ばらばらのメソッドにしておいた方が楽だと思います。


module SnsCount

    require 'open-uri'
    require 'nokogiri'

    def pocket_count(url)
        api = "http://widgets.getpocket.com/v1/button?v=1&count=horizontal&url="
        content = get_content(api + url)
        return 0 if content.blank?

        content.xpath("//*[@id='cnt']").try(:text)
    end


    def twitter_count(url)
        api = "http://urls.api.twitter.com/1/urls/count.json?url="
        html = open(api + url).read
        return 0 if html.blank?

        json = JSON.parse(html)
        json["count"]
    end


    def hatena_count(url)
        api = "http://api.b.st-hatena.com/entry.count?url="
        html = open(api + url).read
        return 0 if html.blank?

        html
    end


    def facebook_count(url)
        api = "http://graph.facebook.com/"
        html = open(api + url).read
        return 0 if html.blank?

        json = JSON.parse(html)
        json["shares"]
    end


    def google_count(url)
        api = "https://apis.google.com/_/+1/fastbutton?url="
        content = get_content(api + url)
        return 0 if content.blank?

        content.xpath("//*[@id='aggregateCount']").try(:text)
    end


    def get_content(url)
        html = open(url).read
        Nokogiri::HTML(html, nil, 'utf-8')
    end

end

  

#Pocket
http://widgets.getpocket.com/v1/button?v=1&count=horizontal&url=

#Twitter
http://urls.api.twitter.com/1/urls/count.json?url=

#はてな
http://api.b.st-hatena.com/entry.count?url=

#Facebook
http://graph.facebook.com/

#Google+
https://apis.google.com/_/+1/fastbutton?url=

それぞれカウント取得したいページのURLをつけて叩けば何かしら返ってくるので、
あとはそこから数字を抜き取っているだけ。
  

コントローラーで使ったり

app/controllers/posts_controller.rb

class PostsController < ApplicationController

    require 'sns_count'
    include SnsCount

    def show
      @post = Post.find(params[:id])
      @pocket = pocket_count("http://www.workabroad.jp/posts/#{post.id}")
    end

end

rakeタスクで使ったり

今回やったのはこっち。
毎日1回このタスクを走らせればいいかなと思ってる。

  
カウント数をDBに保存するので、それ用のカラムが必要です。
migrate/20150203140953_add_sns_count_to_post.rb

rake db:migrate してね。

class AddSnsCountToPost < ActiveRecord::Migration
  def change
    add_column :posts, :pocket_count, :integer, default: 0
    add_column :posts, :twitter_count, :integer, default: 0
    add_column :posts, :hatena_count, :integer, default: 0
    add_column :posts, :facebook_count, :integer, default: 0
    add_column :posts, :google_count, :integer, default: 0
  end
end

  
lib/task/get_sns_count.rake

namespace :sns do

    desc "Get SNS count and store them in DB."

    task get_sns_count: :environment do
        get_sns_count
    end

    def get_sns_count
        sns = SnsController.new

        Post.all.where(published: true).each do |post|
            # www(sub domain) is required.
            # Otherwise twitter/google/hatena won't return the count properly.
            base_url = "http://www.workabroad.jp/posts/"
            url = base_url + post.id.to_s
            puts "Getting SNS count: #{url}"
            post.pocket_count   = sns.pocket_count(url).to_i
            post.twitter_count  = sns.twitter_count(url).to_i
            post.hatena_count   = sns.hatena_count(url).to_i
            post.facebook_count = sns.facebook_count(url).to_i
            post.google_count   = sns.google_count(url).to_i

            puts    "p:#{post.pocket_count} | t:#{post.twitter_count} | h:#{post.hatena_count} | " +
                        "f:#{post.facebook_count} | g:#{post.google_count}"
            if post.changed?
                post.save
                puts "Saved!"
            else
                puts "Not Changed."
            end
            sleep(1)
        end
    end

end

  
このブログはルートドメインへのアクセスをwww.に転送しています。
→詳しくはこちら。
heroku で 独自ドメインを使う際の最善策を考えた | Workabroad.jp

そんな場合は、
http://workabroad.jp/:id ではなく
http://www.workabroad.jp/:id とURLを指定しないとうまくカウントが返ってきません。
違うページだと判断されているんだと思う。

ここハマった。
× Twitter / Google / はてな
○ FacebookとPocketはルートでもwww.でも同一とみなしてくれる。

表示

あとはSNSカウントの合計が多い順に記事を並べれば完成。
リアルタイムではないけど、ランキング用途には十分だと思います。

app/models/post.rb

class Post < ActiveRecord::Base

    scope :by_sns, -> { unscoped.order('pocket_count + twitter_count + hatena_count + facebook_count + google_count DESC') }

end

  
app/controllers/posts_controller.rb

class PostsController < ApplicationController

    def index
      @popular_posts = Post.by_sns.limit(10)
    end

end

  
以上です。
しかし一番人気のある記事がドラゴンボールの曲だとは…。
なんだか拍子抜け。。

参考

はてなブックマーク件数取得API - Hatena Developer Center
Google+のカウント数を取得するために色々試した結果がこちら
  

http://workabroad.jp/posts/2132

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10