Rails/SNS의 인기순으로 기사를 정렬하고 싶다 (카운트수를 취득해 보존) Facebook/Twitter/Pocket/하테나/Google+

블로그를 업데이트했습니다. 원래 기사는 이쪽

인기의 기사를 표시시키고 싶다고 생각했지만, 막상 하면 지표를 무엇으로 해도 좋은지 모른다.
페이스북에서 점유율이 많은 것도 있고, 하테나 북마크가 많은 것도 있다.

그래서 전부 해봤다.

  
social

취득하는 것은 다음의 5 종류.
  • Facebook 좋아요 숫자 (아마도 공유 수가 있습니까?)
  • Twitter 트윗 수
  • Pocket
  • Hatena Hatena 북마크 수
  • Google plus +1 숫자

  • 코드



    rake 태스크의 생각이었지만,
    컨트롤러에서도 사용할까라고 생각했기 때문에 모듈로했습니다.
    사용하기 때문에 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에서 자신의 도메인을 사용할 때 가장 좋은 방법을 생각했습니다.

    그런 경우에는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+ 카운트 수를 얻기 위해 다양한 실험을 한 결과
      

    htp : //를 r 또는 b 여과 d. jp/포 sts/2132

    좋은 웹페이지 즐겨찾기