マロングラッセ Mk.II

赤西真論のブログらしきもの

TwitterのTLから二次元画像だけ収集しよう! (2)TLの画像を全部収集する

前回、環境構築と動作チェックが完了しました。ということで今回より根幹機能を実装していきます。

今回は重要なTLからの画像収集を行っていきます。

まず最初に完成スクリプトを載せてしまいますね。

というのも、解説をするにはスクリプトを動かしてもらってからのほうがやりやすいからです。

giste6f26ed9e3241c10c7a600196d661bb7

スクリプトのところにあるRawボタンを右クリックして、リンク先を保存してもらうとそのまま保存できます。

今後のスクリプトもほとんどこの形式になると思います。

では、ダウンロード出来たら前回用意した環境のフォルダーにスクリプトを置いてstart.batを実行しましょう。

コマンドプロンプトが表示されたら、python TL_capture.pyと入力して実行してみます。(前回作成したsetting.jsonが必須です)

 

今回は前回と違って、勝手に終了しません。「Start Streaming」と同時に今日の日付のフォルダーが作成されます。

その後、放置しているとSaveという文字列が流れ始めます。

終了したい場合は、ウィンドウを閉じるのが早いです。Ctrl+Cを連打しても止めることが可能ですが、時間がかかります。

では、スクリプトの説明です。まずは、どんな動作をしているか書いてみます。

ざっくりとしたフローチャートを書いてみました。大体の流れはこれで把握出来ると思います。

では、次に実際のスクリプトを見ながらいきます。今回は関数、クラス単位で見ていきます。

 

関数 get_oauth(10~15行目)

一番最初にある関数です。ここでは設定ファイルを読み込み、Twitterの認証情報を作成します。

この認証情報を利用することでTwitter APIを扱えるようになります。

今回はTwitter APIを使用するためにTweepyと呼ばれるライブラリを使用しています。

www.tweepy.org

関数 main(91~103行目)

間にクラスが挟まっていますが、一旦置いておきます。これがメインの関数となります。

まず、先ほどの関数 get_oauthを使用して認証情報を取得します(93行目)。

次にこの認証情報を使用してストリームにアクセスします(94行目)。このストリームとは、Twitterの情報をリアルタイムで取るためのAPIです。

今回はストリームのうち、User Streamを使用しています。TLが自動で更新されるクライアントとかは全てこれです。

ストリームにアクセスする時ですが、何やら引数が3つほどありますね。

1つ目の引数は認証情報、3つ目の引数はSSLを使用するかの設定です。2つ目は何なのでしょう?

ここにはストリームから流れてきた情報を処理するとクラスを指定します。今回指定しているのは、関数 get_oauthと関数 mainの間に挟まっていたあれです。詳細は後ほど説明します。

接続できたら、「Start Streaming!」と表示します。先ほど見たやつですね。

次にwhile文で無限ループに入っています(96~103行目)。これはある対策のためです。

実はUser Streamがたまにエラーを吐きます。コレによってスクリプトが落ちます。

通常なら別にスクリプトを再起動すれば問題無いのですが、サーバーなどで常時画像を回収していると気づかないことが多いです。

その対策のためにtry~exceptによる自動復帰を行っています。まあ、これのせいでCtrl+Cがなかなか反応しないのですが...

ちなみにこの対策をやっても、死ぬことがあります。困ったものです。

で、tryの部分でUser Streamを監視するメソッドを呼び出しています(97~98行目)。

後ろのexceptですが、1つ目はCtrl+Cの監視(99~100行目)、2つ目はその他の例外発生時の処理(101~103行目)です。

2つ目のexceptでは、「UserStream Error」と表示した後に60秒待つ処理が入ってます。

クラス StreamListener(17~89行目)

では、一番重要なクラス StreamListenerの説明をしていきます。このクラスはTweepyにあるStreamListenerを継承しています。

メソッドごとに説明を行っていきます。

__init__(18~23行目)

これはコンストラクタみたいなものです。インスタンス生成時(今なら94行目で呼び出された時)に実行されます。

ここではまず引数に渡されたTwitter API用のオブジェクトを自身のメンバー変数に取り込んでいます(20行目)。

その後、現在の日付を取得しています(22行目)。この日付を使用して、フォルダー名が決定します。

最後にメソッド mkdirを実行します(23行目)。このメソッドは後ほど説明します。

on_error、on_timeout(25行目~31行目)

これらは接続してる時にエラーが発生した際に呼び出されるメソッドです。

通常だと必要無いはずなのですが、Tweepy側で正しく処理されないようなのでこちらで管理を行っています。

ツイートを長期間収集する実験(プログラム準備編(2)) - Qiita

内容はただ単にTrueと返すだけです。

mkdir(84行目~89行目)

on_statusを飛ばして、こっちを先に説明します。

ここでは、保存先のフォルダーパスを作成して(86行目)、フォルダーの作成を行い(8~88行目)、必要な変数を初期化(89行目)します。

フォルダー作成時はすでに存在しないかの確認を行っています。ただ、これだけだとちょっと確認不足です。今後、変更していきます。

必要な変数は、今回はfilenoしか存在しません。このスクリプトでは、画像を取得した順に連番を付けるのでそのためのカウンターです。

on_status(33~82行目)

このスクリプトの根幹部分です。正直、ここさえ知っていれば何とかなりますw

このメソッドは、User Streamにツイートが流れてきた際にそのデータを処理する部分となります。

ちなみにツイートをstatusオブジェクトと呼びます。

結構コメントが書いてあるので、大体の流れは分かると思います。なので、ざっくりとだけ説明していきます。

まず、日付を確認します(38~41行目)。日付が変わっていたら、保存先のフォルダーを変えます。

次にstatusオブジェクトを確認して、どのようなツイート形式かを確認します(43~57行目)。

確認する内容はRTツイートか、引用ツイートか、画像が複数枚付いているかです。

RTツイートでもユーザーが変わったことになり、statusオブジェクトが入れ子構造になります。なので、そのstatusオブジェクトを取り出します。

引用ツイートも同様に入れ子構造になるので、取り出します。

複数枚画像の確認ですが、複数枚画像投稿は後から付けられた機能なのでstatusオブジェクトの構造が異なります。

このオブジェクト構造の差を吸収するために確認を行っています。

ただ、1枚の場合でも同じ構造になったような気がするんですよね。修正したい人がいればご自由にどうぞ。

次に画像が付いてるかどうかを複数枚画像チェックのときに行ったのでそのフラグで回収するかどうかを判定します(60行目)。

次に自分のツイートがRTされても流れてくるので、これを確認します(62行目)。この判定はもっと前にやってもいい気がするのですが...

最後に付いてる画像を全て保存します(63~82行目)。

まず、くっついてるmediaが画像かどうかをチェックします(64~65行目)。

次にURLを取り出し、拡張子を取得します(67~68行目)。また、保存する際にファイル名も作成しておきます(69行目)。

次に画像を一旦メモリー上に保存します(71~75行目)。これは画像判定に回す際に必要となるためです。

今回はそのままメモリー上の内容をファイルに書き込んでいます(77~79行目)。

保存ができたら、「Save : (ユーザーID)-(ファイル番号)」の形式でコンソールに出力しています。先ほど、コマンドプロンプトにずっと流れていたのはこれです。

最後にファイル番号のカウンターを1増やし、メモリー上の画像を削除しています。

 

なんとか全部説明できました。今回説明した根幹部分は結構昔に書いたもので、それをほとんどそのまま持ってきているので汚いソースですねw

一応、ところどころは修正していますが、記事を書きながら「こうしたほうがいいなー」みたいなアイデアが思い浮かんだり...

とりあえず、これで画像をTwitterから取得できるようになりました。次から二次元画像の判定をやっていきます。

判定部分の説明なのですが、あんまり専門的なことは説明できません。その都度、参考になるようなリンクは貼るつもりです。