最速で!最短で!真っ直ぐに!Facebookグループの書き込みを監視する方法!

皆さん、こんにちは!WAというと Web Application ではなく、RPGの方を思い出す MUGENUP の osada です。

いきなりの個人的な話で恐縮ですが、私が初めて書いたWeb Application はPHPでした。当時 Web というと、「SSI で include」したり、「perl で cgi」とか、少し大掛かりだと「Java Applet」?、程度しか知らなかった私には、HTMLの中にプログラムが書けるというのは衝撃的なことでした。PHPの真髄は、すぐに動くことにあるのではないかと思っています。そしてさらに個人的な意見で恐縮ですが、ソースコードで最も価値があるのは動くコードだと思っています。少し学術的に言えば、合目的性ですね。そう言う意味で、PHPは私の好きな言語の一つです。PHP、良い言語ですよね!

はい、ということで今回は、コードの美しさとか全くなし。動けばOK、ということで、Facebook Group への書き込みをウォッチして、新着があったらメールで知らせる ツールを作ってみたいと思います。

え、理由ですか?単に必要だったからです(笑)。

Facebook Developer に登録して、アプリを作成

  1. facebook developer へ登録

    https://developers.facebook.com/

  2. app へ

    f:id:mgnup:20131201224213p:plain

  3. 新しいアプリを作成 ボタン

    f:id:mgnup:20131201224220p:plain

  4. 新しいアプリを作成

    f:id:mgnup:20131201224455p:plain

  5. captcha

    f:id:mgnup:20131201224223p:plain

  6. 承認

    f:id:mgnup:20131201224226p:plain

  7. こんな感じに

    f:id:mgnup:20131201224254p:plain

  8. Graph APIエクスプローラーを使用する

    f:id:mgnup:20131201224209p:plain

  9. アクセストークンを取得

    f:id:mgnup:20131201224230p:plain

  10. user groups にチェック

    f:id:mgnup:20131201224243p:plain

  11. friends groups にチェックして、[Get Access Token]

    f:id:mgnup:20131201224233p:plain

  12. アクセストークンをコピー

    f:id:mgnup:20131201224240p:plain

  13. Facebook にアクセスする koala と メール送信用に mail をインストール

# Gemfile

source 'https://rubygems.org'
gem "koala", "~> 1.8.0rc1"
gem "mail"
group :test, :development do
  gem "pry"
  gem 'pry-byebug'
end

$ bundle

14.書く

watch_facebook.rb

# -*- coding: utf-8 -*-
require "koala"
require "mail"

ACCESS_TOKEN = ARGV[0]
GROUP_ID = ARGV[1]
USER_NAME = ARGV[2]
PASSWORD = ARGV[3]
EMAILS = ARGV[4..-1]
SMTP_SETTINGS = {
  address:   'smtp.gmail.com',
  port:      587,
  domain:    'smtp.gmail.com',
  user_name: USER_NAME,
  password:  PASSWORD
}
FROM = "hoge-report@mugenup.com"
SUBJECT = 'Hoge Report'

begin
  load "config.rb"
rescue LoadError
end

puts "access facebook ..."
graph = Koala::Facebook::API.new(ACCESS_TOKEN)
feeds = graph.get_connections(GROUP_ID, "feed")

puts "reject already feeds ..."
already_feeds_file = open("already_feeds.txt", "a+")
already_read_ids = already_feeds_file.readlines.map(&:chomp)
new_feeds = feeds.reject{|f| already_read_ids.include?(f["id"]) }

exit if new_feeds.size == 0

puts "create messages ..."
messages = new_feeds.map do |f|
  <<-EOS
  #{f["from"]["name"]}
  #{f["message"][0..100]}...
  #{'-' * 50}
  EOS
end
messages << "https://www.facebook.com/groups/#{GROUP_ID}/"

puts "send mail new feeds ..."
mail = Mail.new do
  from    FROM
  to      EMAILS.join(",")
  subject SUBJECT
  body    messages.join("\n")
end
mail.charset = 'utf-8'
mail.delivery_method :smtp, SMTP_SETTINGS
mail.deliver!

puts "store feed_ids (#{new_feeds.size}) ..."
already_feeds_file.puts(new_feeds.map{|f| f["id"]})
already_feeds_file.close

15.使う

$ bundle exec ruby watch_facebook.rb ACCESS_TOKEN GROUP_ID USER_NAME PASSWORD EMAILS ← 適宜読み替えて入力してください。

または、config.rbというのを作って、

f:id:mgnup:20131201230418p:plain

こんな感じに書いてから、

$ bundle exec ruby watch_facebook.rb

16.ACCESS_TOKENの長期化

このままだと、ACCESS_TOKEN の有効期間は1時間です。これを長期化します。

omniauth を入れる(心の)余裕は無いんです!

ということで、下記を参考に、(7)で確認した、app-idとapp-secret、および、アクセストークンを入力して、送信します。

https://graph.facebook.com/oauth/access_token? grant_type=fb_exchange_token& client_id={app-id}&client_secret={app-secret}&fb_exchange_token={short-lived-token} Unable to get a long term access token using facebook graph api - Stack Overflow

17.長期化されたアクセストークンを使う

f:id:mgnup:20131201224250p:plain

こんな感じで、新しく長期化されたアクセストークンが取得できます。 expires5184000 になっていることが確認できます。約2ヶ月、使い続けられます。

18.後は cron で登録するなりなんなり!

あ、cronbundle付きを呼ぶのはちょっと面倒ですが、頑張ってください!

ということで、Facebookのグループを監視するアプリが作れました!

ちょっと解説

設定を引数から受け取る部分

ACCESS_TOKEN = ARGV[0]
GROUP_ID = ARGV[1]
USER_NAME = ARGV[2]
PASSWORD = ARGV[3]
EMAILS = ARGV[4..-1]
SMTP_SETTINGS = {
  address:   'smtp.gmail.com',
  port:      587,
  domain:    'smtp.gmail.com',
  user_name: USER_NAME,
  password:  PASSWORD
}
FROM = "hoge-report@mugenup.com"
SUBJECT = 'Hoge Report'

初めに、一番速いのはなんだろう?と思って、ACCESS_TOKENを直書きしたのですが、これをコミットしてはいけないとゴーストが囁いたので、引数で渡すことにしました。

設定をファイルから受け取る部分

begin
  load "config.rb"
rescue LoadError
end

そうこうしているうちに、毎回引数で渡すのが面倒くさい、ということになり、ファイルに格納することにしました。このconfig.rb.gitignore で対象外にしました。

Facebook のグループからメッセージを獲得する部分

puts "access facebook ..."
graph = Koala::Facebook::API.new(ACCESS_TOKEN)
feeds = graph.get_connections(GROUP_ID, "feed")

特に解説することはありません

既に確認済みのメッセージを削除する部分

puts "reject already feeds ..."
already_feeds_file = open("already_feeds.txt", "a+")
already_read_ids = already_feeds_file.readlines.map(&:chomp)
new_feeds = feeds.reject{|f| already_read_ids.include?(f["id"]) }

exit if new_feeds.size == 0

……特に解説することはありません

メール送信用のメッセージを作る部分

puts "create messages ..."
messages = new_feeds.map do |f|
  <<-EOS
  #{f["from"]["name"]}
  #{f["message"][0..100]}...
  #{'-' * 50}
  EOS
end
messages << "https://www.facebook.com/groups/#{GROUP_ID}/"

......……特に解説することはありません(まさか解説する箇所は出てこないのでしょうか?)

メールを送信する部分

puts "send mail new feeds ..."
mail = Mail.new do
  from    FROM
  to      EMAILS.join(",")
  subject SUBJECT
  body    messages.join("\n")
end
mail.charset = 'utf-8'
mail.delivery_method :smtp, SMTP_SETTINGS
mail.deliver!

当初mailコマンドを使用していたのですが、

connect to aspmx3.googlemail.com[74.125.137.26]:25: Connection refused

ということで、macsmtpからダイレクトに送れなかったため、mailgemを導入しました。 これがなければ、もっとシンプルでもっと速く作れたのに、と思うとちょっと残念です。

さて、Mail ですが、送信相手が複数居る時は、カンマで区切りましょう。

charasetutf-8にしないと、Non US-ASCII detected and no charset defined.という警告がでます。

(説明することが合って良かったぁ〜)

送信したメッセージのIDを記録しておく部分

puts "store feed_ids (#{new_feeds.size}) ..."
already_feeds_file.puts(new_feeds.map{|f| f["id"]})
already_feeds_file.close

特に説明することはありません!

まとめ

以上が、Facebookの特定のグループの新着をメールで送信するツールです。

全くシンプルに、ただ動くことだけを考えて書いたコードですが、いかがだったでしょうか?

ついつい、「DBを使おう」とか「ActiveSuppoだけでも使おう」とか、「関数に分けよう」とか、「クラスを作ろう」とか色々考えてしまうのですが、問題を解決することだけに注目するというのも、また楽しいプログラミングですよね!

そうそうPHPが好きだと言いましたが、単に作成者のRasmus Lerdorf氏が好きなだけかもしれません。彼の発言は一読の価値があると思いますので、宜しければ一度、Rasmus Lerdorf - Google 検索してみてください!

宣伝

MUGENUP では、rails を使いたいエンジニアを募集中です。 無限流開発、ご一緒しませんか?

大きな裁量で自社サービス開発!Rubyエンジニアをウォンテッド! - 株式会社MUGENUPの求人 - Wantedly

f:id:mgnup:20131118023234p:plain

あ、WAでビンタしあう方を思い出す方は友達になりましょう。