【Ruby】Twitter検索の不便な面を改善してみました

# 概要
## Twitter検索機能のクソ仕様について
　Twitterでは、[ブラウザで表示した際の検索ボックス](https://twitter.com/search-advanced?lang=ja)や[Twitter API](https://syncer.jp/twitter-api-matome/get/search/tweets)から、ツイートを検索することができます。
　しかし、このツイート機能には大きな問題があることが前から指摘されていました。
　つまり、**検索ワードが『名前』や『スクリーンネーム』にまで引っかかる**のです。
　これにより、検索しても欲しい結果と違うものが多くヒットする……といった悲劇が頻発することになります。

**↓「[みぽりん](http://dic.pixiv.net/a/%E3%81%BF%E3%81%BD%E3%82%8A%E3%82%93)」で検索した結果の例。予想に反して、[ガルパン](http://dic.pixiv.net/a/%E3%82%AC%E3%83%BC%E3%83%AB%E3%82%BA%26%E3%83%91%E3%83%B3%E3%83%84%E3%82%A1%E3%83%BC)とは縁のない検索結果になってしまうことが分かる**
　![検索結果1](https://qiita-image-store.s3.amazonaws.com/0/29802/af2890e2-cac5-adb2-40d8-f7a22942cb10.png)

## あの有名人も被害に！
　この生地を書こうと思った切っ掛けは、この前[岸田メル先生がTwitterで嘆いていた](https://twitter.com/mellco/status/786024211684794368)ことから来ています。検索キーワードを「岸田メル -from:mellco」としても、**名前に『岸田メル』を含むアカウントのツイートが引っかかってしまう**とのこと。まったく嘆かわしい話です……。

# 解決策
　そこで、とりあえずRubyで検索用プログラムを作ってみました。

```twi_search.rb
require 'twitter'

# 検索キーワード
keyword = 'みぽりん'
# 自分のアカウントを弾きたい場合は''以外にする
exclude_account = ''
# 検索する範囲
search_tweets = 100

# Application-only auth
# consumer_keyとconsumer_secretは、自分でアプリを登録してからコピペすること
# 参考サイトの例：http://hello-apis.blogspot.jp/2013/03/twitterapi.html
client = Twitter::REST::Client.new(
  consumer_key:    'YOUR_CONSUMER_KEY',
  consumer_secret: 'YOUR_CONSUMER_SECRET',
)

# 検索キーワードを作成
if exclude_account != ''
	query = "#{keyword} -from:#{exclude_account} -to:#{exclude_account}" 
else
	query = "#{keyword}"
end

# 検索結果を取得する
result_tweets = client.search(query, lang: 'ja', count: search_tweets, result_type: "recent", exclude: "retweets", since_id: nil)

# 検索結果を表示する

result_tweets.take(search_tweets).each do |tw|
  # 名前やスクリーンネームが検索キーワードを含む場合は除外する
  next if tw.user.name.downcase.include?(keyword.downcase)
  next if tw.user.screen_name.downcase.include?(keyword.downcase)
  # リプライが検索キーワードを含む場合は除外する
  # (「@スクリーンネーム」といった形で本文中に使われることがあるため)
  match_flg = false
  tw.full_text.scan(/@[0-9a-zA-Z_]{1,15}/).each{|word|
    if word.downcase.include?(keyword.downcase)
      match_flg = true
      break
    end
  }
  next if match_flg
  # ツイートを表示する
  puts "#{tw.user.name}@#{tw.user.screen_name} #{tw.created_at}"
  puts "https://twitter.com/#{tw.user.screen_name}/status/#{tw.id}"
  puts tw.full_text
  puts ''
end
```
　これを使って、同じように「みぽりん」というワードで検索した例がこちらになります。
　先ほどと違い、**意図しないツイートがほどよく省かれている**のが分かりますね。
![検索結果2](https://qiita-image-store.s3.amazonaws.com/0/29802/961f0e87-61be-1c12-17e8-de49c3b750e2.png)

# 注意点
　Twitter関係のアプリケーションを開発したことがある人にとっては**常識**ですが一応説明しておきます。
　ソースコード中に「YOUR_CONSUMER_KEY」と「YOUR_CONSUMER_SECRET」とある部分は、各々の環境毎に適宜置き換えてください。
　これらは認証処理のために必須のフレーズで、[アプリケーションをTwitter社に登録](http://hello-apis.blogspot.jp/2013/03/twitterapi.html)すれば受け取れます。
　認証すると、APIの仕様上、様々な使いかたができることからダミー文字列としました。

# 追記
　冷静に考えますと、どうせTwitter APIで『本文だけ』取り出せますので、そこだけピンポイントで検索しなおせば済む話でした。
　というわけで書き換えたコードは次の通りです。

```twi_search2.rb
require 'twitter'

# 検索キーワード
keyword = 'YSR'
# 自分のアカウントを弾きたい場合は''以外にする
exclude_account = 'ysrken'
# 検索する範囲
search_tweets = 1000

# Application-only auth
# consumer_keyとconsumer_secretは、自分でアプリを登録してからコピペすること
# 参考サイトの例：http://hello-apis.blogspot.jp/2013/03/twitterapi.html
client = Twitter::REST::Client.new(
  consumer_key:    'YOUR_CONSUMER_KEY',
  consumer_secret: 'YOUR_CONSUMER_SECRET',
)

# 検索キーワードを作成
if exclude_account != ''
	query = "#{keyword} -from:#{exclude_account} -to:#{exclude_account}" 
else
	query = "#{keyword}"
end

# 検索結果を取得する
result_tweets = client.search(query, lang: 'ja', count: search_tweets, result_type: "recent", exclude: "retweets", since_id: nil)

# 検索結果を表示する

result_tweets.take(search_tweets).each do |tw|
  # 本文からリプライ部分を除去する
  full_text = tw.full_text.gsub(/@[0-9a-zA-Z_]{1,15}/, '')
  # 本文に検索キーワードを含まない場合は除外する
  next unless full_text.downcase.include?(keyword.downcase)
  # ツイートを表示する
  puts "#{tw.user.name}@#{tw.user.screen_name} #{tw.created_at}"
  puts "https://twitter.com/#{tw.user.screen_name}/status/#{tw.id}"
  puts tw.full_text
  puts ''
end
```