11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?