Twitterで自分が誰にどれくらい 「いいね」 されたのかを調べる方法

成果物

自分のツイートが過去にどのアカウントから何件の「いいね」を貰ったかをグラフにしてみた。

f:id:teriyaki398:20181117094456p:plain:w500

作成したコードはGitHubに公開してます。

github.com

環境

今回の目的

2018年11月、次の衝撃的なニュースが話題に。

www.itmedia.co.jp

なんと、ツイッターの「いいね」機能が無くなるかもしれないそうです。

多くの人がこの機能で承認欲求を満たしていることでしょう。私もそうです。

それなら今のうちに、自分のツイートがどれくらいファボをもらっているのか、
そして、どのアカウントから何件もらっているのかを調べておきたい!

実はこれ、簡単な事ではないです

Twitter公式が公開しているAPI を使えば、

  • 自分のツイート一覧
  • フォローしているアカウント一覧

などの様々な情報が取得できますが、肝心の特定のツイートにいいねしたアカウント一覧という情報は取得できないのです。

API についての詳しい説明は割愛します。取得できる情報はページ下部に載せておきます。)

すなわち、公式API では「いいね の合計数」は調べられますが、「いいね の内訳」は調べられないのです(詳しくはこちら

また、合計数を調べたいだけならわざわざAPI を使わなくとも、
自分のアカウントのアナリティクス からCSV形式のデータをエクスポートしてなんやかんやすればいけそうです。

Twitter Analytics

解決策1

という事でAPIを用いずに取得する方法で頑張るしかないです。

色々調べた結果、 stackoverflow で同じような質問があったので、そちらを参考にします。

記事内の関数はツイートidを入れるといいね元アカウントidリスト を返します。

stackoverflow.com

各ツイートにツイートid と呼ばれる識別番号が付与されており、それを与えると対象ツイートにいいねしたアカウントのリストが得られるという訳です。

つまり、基本的な方針としては

  • Twitter API を用いて自分のツイートid 一覧を取得する
  • 各ツイートid ごとに、いいねしたアカウントidのリストを取得する
  • アカウントid を集計する
  • matplotlib を用いてグラフを描画する

という感じでしょう。

note

アカウントid とは@xxxxx のようなやつとは別物です。各ユーザに振り分けられた数列で、普段目にすることはありません。@xxxxx のようなid はscreen name と呼ばれ、API を叩いてアカウントid からscreen name に変換することができます。

ただし、この方法では誰でも閲覧できるアカウントしか対象になりません。
すなわち、鍵垢(非公開のアカウント)からのいいねは統計に入らないのです。

解決策2

鍵垢からのいいねも含めて調べたい場合。

  • Twitter API で相互フォローしてるアカウントリストを取得する
  • 各アカウントが「いいね」したツイート一覧を取得する
  • その中で自分のツイートの数を集計する

みたいにする必要があります。

パッと見で気づくかもしれませんが、これはかなり素直(あほ)な実装で、かなり時間がかかります(笑)

回しっぱなしで気長に待てる場合や、
定期的に回してデータベースを更新していく。みたいな運用を想定している人向けでしょうね。

(試しに期間を今年分に絞って回してみたが、それでも2、3時間ぐらいかかった)

コードの詳細な説明は省きます。

note

当然のことですが、鍵垢を含めた検索は自分のアカウントでしか行えません。他のアカウントに来ているいいねの統計は公開アカウントからのもののみです。

役立ちそうな情報メモ

Twitter Developer アカウントの取得について

Twitter API を使うためには開発者用のアカウントを取得する必要があります。

Developer — Twitter Developers

いつの間にか仕様が変わっていて、取得がかなり面倒になっていました。

ただ、面倒と言っても適当に入力したらすぐに取得できました。

masatoshihanai.com

アカウントid リストの取得方法

元記事のプログラムは Python 2系 で書かれていたので、Python 3系 に少しだけ書き換えました。

def getUserIDList(self,post_id):
    """
    指定されたIDのツイートにいいねした人のIDリストを返す

    post_id : string
        調べるツイートID
    """
    # 一秒まつ
    sleep(1)
    
    try:
        json_data = urllib.request.urlopen(url='https://twitter.com/i/activity/favorited_popup?id=' + str(post_id)).read().decode("utf-8")
        found_ids = re.findall(r'data-user-id=\\"+\d+', json_data)
        unique_ids = list(set([re.findall(r'\d+', match)[0] for match in found_ids]))
        return unique_ids
    except urllib.request.HTTPError:
        return False

クラスのメソッドにしたのでselfが付いてます。

matplotlib でいい感じの円グラフ

いい感じの円グラフの作成には以下を参考にしました。

qiita.com

普通にやると色が足りなくなってしまうので、

temp = cm.Pastel1(np.arange(9))
col = []
for i in range(len(data)):
    col.append(temp[i % 9])

このようにして 9色 をデータの数だけループするような色リストを作成しました。それだけです。

注意点

こちらにも書いてあるが、リクエストの間隔は少なくとも 1秒 空ける必要がある。

そのため、結局全てのツイートを調べるには、少なくとも Tweet数 x 1 [sec]だけの時間がかかってしまう。

2000件くらいツイートしていれば 最低でも 2000秒はかかる。

また、ユーザーid : screen_name の解決も 1ユーザずつ行なっており、こちらも1秒ずつ間隔を空ける必要がある。よって、「ツイート数はそれほどでもないが、大量のアカウントからいいねされている」みたいな感じのアカウントもかなり時間がかかってしまう。

API で取得できる情報

APIでツイートを取得したとき、以下の情報が付随してくる。

キー 内容
created_at ツイートされた日時
id ツイートに一意に割り当てられるid
id_str id の 文字列
text ツイートの本文
truncated ツイート本文が長すぎて途中で切られたかどうか
entities ハッシュタグや画像・動画などに関する情報
extended_entities 複数の画像を取得したいとき
source どの端末からの送信か
in_reply_to_status_id (リプの場合)どのツイートへのリプライか
in_reply_to_status_id_str どのツイートへのリプライかの文字列
in_reply_to_user_id リプするアカウントのid
in_reply_to_user_id_str リプするアカウントのid の文字列
in_reply_to_screen_name リプするアカウントのscreen_name
user ツイート送信者の情報(JSON)
geo ツイートを送信したときの位置情報(非推奨らしい)
coordinates こちらも送信時の位置情報
place ツイートに関連付けられている場所情報(必ずしもこの場所からの送信とは限らない)
contributors アカウントを複数人で運営している時の話
is_quote_status 引用ツイートかどうか
retweet_count リツイートされた数
favorite_count いいねされた数
favorited 認証済みユーザーにいいねされたかどうか
retweeted 認証済みユーザーにリツイートされたかどうか
possibly_sensitive ツイートにリンクがあり、そのコンテンツが危険な可能性がある
lang 言語

続・将棋ウォーズの棋譜をまとめて保存する方法

以前、将棋ウォーズの棋譜将棋ウォーズ棋譜検索β で検索してローカルに保存 という流れをやってみたが、 よく見たら2018年8月以降の棋譜が出てこなくなっていた。(私だけ?)

ということで、最近の棋譜を取得するべく、別の手法で棋譜をダウンロードしてみたいと思う。

さらに今回は、ローカルに保存するだけではなく、ローカルのデータベースに保存して棋譜を再生できるようにしてみた。 その際に必要となったセットアップなどのメモ。

成果物

データベースに棋譜を登録

最近のアップデートで戦型のタグがつくようになった。棋譜を解析しなくてもどういった内容かわかるのでとても嬉しい。

f:id:teriyaki398:20181110174918p:plain:w550

一応再生できる(必要性はない) f:id:teriyaki398:20181110174707g:plain

使用したコードは GitHub に公開している。

github.com

環境

  • macOS 10.14
  • anaconda3-5.0.0
  • MongoDB 4.0.3

棋譜のダウンロード

基本的な方針は前回とほぼ変わらないが、今回は公式のサイトから収集する。

https://shogiwars.heroz.jp/users/history/ユーザーID/web_app?locale=ja

アクセスすると分かるが、対局履歴を一ヶ月分(?)くらい閲覧することができる。

このページから棋譜のURLを取得してく。具体的にはgame_replayクラスの中にあるaタグにリンクが貼ってある。

特定のページにアクセスしたい時は以下のようなパラメータを設定する。

params = {
    "page" : ページ番号(一番最初のページは page = 1)
    "gtype" : 対局ルール(3切れは"sb"、10秒将棋は"s1")
}

とりあえずデータベースに登録したい時は GitHubにコードを公開しているので、

  1. コードをダウンロード
  2. 以下の手順でスクリプトを実行する
$ python updateDB.py

これでMongoDBに棋譜データが閲覧できる分だけ保存される。重複して登録しないようにしてあるので、後からもう一度実行することで新しい分だけを取得できる。

対局ルールは以下の規則で命名してある。

10分切れ負け 10m
3分切れ負け 3m
10秒将棋 10s

もしデータベースじゃなくてローカルにファイルとして保存したいときは、

  1. コードをダウンロード
  2. 以下の手順でスクリプトを実行する
$ python downloadKifu.py

とすれば良い。

データベースを利用する準備

MongoDB のインストール

MongoDB というオープンソースのデータベースを使ってみる。

MongoDB はJSON形式でデータを格納できるので使い勝手が良い(個人的に)

  1. homebrew を使ってインストール
$ brew install mongodb
  • mongodb の起動
$ brew services start mongodb
  • 起動しているかどうかの確認
$ brew services list
  • mongodb の停止
$ brew services stop mongodb
  • 特定のコレクションに含まれているデータを全て表示する
$ mongo
> show dbs
> use [db name]
> show collections
> db.[collection name].find()
コマンド 操作
mongo mongoDB のシェルを起動
show dbs データベース一覧を表示
use [name] 使用するデータベースを変更
show collections コレクション一覧を表示
db.test_collection.find() コレクションに登録されている内容を全て表示

pymongo のインストール

今回はPython 経由でデータを追加・参照する予定なので、PyMongoというライブラリをインストールする。

  1. pip を使ってインストール
pip install pymongodb
  • mongoDBへのアクセス
>>> from pymongo import MongoClient
>>> client = MongoClient("localhost", 27017)
  • データベースを使用(なければ作成)
>>> db = client["db_name"]
  • コレクションを使用(なければ作成)
>>> collection = db["collection_name"]
  • コレクションに追加
>>> type(post)
<class 'dict'>
>>> collection.insert_one(post)

複数追加したい場合は,辞書のリストを作成し,

>>> type(post)
<class 'list'>
>>> collection.insert_many(post)
  • コレクションを参照

全て取ってくる

>>> collection.find()

Cursor というイテレータオブジェクトが返ってくる. for文などで回すことで一つずつ参照できる.

一つ取ってくる

>>> collection.find_one({"key": "000"})

引数として渡した条件に一致するデータが返ってくる。

上での例でいうと、"key" が "000" のデータで一番最初に見つかったやつが返ってくる。

棋譜を再生する

Python の将棋ライブラリとしてpython-shogiがある。

とても使いやすいのでこちらを使って棋譜を再生してみた。

使い方

  1. pip を使ってインストール
$ pip install python-shogi
  • 将棋盤を描画するまで

f:id:teriyaki398:20181110183852p:plain:w550

ポイント
入出力はSFEN形式で行う.
http://ch.nicovideo.jp/kifuwarabe/blomaga/ar795371

  • 駒を動かす
>>> board.push(shogi.Move.from_usi(["操作"]))
  • 盤面を描画する
>>> print(board.kif_str()))
  • SFEN形式の文字列を取得
>>> board.sfen()

Tips

過度なアクセスはサーバーに負荷をかけるので十分に注意しよう。 少なくとも1秒くらい間隔を開けながらアクセスする!

Raspberry Pi Camera Module V2 の使い方 (Python 3)

Raspberry pi 公式が販売しているカメラモジュール Camera Module V2 を使ってみたメモ

https://www.raspberrypi.org/products/camera-module-v2/

参考にしたもの

公式の情報

Getting started with the Camera Module - Introduction | Raspberry Pi Projects

先人の情報

PythonでRaspberry Pi カメラを制御する
【Raspberry Pi】Camera Module V2を接続する

環境

モジュールの準備

何はともあれ、Raspberry Pi 3 と カメラモジュールを接続します

こちらが詳しいです。向きなどに注意しましょう

studio.beatnix.co.jp

次に、raspi-config > 5. Iterfacing Options > P1. Cameraからカメラを有効にしましょう

Pythonからの操作方法

picameraパッケージのインストール

% pip install --upgrade pip
% pip install picamera

写真を撮影する

from picamera import PiCamera
from time import sleep

camera = PiCamera()
camera.resolution = (800, 600)

camera.start_preview()
sleep(2)
camera.capture("./image.jpg")
camera.stop_preview()
  • camera.resolution(width, height)で撮影する写真のサイズを指定
  • camera.start_preview()でカメラを起動(ラズパイがディスプレイに接続されていると確認できる)
  • cmera.capture([保存したい場所]) で写真を撮影できる
  • camera.stop_preview()でカメラを終了する

基本的な使い方はこれだけ。

こんな感じで撮影できましたか?

f:id:teriyaki398:20181014193545j:plain:w300

動画の録画

動画も撮影できます。

from picamera import PiCamera
from time import sleep

camera = PiCamera()
camera.resolution = (800,600)

camera.start_preview()

camera.start_recording("./movie.h264")
sleep(10)
camera.stop_recording()

camera.stop_preview()

動画も写真とほぼ同様の手順で録画できます。異なるのは、

  • camera.start_recording([保存する場所]) で録画開始
  • sleep([秒数]) で何秒間録画するかを指定
  • camera.stop_recording()で録画停止

の部分だけ。

エフェクト

なぜか多種類のエフェクトが用意されています。ぜひ活用してみましょう。

使用できるエフェクトは以下の通りです。

>>> camera.IMAGE_EFFECTS
{'none': 0, 'negative': 1, 'solarize': 2, 'sketch': 6, 'denoise': 7, 'emboss': 8, 'oilpaint': 9, 'hatch': 10, 'gpen': 11, 'pastel': 12, 'watercolor': 13, 'film': 14, 'blur': 15, 'saturation': 16, 'colorswap': 17, 'washedout': 18, 'posterise': 19, 'colorpoint': 20, 'colorbalance': 21, 'cartoon': 22, 'deinterlace1': 23, 'deinterlace2': 24}

使用する場合は次のように指定します。

camera.image_effect = "[エフェクト名]"

具体例

f:id:teriyaki398:20181014231423j:plain:w300 f:id:teriyaki398:20181014200113j:plain:w300 f:id:teriyaki398:20181014200131j:plain:w300 f:id:teriyaki398:20181014200122j:plain:w300

テキストを挿入する

以下のようにすることで、写真や動画にテキストを表示できます。

camera.annotate_text_size = [フォントサイズ]
camera.annotate_text = [表示したいテキスト]

注意すること

サイズの限度

写真の場合は2592 x 1944で、動画の場合は1920 x 1080までです。

また、最大解像度での撮影を行う際は、

camera.framerate = 15

でフレームレートを15に設定する必要があります。

ファイルフォーマット

写真のフォーマットを変更することもできます。

変更したいときは以下のように指定する。

camera.capture("[ファイルパス]", format="[フォーマット名]")

利用できるフォーマットは以下の通り。

jpeg, png, gif, bmp, yuv, rgb (24-bit RGB), rgba (32-bit RGBA), bgr (24-bit BGR), bgra (32-bit BGRA), raw

動画も同様にフォーマットを変更できます。

camera.start_recording("[ファイルパス]",format="[フォーマット名]")

利用できるフォーマットは以下の通り

h264, mjpeg, yuv (YUV420), rgb (24-bit RGB), rgba (32-bit RGBA), bgr (24-bit BGR), bgra (32-bit BGRA)

カメラを起動してからの待ち時間

公式には、カメラを起動してから最低2秒間は明るさの調整のために待てと書いてあります

試しに0秒から1秒おきに撮影してみました。

0秒時点
f:id:teriyaki398:20181014193538j:plain:w300

1秒時点
f:id:teriyaki398:20181014193541j:plain:w300

2秒時点
f:id:teriyaki398:20181014193545j:plain:w300

確かに0秒時点での写真は全体的に暗く青みがかって見えます。1秒時点と2秒時点の画像もよーく見ると違いますが、そこまで大きな違いは無さそうです。

この辺りは目的に合わせて調整しよう。

画像が180度回転していたら

今回の環境では問題なかったが、上下逆さに撮影されてしまう場合は以下のように指定することで画像を回転できます

camera.rotation = 180

とりあえず主要な機能はこんなところでしょう

詳しい内容は以下で確認できます

10. API - picamera.camera Module — Picamera 1.10 documentation