LoginSignup
4
2

More than 5 years have passed since last update.

RailsでTypetalkを定期的にスクレイピングして「いいね」数を記録しておく

Posted at

なぜこんなことをするのか

Typetalkには「いいね」つける機能があります。
しかしTypetalkには「いいね」を集計するツールがありません。
仕方ないのでapiを叩いて、調べることにしました。

ここで問題が発生しました。
Typetalkのapiは、トピック(掲示板でいうスレッド)の中の投稿の情報が
最新から200件のみしか取得できません。
従って、全件の情報をアプリケーションのデータベースに保持しておきたい場合
定期的にバッチ処理をして、データベースに記録しておきます。
その上で「いいね」数をカウントしてデータベースに格納します。

バッチ処理にはrakeファイルを使う

以下がrakeファイルのソースコードです。

post.rake
# encoding: utf-8

namespace :post do
  desc "投稿データを取得する。"

# $ rake post:update
# :environmentは超大事。ないとモデルにアクセスできない

  task :update => :environment do
    topics = Topic.all

    # httpインスタンスの生成
    http = Net::HTTP.new('typetalk.in', 443)
    http.use_ssl = true

    # Typetalkのトークンの代入
    client_id = ENV['CLIENT_ID']
    client_secret = ENV['CLIENT_SECRET']

    # アクセストークンの発行
    res = http.post(
        '/oauth2/access_token',
        "client_id=#{client_id}&client_secret=#{client_secret}&grant_type=client_credentials&scope=topic.read"
    )
    if res.code != '200'
      next
    end
    json = JSON.parse(res.body)
    access_token = json['access_token']

    topics.each do |topic|
      req = Net::HTTP::Get.new("/api/v1/topics/#{topic.topicId}?count=200&direction=backward")
      req['Authorization'] = "Bearer #{access_token}"
      res = http.request(req)
      if res.code != '200'
        next
      end
      res= JSON.parse(res.body)

      res['posts'].each do |post|
        if Post.where(post_id: post['id']).exists? then
          @post = Post.find_by(post_id: post['id'])
          if post['account']['isBot'] == true
            @post.destroy if @post
            next
          end
          @post.like = post['likes'].count
        else
          if post['account']['isBot'] == true
            next
          end
          @post = Post.new
          @post.topic = topic
          @post.post_id = post['id'].to_s

          @post.like = post['likes'].count
          p "UTC時間"
          p post['createdAt']
          p "JST時間"
          p post['createdAt'].in_time_zone
          @post.posted = Time.parse(post['createdAt']).in_time_zone
        end
        @post.save
      end
      topic.updated_at = Time.now()
      topic.save
    end
  end
end

解説

トピック情報を記録するTopicテーブル
投稿情報を記録するPostテーブル
の2つを使用して処理をしています。

まず前準備として、TopicテーブルにTypetalkから取得できるトピックのIDを入れてください。

topicオブジェクトをeachメソッドで処理して、各トピックごとに先頭200件の投稿情報を取得します。
apiのcountパラメーターは最大値200にしておきます。
ここらへんは下記のapiのリファレンスを参照ください。
投稿メッセージリストの取得

    topics.each do |topic|
      req = Net::HTTP::Get.new("/api/v1/topics/#{topic.topicId}?count=200&direction=backward")
      req['Authorization'] = "Bearer #{access_token}"
      res = http.request(req)

返却されたjsonは、posts単位の情報が、先ほどのcountパラメーターで設定した数の情報が返却されます。
postのIDが登録済みであれば、update処理、存在しなければcreate処理を行います。

      res['posts'].each do |post|
        if Post.where(post_id: post['id']).exists? then

各投稿の['account']['isBot']には、botか人間かの判定が格納されているので、
botは必要がなければ、データベースにinsertしないようにしましょう。

          if post['account']['isBot'] == true

['likes]は「いいね」をしてくれたアカウントの情報が配列で入っているので、countメソッドを使用して「いいね」数を計測しましょう。

          @post.like = post['likes'].count

このrakeファイルの実行コマンドは下記の通り
このコマンドをジョブスケジュラーに登録して、定期実行する
これでTypetalkの全発言を補足することができる。
自分は、Herokuを利用しているのでHeroku Schedulerを利用している。

$ rake post:update

最後に

毎度のことながら、Typetalkのapi関連の記事は需要があるのだろうか
一応、備忘録のために残しておこう。

4
2
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
4
2