StatsBeginner: 初学者の統計学習ノート

統計学およびR、Pythonでのプログラミングの勉強の過程をメモっていくノート。たまにMacの話題。

エンジニア泣かせの「日本の住所」は誰が決めているのか

 住所のデータを機械で扱おうと思った時、日本の住所は「1の1」と「1丁目1番」と「1-1」のように表記が統一されていないこと、数字の部分だけでなく町名や字名の部分も複数の書き方があること、漢字の旧字新字が混じること、アメリカ等のようにカンマでの分かち書きがされていないことなどの理由によって、処理が難しいというのはよく知られた話です(分かち書き問題についてのわかりやすい記事はこちら)。
 それで苛立ったエンジニアの人が「なんで統一ルールを作らねぇんだよ!」とブチ切れたりすることがあったりするわけですが(私はエンジニアではないのでブチ切れません)、「じゃあその統一ルールは誰が作ればいいんだ?」と考えると、「そもそも誰が決めてるんだっけ?」という疑問に行き当たります。
 そこで、日本の住所が何に基づいてどのように決定されているのかについて、備忘のために要約しておきました*1。未確認事項が2点残っており、分かり次第追記します。というか知ってる方いたら教えてください。


 法的根拠のある権限に基づいて、誰かが定義したり決定したりしている住所というのは、以下の1〜5ですべて説明できるはずです(6は法的根拠なしです)。

  1. 市区町村名:当該地域の議会の議決を経て、都道府県知事が国に届け出る。
  2. 町名又は字名:地方自治法260条に従って、市区町村が議決の上都道府県知事に届け出、知事が告示する。
  3. 街区:町又は字の下の単位であり、「番地」とかが該当。住居表示に関する法律に従って市区町村が決める。
  4. 住居番号:街区に含まれる住居に番号を振るもの。「○番●号」の「●号」のこと。住居表示に関する法律に従って市区町村が決める。
  5. 地番:不動産登記法に基づいて登記所(法務省の出先機関)が決める、土地に振られた番号。住居表示とは別物なので注意。
  6. 部屋番号等:住居番号に集合住宅の番号まで含めている場合以外は、法律上の根拠はない。


 「2.町又は字」には、「大字」「小字」「町」「丁目」などが全部含まれます。「丁目(丁)」は、地方自治法の概念上は「町又は字」に含まれるので、たとえば「霞が関1丁目」で一つの町・字を構成しています。郵便番号は丁目の手前までを表すので、混乱しやすいです。
 またこれは、「市区町村」というときの「町」とは別モノです(間違える人はいないでしょうが)。私は昔、「大阪府豊中市新千里北町」という「町」に住んでましたが、こういう「町」のことです。


 京都市内の「上ル」とか「西入ル」とかは有名で(わかりやすい解説はこちら)、単位としては「町又は字」の上位(前に付ける)にあたるのですが、これは慣習的な呼称であって法的な位置づけはありません。つまり、誰かが法令に則って決定したり定義したりしているわけではない。
 ただしこれらは住基の情報として登録されているとのことなので、住民基本台帳法に則った市区町村長の権限による住民登録事務として、お墨付きが与えられているとは言えるかもしれません。
 なお、「京都市上京区今出川通浄福寺西入二丁目東上善寺町」のように、丁目が町の前に付いている場合がありますが、これが「町又は字」の一部なのか、慣習的な表記の一部なのか確認していません。そのうち分かったら追記します。


 「3.街区」には、「街区方式」と「道路方式」があり、「街区方式」の場合はたいてい数字になっていて、いわゆる「番地」(「○番●号」の「○番」)がこれに相当します。この「○番」の数字を街区符号と呼びます。街区符号は数字が一般的ですが、アルファベットや漢字の場合もあります。「道路方式」の場合は、住所は「○○通り●号」とかになります。


 「3.街区」と「4.住居番号」をあわせて、「住居表示」と言います。住居表示に関する法律は市街地を対象としたものなので、田舎では住居表示が整備されていません。その場合は、町・字より下の単位として「5.地番」が住所として用いられることになります。つまり「1 + 2 + 5」という住所になっているということです。


 集合住宅の部屋番号は、「4.住居番号」として定義される(つまり住居表示の一部になっている)場合と、「6.部屋番号等」に相当するような、住居表示に含まない「方書」として定義されている場合の両方があります。ちなみに方書は戸籍の登録時には含まないことになっています。


 「5.地番」は登記所、つまり国の出先機関が決めているので扱いがややこしく、住居表示によっても表現できるし地番によっても表現できるというような家があり得るわけですが、戸籍法では、戸籍を登録するときに住居表示を用いても地番を用いても良いことになっています。
 地番は、不動産登記法では「市、区、郡、町、村及び字」の下に付ける番号および枝番のことになってるんですが、この法律でいう「字」に、「2.町又は字」の「町」が含まれるのか分かりませんでしたので、わかったら追記します。
 「番外地」とはこの「地番」が振られていない土地(例えば、明治以来ずっと国有地である場所は登記されたことがないため地番がない)のことです。


 こうやって整理してみると、住所表記の統一ルールを作ると言った場合、そもそも「住居表示」が全ての建物をカバーしていないという点がネックになりそうですね。決定権限の異なる「地番」とまざった形で戸籍が作られているというのはややこしいです。
 京都市の例のような慣習的な呼称については、何通りもある可能性がありますが、どれか1個を選んで「町又は字」に取り込んで自治体が決定してしまえばいいような気もします。もともと法的根拠がないのだから、新たに定義することによって「歴史的な呼称が消えてしまう」というわけでもないでしょう。

*1:Wikipediaと法律と役所のホームページを読んだだけです

Python作業メモ: 残しておくとマズそうな自分のツイートをまとめて削除する(YouTubeリンク編)

著作権侵害にあたるYouTube動画へのリンクを削除する

 たまにツイッターで、YouTubeのリンクを貼り付けたツイートをしていますが、よく考えたら違法アップロードに該当するものを拡散してしまっている可能性があります。可能性とかいう曖昧なレベルで考えるのが面倒なので、いっそのことYouTubeのリンクを共有した過去のツイートをいっぺんに削除してしまおうと思いました。


 ついでに、人の悪口を言ってるようなツイートも削除して、自分のアカウントを「とてもいい人のアカウント」に変貌させていこうかとも思い出しましたが、まだ手法が検討できていません。(私の場合は必要性が低いですが、最近の就活生などには必要かも?)
 ツイートの感情分析を行って、負の感情の高ぶりが感じられるツイートを自動削除していけばいいんでしょうかね。本文を形態素解析で単語に分けて、人名を含むツイートを抽出した上で、さらに単語ごとに感情のポジ/ネガ度合いを定義した辞書*1*2を使って評価するようなことはできると思いますが、誹謗中傷・罵詈雑言のようなものを特定することってできるんでしょうかね。よくわからないのでそれは後回しにし、今日はYouTubeのリンクが入ってるツイートを削除するという、一瞬で終わる作業だけやりました。


 ところで、TwitterのAPIから自分のツイートを全件調べようとしても無理です。APIでツイートをまとめて取得する系の機能では、過去3000件分しか情報が取れないからです(ツイートidを個別に指定して、もっと古いツイートを参照したり操作したりすることはできる)。なので、Twitterが公式に提供している「全ツイート履歴ダウンロード」の機能を使えばいいと思います。まず全件履歴から該当するツイートのidを取得して、その後にAPIからid指定で消すわけです。


f:id:midnightseminar:20170504122227p:plain


 ダウンロードしたzipファイルを解凍するとフォルダになってるのですが、その中の'data/js/weets/'という場所に'2017_05.js'というようなファイル名で、月ごとのツイートがJavaScriptで保存されています。中身をみると、

Grailbird.data.tweets_2017_05 =
[{
  1件目のツイートデータ
}, {
  2件目のツイートデータ
}, {
  3件目のツイートデータ
}]


 というような感じで、配列の中にツイートのjsonが埋め込まれたような内容になっています。
 最初はこれを使おうと思ったのですが、よく見たら解凍後のフォルダの直下に'tweets.csv'というファイルも入っていて、上記のjsファイルよりも情報量は少ないのですが、ツイートのID、本文、リンク、retweetとreply関係の情報が含まれており、今回の目的には十分だったので、そっちを使うことにしました。

該当ツイートの抽出方法

 私の場合、YouTubeのリンクを含むツイートは3通りの経路で投稿しています。

  1. MacまたはiPhoneのSafariから、[↑]マークの共有ボタンでツイートする。
  2. YouTube側のツイッター連携機能でツイートする。
  3. YouTubeの動画ページをはてブに登録する際に、はてブの機能でブクマをツイートする。


 1つ目の方法だと、ツイート内に"https://www.youtube.com/watch?v=なんたらかんたら"とか"https://m.youtube.com/watch?v=なんたらかんたら"というURLが含まれます。(本文の見た目上はhttps://wwwなどは省略されますが、リンク先情報として入っている。)
f:id:midnightseminar:20170504122305p:plain


 2つ目の方法だと、"https://youtu.be/なんたらかんたら"という短縮URLが含まれます。
f:id:midnightseminar:20170504122411p:plain


 3つ目の方法だと、"http://htn.to/なんたらかんたら"という短縮URLが含まれますが、これははてブが生成するものなので、YouTube動画以外のリンクも同じ形式になります。
f:id:midnightseminar:20170504122421p:plain


 1つ目の場合は、リンクのところに"youtube.com"が含まれるツイートを検索すればOKです。
 2つ目の場合は、同じく"youtu.be"が含まれるツイートを見つければいいです。
 3つ目の場合は、htn形式のURLを探すと関係ないものも含まれてしまいます。ツイート本文に"動画タイトル - YouTube"という文字列が含まれる場合がほとんどなので、この文字列を探すことにします。
 例外があるかもしれませんが、これでほぼカバーできるでしょう。
 いずれも本文のデータを参照すれば見つかる気がしますが、今回はURLについてはexpanded_urlsというフィールドを見ることにしました。

Pythonでの作業

 以下、作業内容です。

import pandas as pd
import csv
import tweepy


# csvをpandasに読み込み
tw_df = pd.read_csv('解凍後フォルダ/tweets.csv', encoding='utf-8')


# 条件に合致する行を抽出し、ツイートID、本文、リンク先URLのフィールドだけ取得。
yt_df = tw_df.ix[\
      (tw_df['text'].str.contains(' - YouTube'))\
    | (tw_df['expanded_urls'].str.contains('youtube\.com'))\
    | (tw_df['expanded_urls'].str.contains('youtu\.be'))\
    , ['tweet_id', 'text', 'expanded_urls']]


# あとで念のため目視確認用に、抽出したツイートのcsvを出力しようと思っており、
# 改行コードが含まれていると何かをミスりそうなので半角スペースに置き換える。
# pandasの要素を直接書き換える方法がよくわからなかったので、textのフィールド
# をリストとして取り出して、そのリストを使ったデータフレームを新たに作った・・・
text_list = list(yt_df['text'])
for i in range(len(text_list)):
    text_list[i] = text_list[i].replace('\n', ' ')
yt_df = pd.DataFrame({'tweet_id':yt_df['tweet_id'],
                      'text':text_list,
                      'expanded_urls':yt_df['expanded_urls'],
                     },
                     columns=['tweet_id', 'text', 'expanded_urls']
                    )


# 確認用にcsvを出力
yt_df.to_csv('~/Desktop/yt.csv', index=None, encoding='utf-8', quoting=csv.QUOTE_NONNUMERIC)


# 削除すべきツイートのidリスト
rem_ids = list(yt_df['tweet_id'])


# 削除の処理はAPIで自分のアカウントを操作して行います。
# 件数があまりにも多い場合、リクエスト制限にひっかかります。


# APIハンドラインスタンスの生成
CONSUMER_KEY = '自分のコンシューマキー'
CONSUMER_SECRET = '自分のコンシューマシークレット'
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
ACCESS_TOKEN = '自分のアクセストークン'
ACCESS_SECRET = '自分のアクセスシークレット'
auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
api = tweepy.API(auth)


# 削除します。
# 試しにやってみてる時に何件か削除してしまい、どれを削除したか
# わからなくなったので、try-exceptで飛ばすことにしました・・・
for id in rem_ids:
    try:
        api.destroy_status(id)
    except:
        print('couln\'t delete id:' + str(id))
        continue


 pandasのto_csvでcsvを出力する時、引用符を付けるかどうかは、quotingという引数にPythonの標準モジュールcsvのプロパティを与えれば良いです。数値以外の情報に引用符をつけるなら'csv.QUOTE_NONNUMERIC'、全部に引用符を付けるなら'csv.QUOTE_ALL'、付けないなら'csv.QUOTE_NONE'といった具合。


 べつに著作権の侵害に当たらないような動画リンクも多いわけで、私の場合上記の条件で抽出した結果は220件程度(ツイート総数は1万3000件ぐらいです)だったので、目視確認用に出力したCSVをExcelなどで表示して、手作業で安全なやつを削除対象から除くことはできたと思います。しかし過去のツイートに特に未練はないので全部削除としました。

黒歴史の抹消について

 動画のリンクに限らず、残しておくと都合の悪いツイートを一気に消すという作業は、一部の就活生などには需要があるかもしれません。

  • 著作権侵害
  • 誹謗中傷、差別的言動
  • 政治的発言
  • 極度の下ネタ
  • 機密情報
  • 違法行為の告白(未成年の飲酒など)
  • 他人のプライバシー情報(顔写真なども)
  • 自分のプライバシー情報


 など、つい投稿してしまったけど消したいつぶやきはけっこうあるかもしれません。これらは件数が少なければ、根性で洗っていけば手作業で消すことはできるでしょう。また考え方として、古いツイートを残しておいてもとくにメリットはない場合が多いと思うので、一定期間経過したツイートはすべて消すという考え方もありなような気がします。


 しかしTwitterのデータは色々なサイトが勝手に収集して保存しているので、全部に削除依頼を出すのは大変です。というか無理。
 ネット上では、黒歴史的なものを完全に消し去ることはできないのだと覚悟を決めて、匿名管理を徹底するか、上品なつぶやきを心がけるかしたほうがいいですね。

フォルダの差分同期をExcel(VBA)で行う

 VBAの勉強エントリです。
 自分がデータ分析とかをやる場面ではべつにVBAを使う必要はなく、RやPythonでやればいいのですが、会社の仕事で他の人たちと共同作業する上では、Excelとかのマクロが組めると便利だろうなと思うことが多いです。
 しかしほっといたらいつまでたっても勉強しないので、「とりあえず使いこなせるレベルにはならなくていいから、VBAで何かやるときの作業イメージをつかんで、いざ必要になったときの心理的ハードルを下げておきたい」と思い、ちょっといじってみています。
 何かVBAでできそうなタスクがあったときに、「ググりながら時間かければ俺でも何とかできるかも」という前向きなモチベーションを持てるようにしておくのが目的です。
 
 

フォルダの同期

 VBAで2つのフォルダの中身を比較して、差分の同期をする方法を検索したら、robocopyというWindowsのコマンドをVBAから起動する方法が載っていた。
【robocopyコマンドでフォルダーをバックアップ/同期する】【エクセル2013,VBA】 - DuKiccoの雑記
Office TANAKA - Excel VBA Tips[MS-DOSコマンドの標準出力を取得する]
Tech TIPS:Windowsのrobocopyコマンドでフォルダーをバックアップ/同期させる - @IT


 VBAの練習台にと思って、適当にボタンを配置して、同期元と同期先のフォルダをそれぞれ選択し、同期するマクロを作りました。
 練習台なのでかなり適当です。
 「同期元を選択」ボタンを押すとダイアログが開くので、フォルダを選択すると、E4セルに書きこまれます。「同期先を選択」はE9セルに書き込みます。
 それで「同期!」ボタンを押すと差分同期が始まり、B15以下のセルに処理のログが書きこまれます。「結果の削除」ボタンを押すとログが消えます。


f:id:midnightseminar:20170317220352p:plain
 
 

同期元フォルダを選択するボタン用のコード

 前回のエントリでも使った「msoFileDialogFolderPicker」ってのを使い、GUIで対話的にフォルダを選択して、選択したフォルダのパスを所定のセルに記入するようにします。

Sub GetSrcPath()

    Dim strSrcPath As String                           ' フォルダのパスを格納する変数
    Dim dlgFolder As Office.FileDialog                 ' ダイアログを受け取る変数
    Set dlgFolder = Application.FileDialog(msoFileDialogFolderPicker)
    
    If dlgFolder.Show = False Then                     ' キャンセルが押されたら抜ける
        Exit Sub
    
    Else
        strSrcPath = dlgFolder.SelectedItems(1) & "\"  ' 選択されたフォルダのパスを受け取る
        Range("E4").Value = strSrcPath                 ' セルに書き込む
    End If
    
End Sub

 
 

同期先フォルダを選択するボタン用のコード

上とほぼ同じです。

Sub GetDstPath()

    Dim strDstPath As String                           ' フォルダのパスを格納する変数
    Dim dlgFolder As Office.FileDialog                 ' ダイアログを受け取る変数
    Set dlgFolder = Application.FileDialog(msoFileDialogFolderPicker)
    
    If dlgFolder.Show = False Then                     ' キャンセルが押されたら抜ける
        Exit Sub
    Else
        strDstPath = dlgFolder.SelectedItems(1) & "\"  ' 選択されたフォルダのパスを受け取る
        Range("E9").Value = strDstPath                 ' セルに書き込む
    End If
    
End Sub

 
 

フォルダを同期するボタン用のコード。

 前提として、VBEの参照設定で「Windows Script Host Object Library」への参照をONにしておく必要があります。
 WScript.Shellは、Execメソッドに対して文字列でWindowsのコマンドを与えてやればそれが実行されるようで、かなり便利ですね。
 なおrobocopyは、MacやLinuxのrsyncっていうコマンドに似ていて、「robocopy src dst /option」という書き方で、srcからdstへのコピーを行ってくれるようです。/mirというオプションは、フォルダの中がばっちり同じ内容になるやつ。
 コマンドの実行に時間がかかるので、VBA側では、処理が終了するまで待つためのループを書くらしいのですが、ふつうに書くとOSのコマンドに処理を投げたあとはほったらかしでVBA内の次の処理に行ってしまうということなんでしょうか。
 処理のログは、1つのセルに書くと見づらいので、改行コードで分割して配列にし、ループで1行1行書いていくようにしました。

Sub RunRoboCopy()

    Dim WSH    As IWshRuntimeLibrary.WshShell
    Dim wExec
    Dim sCmd   As String
    Dim Result As String
    Dim Src    As String
    Dim Dst    As String
    Dim Lines  As Variant
    Dim i      As Integer

    Src = Range("E4").Value '同期元フォルダのパス
    Dst = Range("E9").Value '同期先フォルダのパス

    Set WSH = CreateObject("WScript.Shell")

    sCmd = "robocopy " & Src & " " & Dst & " /mir"  '/mirオプションを付けたrobocopyコマンド
    Set wExec = WSH.Exec("%ComSpec% /c " & sCmd)    'コマンドの実行

    Do While wExec.Status = 0                       '処理が終了するのを待つループ
        DoEvents
    Loop

    Result = wExec.StdOut.ReadAll     ' 結果の取得
    Lines = Split(Result, vbCrLf)     ' 改行コードで分割して配列を得る
    For i = 0 To UBound(Lines)        ' 1行ごとに出力するループ
        Cells(i + 15, 2) = Lines(i)
    Next i

    Set wExec = Nothing
    Set WSH = Nothing

End Sub

 
 

結果を削除するボタン用のコード

下端まで指定する方法が良く分からなかったので1万行目まで消すようにした。

Sub ClearResult()
    Range(Cells(15, 2), Cells(10000, 2)).Clear
End Sub

メールデータ解析のため、Outlookの分類フォルダをまたいでメッセージを一括テキスト変換

 Outlookのマクロ(VBA)に関するエントリです。


 オライリーの『入門機械学習』はRによる機械学習の教科書で、正直どっちかというと今は「同じタイトルでPythonによる分析の教科書」の方が欲しい感じなのですが、これもけっこう写経しているだけでも勉強になります。


入門 機械学習

入門 機械学習

  • 作者: Drew Conway,John Myles White,萩原正人,奥野陽,水野貴明,木下哲也
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2012/12/22
  • メディア: 大型本
  • 購入: 2人 クリック: 41回
  • この商品を含むブログ (11件) を見る


 代表的な機械学習モデルの基本的な処理が一通り解説されており、実際にサンプルデータを使って一からコードを書いて分析を進めていくという内容で、前処理から順番に「こういうところでこういう問題が起きるだろ?だからこうやって解決するんだぜ」みたいな感じになっており、プロジェクトを進行させていくノリで書かれていて面白いです。
 それで、この教科書の最初の演習は、ナイーブベイズ分類器によるスパムメールの検出になってるのですが、これを読むとなんか「自分のメールを練習台にして色々分析してみたい」という気になってきます。


 ところで、メールボックスに溜まっているメールのデータを解析しようと思ったら、とりあえずテキストファイルでメール1通1ファイルみたいなデータが欲しいところです(区切りがハッキリしていれば1つのテキストファイルにつなげて書いてあっても良いですが)。
 『入門機械学習』でも、1通1ファイルのテキストファイルを使って分析を進めていました。


 それで、Windowsのパソコンで使っているOutlook2010内のメールデータを、どうやって吐き出そうかと考えました。Gmailのデータでもやってみたいですが、それは別途考えることに。
 一応、Outlookでメールボックスを開き、メッセージを全選択して「ファイル」→「名前を付けて保存」でTXT形式を選択すると、メッセージ全件が1つのテキストファイルにまとまったものを出力することができます。
 しかしこの方式だと、出力されたテキストファイル中でメールの区切りが厳密に判定するのが無理そうでした。また、私の場合メールボックスのフォルダ分類を細かくやりすぎて大変なことになってるので、全部やるのがめんどくさい。
 そこで、メッセージを「1通1ファイル」にして吐き出すマクロを書くことにしました。といっても私はVBAをほとんど触ったことが無いので*1、ググって色々参考にしながら作業しました。
 以下、ディスク上の保存先フォルダとの混同を避けるため、Outlookアプリ上に表示されるメールボックスの「フォルダ」は「ボックス」と呼ぶことにします*2


 1つのメールボックスの中身を、1通1ファイルで出力するだけなら、↓の知恵袋で紹介されているコードが使えます。
Outlookの複数のメールを、ワードファイルまたはテキストファイルとして... - Yahoo!知恵袋


 しかし私はかなりたくさんのボックスに、しかも階層的にメッセージを保存しているので、その全体を再帰的に掘れるようなマクロじゃないと使えません。そこでさらにググって見つけた、


選択したフォルダーとそのサブフォルダーのすべてのアイテムを MSG ファイルとして保存するマクロ | Outlook 研究所


 このページで紹介されているマクロを使わせて頂くことにしました。写経してたら少しだけVBAの雰囲気を感じ取ることができました。
 これはmsgファイルとして保存するコードだったんですが、これを少し改変して使いました。


 上記サイトのコードだと、保存フォルダを1つ決めてパスをコード中に書き込んでおき、Outlook上でボックスを選択してこのマクロを実行すれば、選択中(アクティブ)のボックスに属しているフォルダやメールが、その階層構造を保ったまま、保存フォルダに記録されます。
 メール1件を「日付_時刻_件名」という形式のファイルにする処理や、ボックスの階層を再帰的にたどっていく処理を書いてくれているので、大変助かります。 
 
 
 ただ私の場合、10年分ぐらいのメールが、いくつものOuotlookメール保存データファイル(pstファイル)に分けて記録されていて、それぞれを開くとまたいくつものボックスに分かれています。上記のコードでやる場合、pstファイルの単位で保存先のフォルダを定義し、いちいちコード中に書き込んでから実行しなければならない。
 それだとちょっと手間なので、

  1. Outlookでpstファイルを開いた状態でpstファイル(を表すメールボックス名)を選択する
  2. マクロを実行する
  3. 選択したメールボックス名と同名のフォルダを、保存フォルダ内に生成する
  4. 生成したフォルダの中に、メールのデータを、メールボックスの階層構造に従って記録していく


 といったことがやりたい。
 そこで結論としては、上記サイトのマクロに、

  • "olMSG"(msgファイル形式を表す)をolTXT(txtファイル形式を表す)に変更
  • ファイル命名時の拡張子を".msg"から".txt"に変更
  • 選択中のメールボックスの名前を取得して、その名前のフォルダを生成し、それを保存フォルダとする


 という変更を加えました。
 あと、元サイトのコードでは「Dim objItem As MailItem」の部分のAs以下がコメントアウトされてましたが、たぶん間違いなので「'」を取りました。コメントアウトしてあっても、方がvariant型になるだけで、マクロ自体は正常に動きますが。
 コードは以下のとおりです。コメントは私が細かく付しましたが、なんか見づらくなりました。


【追記】
 保存先のフォルダを、GUIで対話的に選択できるように、コードを追加しました。
 Outlook自身はFileDialogメソッドをサポートしていないので、裏でExcelを起動してダイアログを表示させ、選択したフォルダのパスを取得してExcelを終了するというルーチンを追加することになります。
 前提として、VBEの「ツール→参照設定」で、「Microsoft Excel 14.0 Object Library」を参照可能にしておかないと、上手く動きません。
 コードは以下のページを参考にしました。
マクロ実行中にフォルダーを選択・指定してもらう-FileDialog(msoFileDialogFolderPicker):エクセルマクロ・Excel VBAの使い方
Outlook: FileDialog object error - Microsoft Community


 メインのルーチンから、「ダイアログで保存先フォルダを選択させる」ルーチンと、「選択中ボックス内のアイテムを再帰的に掘ってテキストファイルとして保存先フォルダに保存していく」ルーチンを、順番に呼び出していますが、前者において、ユーザがキャンセルボタンを押して選択を中止した場合の処理を書く必要があります。このとき、選択用ルーチン(Private Function)内でExit Functionするだけだと、呼び出し元は停止しないで、後者の保存用ルーチンが実行されてしまい、実際やってみたらDドライブ直下に保存されるという動きになりました。
 なので、キャンセルボタンが押された場合は、呼び出し元のメインルーチンに対して停止信号となるような返り値を返してやり、メインルーチン自体をExitするようにしました。
【/追記】
 
 

' 以下は、メインのルーチン。
' ディスク上の保存フォルダを指定し、Outlookで選択中のメールボックス名を
' 取得して同名のフォルダを保存フォルダ内に生成した上で、選択中のメールボックス
' と保存先を引数として保存用ルーチンに処理を投げる。

Sub SaveMailsAsText()
	Dim Selected As String
	Selected = SelectFolder()      ' フォルダを選択させるルーチンを呼び出して返り値を取得

	If Selected = "::::STOP::::" Then  ' 停止信号を受け取ったら、このメインルーチンを停止
		Exit Sub

	Else
		Dim SAVE_PATH As String
		SAVE_PATH = Selected & "\"                                         ' パスの最後に\を付ける必要がある
		Dim objFSO As Object                                               ' ファイルシステムオブジェクトを入れる変数の宣言
		Set objFSO = CreateObject("Scripting.FileSystemObject")            ' ファイルシステムオブジェクトの生成
		objFSO.CreateFolder SAVE_PATH & ActiveExplorer.CurrentFolder.Name  ' 選択中のメールボックスと同名のフォルダを生成
		
		' 保存用ルーチンに処理を投げる
		SaveFolderRecursive ActiveExplorer.CurrentFolder, SAVE_PATH & ActiveExplorer.CurrentFolder.Name & "\"
		
	End If
	
End Sub


' 以下は、ダイアログを表示して対話的にフォルダを選択させ、パスを取得するルーチン。
' Outlook自体はFileDialogメソッドをサポートしていないので、裏でExcelを起動して、
' ExcelのFileDialogメソッドでパスを取得し、変数に格納した上で、ExcelをQuitする。
' 前提として、VBEのツール→参照設定でExcelオブジェクトライブラリを参照可にしておく必要がある。

Private Function SelectFolder() As String

	Dim strFolderPath As String               ' フォルダのパスを格納する変数
	Dim objSurrogate As Object                ' 裏で動くエクセルを受け取る変数
	Dim dlgFolder As Office.FileDialog        ' ダイアログを受け取る変数

	Set objSurrogate = New Excel.Application  ' Excelを起動
	objSurrogate.Visible = False              ' ユーザには見せない

	' エクセルから、フォルダを選択させるダイアログを起動
	Set dlgFolder = objSurrogate.Application.FileDialog(msoFileDialogFolderPicker)
    
	' キャンセルボタンがクリックされたら呼び出し元ルーチンに停止信号を送る
	If dlgFolder.Show = False Then

		SelectFolder = "::::STOP::::"  ' 適当に考えた停止信号

	Else

		' 選択されたフォルダーのパスを変数に格納
		strFolderPath = dlgFolder.SelectedItems(1)

		objSurrogate.Quit                      ' Excelを終了
		Set objSurrogate = Nothing             ' 参照の解除(不要?)
		MsgBox strFolderPath & "に保存します"  ' 確認メッセージの表示(OKを押させるだけ)

		SelectFolder = strFolderPath           ' Functionプロシージャは関数名に返り値を格納する

	End If

End Function


' 以下は保存用ルーチン。
' Outlook上での選択中メールボックスを受け取って、当該ボックス内のアイテムに
' ファイル名を付けて保存フォルダに保存していく。
' 最後の方に、「ボックス内のボックス(サブボックス)」に対してこのルーチン
' 自身を適用する入れ子構造が埋め込まれているので、ボックスの階層を再帰的に
' 辿っていくことができる。

Private Sub SaveFolderRecursive(objFolder As Folder, strSavePath As String)
	On Error Resume Next       ' エラーを無視
	Dim objItem As MailItem    ' メールアイテム用の変数を宣言
	Dim strFileName As String  ' 保存する際のファイル名用の変数を宣言
	Dim i As Integer           ' ループのカウンター用の変数を宣言
	Dim arrErrChars            ' ファイル名・パスに使えない文字一覧用の変数を宣言
	Dim objFSO                 ' ファイルシステム操作用の変数を宣言
	Dim objSubFolder As Folder ' Outlookのサブボックス取得用の変数を宣言
	arrErrChars = Array("\", "/", ":", "*", "?", """", "<", ">", "|")  ' ファイル名・パスに使えない文字
	Set objFSO = CreateObject("Scripting.FileSystemObject")            ' ファイルシステムオブジェクトの生成

	' 選択中ボックスを受け取って中味のアイテム一覧からforループ
	For Each objItem In objFolder.Items
		' 日時と件名からファイル名生成
		strFileName = Format(objItem.ReceivedTime, "yyyymmdd_hhnn_") & objItem.Subject

		' エラーが発生したら受信日時ではなく最終更新日時をファイル名とする
		If Err.Number <> 0 Then
			strFileName = Format(objItem.LastModificationTime, "yyyymmdd_hhnn_") & objItem.Subject
			Err.Clear
		End If

		' ファイル名に使えない文字を_に置き換えるループ
		For i = 0 To UBound(arrErrChars)
			strFileName = Replace(strFileName, arrErrChars(i), "_")
		Next

		' ファイル名が 260 文字を超えないように、左から250字を取る
		strFileName = Left(strSavePath & strFileName, 250)

		' 同一日時に同じ件名のメールがあるとファイル名が同じになるので、
		' 同名のファイルがすでにある場合は2~の連番を付けるというループ
		If objFSO.FileExists(strFileName & ".txt") Then
			i = 2
			While objFSO.FileExists(strFileName & "(" & i & ").txt")
				i = i + 1
			Wend
			strFileName = strFileName & "(" & i & ")"
		End If

		' ファイルをフォルダに保存する
		objItem.SaveAs strFileName & ".txt", olTXT
	Next

	' 選択中ボックス内のボックス(サブボックス=サブフォルダ)一覧にforループを適用し、
	' 各サブボックスに対してこのルーチン自身を適用するという、再帰的処理
	For Each objSubFolder In objFolder.Folders
		If Not objFSO.FolderExists(strSavePath & objSubFolder.Name) Then  ' 保存フォルダに同名フォルダがなければ
			objFSO.CreateFolder strSavePath & objSubFolder.Name           ' 保存フォルダにサブフォルダを作成
		End If
		SaveFolderRecursive objSubFolder, strSavePath & objSubFolder.Name & "\"  ' サブフォルダに同じ処理を適用
	Next

End Sub

 
 
使い方としては、

  1. Outlookを起動する。
  2. Alt + F11でVBAエディタを開き、新規プロジェクトの標準モジュールで上記コードを書き込んで保存する。
  3. 保存したいメールボックスを選択し、Alt + F8のあと上記プロジェクト名を選択して実行する。


 とするだけです。
 また、リボンのユーザ設定でボタンを割り当てればワンクリックで動かせるようになります。*3
 複数のpstファイルをまたいで一発で保存することもできるかもしれませんが、調べていません。とりあえず上記マクロを、pstファイルの数だけ実行するという対応にしました。中途半端ですが・・・。
 なお、添付ファイルは無視です。


 実際やってみたら、メールの数があまりにも多い(1万通以上とか)メールボックスの場合、途中から「ファイルアクセス権のエラーのため保存できません」というメッセージが出て1通も保存ができなくなってしまいました。原因はよく分かりません。ググったら、そのエラーは常住アプリが作用して起きることがあるとかいう曖昧なことしか分かりませんでした。
 良く分からなかったので、いったん強制終了し、アイテム数がきわめて多いメールボックスについては、サブボックス単位でマクロを適用していくことにしました。結果、そこそこ手間がかかりました…が、求めていた「1通1ファイルのテキスト」が手に入ったので、よかったです。


 私はVBAを(ましてやOutlookで)使ったことがほとんどありませんが、上記のような超短いコードを写経しただけでも、なんか心理的なハードルがとても下がりました。「どういうオブジェクトがあって、どういうプロパティとメソッドがあるかを覚えていけばいいのか~」と、こう書いてしまうと当たり前のこと過ぎてナンセンスな感想なのですが、でもほんとにそんな感じでした。あと、VBAに限りませんが、一行一行自分で理解して、コメントを付けていくってのがけっこう勉強になるなと思いました。

 

*1:しかもExcelじゃなくてOutlookだし

*2:VBAのコード中ではFolderとなりますが。

*3:どこかのタブを開いてボタンが並んでいるところの端の方を右クリックし、リボンのユーザ設定で、新しいグループを作成してから、そのグループにマクロを挿入し、適当に名前を付ける。

学術研究費のクラウドファンディング 〜CrowdからTribeへ〜

 以下の記事をみてTwitterでシェアしようと思ったら要約が長くなりすぎたのでここにメモしておきます。単に概要を箇条書きしただけです。
 Crowdfunding and Tribefunding in Science – The Next Regeneration
 
 

  • 政府系の競争的な研究資金を取るのは大変で、研究者はその応募書類をつくるのにめちゃめちゃ労力を割いている。
  • 一方、そんだけ労力を割いても採用されないプロジェクトが多く、審査も完全ではないから、優れたアイディアが闇に消えてしまっている可能性もある。
  • そんななか、最近は学術研究の分野でも、クラウドファンディングによって研究費を集めるケースが増えてきている。
  • experiment.comなど、そのためのオンラインプラットフォームも出来ている。
  • 数十人・数十万円を集めれば成立するプロジェクトが多く、意外と成立している。
  • 意外と、大衆受けするテーマでなくてもプロジェクトが成立している。
  • しかし問題は、研究経費の一部を賄うレベルの案件ばかりで、研究者の人件費をカバーできるようなものはなかなか難しいから、長期的な研究プロジェクトのベースにはなりにくい。
  • そこで最近は、「ばらばらの個人」に資金提供してもらうcrowdfundingではなく、資金提供者にもプロジェクトのコミュニティメンバーとして深く長期的に関与してもらうtribefundingの考え方が台頭してきている。
  • イメージとしていうと、バラバラの個人との一時的な関係だと1万円ぐらい出してもらうのが限界だとしても、一緒にディスカッションしてプロジェクトを築き上げていくメンバーとしてなら10万円ぐらい出してくれるかもしれない。
  • また、こういう方式であれば、研究プロジェクト提案の査読についても、どっかの大学教授が適当に捌いていくのではなく、その研究に関心のある幅広い人達でディスカッションすることができ、内容をより良いものにすることもできる。
  • 草の根レベルで広い範囲から資金を募ることができるというクラウドファンディングの良さと、プロジェクトに関心がある人同士の長期的な共同関係をミックスすることで、学術研究におけるファンディングがもう少し進歩するかもしれない。

 
「クラウドファンディング」から「トライブファンディング」への進化については以下の解説記事を参考に。
Crowdfunding or Tribefunding? – Klugemotivation
 
 なるほどなぁと思いつつ、具体的なイメージはまだついてないです。
 ただまぁ、「ガチの共同研究者」としてでもなく、「投げ銭程度の寄付をする一般人」としてでもなく、その中間的なレベルで学術研究に関与するっていうあり方はあっても良いんだろうと思いますね。この世の中に、そういうレベルのモチベーションは確かにある程度ありそうで、モチベーションがあるならそれに見合ったおカネが動く可能性はある。意思決定のルールを明確にしておかないと活動が混乱するかもしれませんが。


 それはそれとして、河野太郎議員には、大学の事務ルールがどうのこうのみたいな細かい問題はさっさと片付けて、学術研究資金を「総額としてどんどん増やす」方向で太っ腹な活躍をして頂きたいと個人的には思ってます。
 

Pythonメモ: Tweepyのややこしいレスポンスデータの読み方 〜Twitter API活用の最初の難関〜

Twitterのbot作りは良い勉強になる

 以前のエントリで紹介したように、Tweepyというライブラリを使うと、かなり簡単にPythonでTwitterを自動操作出来るようになります。


www.statsbeginner.net


 つぶやいたり、フォロー/アンフォローしたり、RTしたりふぁぼったりといったアクションをTweepyを使って記述し、自動で実行できる環境に置けば、自前のbotが出来上がります。botといえば、ブログ記事の紹介ツイートを定期的に流したり、新しいフォロワーにフォロバするといった使い方がよくされていますが、自作のプログラムであれば例えば特定のキーワードを含むツイートをしているユーザを検索してそのプロフィールを取得してデータベース化するとか、ふぁぼやRTをよくしてくれる人を一定の基準を設けてリストに登録していくといった複合的な作業も、自動化できて手間が省けます。


 私は自分がメインで使ってる個人アカウントとは別に、仕事や趣味の情報を収集・発信するためのアカウントをいくつか運営していて*1、それらのアカウントではフォロバなどいくつかのアクションを自動化しています。初心者なので勉強しながら色々な機能を作ってみて、自動化できた操作が増えるたびに「これは便利!」と実感しています。暴走したら困る*2のでまだメインのアカウントにはほとんど組み込んでないけどw
 動作環境は単純で、Tweepyを使って書いたPythonのスクリプトを、AWS(EC2)で借りた一番安いスペックのLinuxサーバに置いて、cronでPythonインタープリタごと起動して動かしてます。このへん、一連の環境作りを後日エントリにまとめようと思います。


 今は、機械学習の練習台にと思って、スパム的なアカウントや、過激なネトウヨアカウントなどを識別して自動的にフォローを外すなどの機能を加えるため、学習用のデータを集めているところです。そのためのデータ収集も、ある程度自動化しています*3
 最近思うんですが、初心者がプログラミングの勉強を進める上で、「Twitterのbotづくり」はとても良い演習の題材な気がします。基本的なコーディングに慣れるし、私の場合はラッパーを介して単純化してしまっているものの「Web APIを使う」ことの入門にもなるし、「プログラムを自動で定期実行させる」ことの練習にもなります。私の場合、「AWSでLinuxサーバを借りてSSHでログインしてcronの設定をして・・・」という作業を初めてやってみるいい機会にもなりました。
 また、機械学習の練習にも良いのではと感じます。私もいま、特定の傾向を持つツイートのデータを集めてるんですが、単語で分割して頻度を数えてクラスタリングするみたいな単純な分析を試せるし、データを分析可能な形に成形するための処理を書く勉強にもなります。「データを取ってくる」→「加工する」→「解析する」→「レポートする」が一通り出来ないといけないので、Web APIを使った演習はためになると思いました。今後、WikipediaのAPIとかも使ってみたいと思っています。

Twitter APIを使う上での最初の難関

 さて、Tweepyを使えば、TwitterのREST APIを手軽に叩けるようになるのは事実なのですが、恐らく最初の難関となるのが、レスポンスデータが膨大すぎて意味分からんということです*4
 これはTwitterのAPIを(Tweepy等のラッパーを使わずに)生に近い形で叩いた場合に受け取るJSONを読む場合にもある程度言えることではありますが、後述する理由で、Tweepyの場合はさらにデータが膨大になっています。せっかくデータが得られても、中にどういう情報が入っているかがちんぷんかんぷんだと、やる気が失せます。
 「フォローする」「つぶやく」といったアクションだけを自動化するならレスポンスは特に気にしなくていいですが、自分のフォロワー/フレンド一覧を取得して何かやるとか、特定の内容のツイートを選んでRTするとか、他人のアカウントの特性(プロフの内容、フォロー/フレンドの傾向、最近のツイート等)を調べてフォローするかどうか決めるとかいう処理を行うには、どうしてもget系の機能で取得したレスポンスを読む必要が出てきます。


 ちなみに、たとえば私自身のツイート1件分のデータを要求した場合のレスポンスは、以下のようなデータです。なんかヤバいので画像にしました。


f:id:midnightseminar:20170212181117p:plain


 もはや、文字も小さすぎてよく分かりませんw
 このエントリの後ろのほうにテキストで掲載してますが、とりあえずここでは、大量の文字列が返ってきて吐き気がするイメージだけをつかんでいただければと思います。
 ツイート1件分でこんなのが返ってくると、必要な情報をどうやって取り出せばいいのか検討もつかず、いきなりやる気がなくなってしまう人も多いと思います。しかもこの例はまだマシな方で、場合によっては1つのツイートのデータが1000項目ぐらいの情報を含んでいる場合すらあります。


 しかしこのデータは、冷静に見ていけばそんなに複雑なわけでもなく、パターンが分かってしまえば欲しいデータを取り出すのに苦労はしなくなります。かなり多くのデータ項目が含まれてはいるのですが、だいたいよく使うものは限られてくるし、全体の構造がいったん頭に入ると、それがどこにあってどうやって取り出せるのかも簡単に分かります
 必要な情報のとり方がわかると、俄然やる気が出てきます。ツイートの位置情報はどこにどういう形式で入っているのかとか、何件くらいリツイートされているんだろうとか、そういうのが分かりだすと、「この情報を使ってこういう自動処理ができるのでは?」っていう想像力が働いて、色々プログラムを書いてみたくなってきます。


 そこで、本エントリでは、Tweepyを使っていて返される代表的なレスポンスデータの全体の構造と、よく使いそうなデータがどのように入っているのかをメモしておこうと思います。


 なお大前提ですが、TwitterのAPIでは「つぶやき」は「Status」と呼ばれ、あるアカウントがフォローしている相手のことは「Friend」と呼ばれます。フォローを外すアクションは「Destroy Friendship」という怖い名前で呼ばれます。ユーザ名(@がつくやつ)は「Screen Name」と呼ばれ、システム的に振られているID(数字の並びになっている)と区別されます。あとはだいたい、ふだん使っている機能のまんまかなと思います(followerとか)。
 また、以下の説明は、冒頭にリンクを貼った以前のエントリでやったように、「api」という変数名でTweepyのAPIハンドラオブジェクトを生成していることを前提とします。
 
 

レスポンスの種類

 まず、そもそも返されるデータにはどんな種類のものがあるのかですが、これはTweepyのreferenceを眺めるとわかります。


API Reference — tweepy 3.5.0 documentation

 
 色々なメソッドの使用法が書かれてますが(これも後日エントリにまとめようかと思います)、それぞれの一番下に、「Return type」って欄がありますよね。


 Return type: list of Status objects
 Return type: Status object
 Return type: User object
 Return type: list of DirectMessage objects


 みたいなやつです。
 各メソッドを使ったときに返り値として得られるデータは、いくつかの種類のTweepyオブジェクトの1つ、もしくはオブジェクトのリストです。


 このリファレンスを見ていると、「Status」オブジェクトと「User」オブジェクトがたくさん登場していますね。「List」オブジェクトとか「Frendship」オブジェクトとか「DirectMessage」オブジェクトもありますが、多くの機能で、返り値がStatusオブジェクトかUserオブジェクト、またはそれらのリストになっています。
 また、よく使うであろうものとしては、.followers_ids()メソッドや.friends_ids()メソッドで返ってくる、id(整数)のリストですね。あるアカウントを自分がすでにフォローしているかを判定するといった場合は、このidリストを使います。
 botを作って実行したいような事はたいてい、idリストかStatusオブジェクトかUserオブジェクトを使うのだぐらいに思っておいてもいいような気がします。


 StatusオブジェクトとかUserオブジェクトとか言ってますが、このStatusとかUserとかは要するにクラスになっています。たとえば、

>>> mytweet1 = api.user_timeline(count=1)[0]


 このように、自分のタイムラインを取得するメソッド「.user_timeline()」を使用すると、Statusクラスのオブジェクトのリストが返されます。上の例では、ユーザ名等を省略しているので「自分自身のタイムライン」が参照されており、その0番目要素、つまり「自分の最新のつぶやき」データを取得して、mytweet1という変数名に渡しています。このmytweet1という変数の中身はstatusクラスのインスタンスになっており、

>>> print(mytweet1.id)
830561754123956224


 のように、アトリビュートとして中身の情報を取り出すことができます(↑の例では.idでツイートのIDを表示)。
 要は、そのクラスのオブジェクトにどのようなアトリビュートが入っているのかを理解しておけば、レスポンスデータを使いこなして様々な処理を行うことができるわけですね。

レスポンスデータの構造

 Tweepyのレスポンスデータが、先ほど貼り付けた画像のようにパッと見めちゃめちゃややこしい理由の一つは、データがだいぶ冗長な構成になってるからです。同じ情報が何箇所にも入ってるんです。冗長化している原因は主に2つあります。
 1つは、Twitter APIが返すデータがそもそも、「ユーザのデータを取得するとそのユーザの最新のツイートのデータが付いてくる」「ツイートのデータを取得するとそのユーザのデータが付いてくる」ようになっていることですね。もともと入れ子になってるわけです。
 もう1つは、Tweepyは、Tweepyで作ったオブジェクトのアトリビュートとして直接取り出せるデータの他に、Twitter APIが返してくる生のJSONのデータも埋め込んでくれているからです。このおかげで、取り出せるデータがほぼまるごと、「素のアトリビュートの1項目」と「アトリビュートの1つとして埋め込まれたJSON内の1項目」で重複する形になっています。
 この1つ目と2つ目の要因が重なって、たとえばある1つのツイートのデータを取得すると、そのツイートの性質を表すさまざまなデータ項目と、それがJSONでまとまった項目が含まれるのに加えて、そのツイートの主であるユーザの性質を表すさまざまなデータ項目と、それがJSONにまとまった項目も得られるわけですね。んでJSONの中身も入れ子になっていると。
 私は今のところJSONのデータを使っていませんが、Tweepy以外の手段(たとえばurllib2)でAPIをコールする作業と統合するようなことを考えると、JSONで見るように揃えておいたほうが良いのかもしれません。


 主なTweepyオブジェクトのデータの構造を、途中のデータを省略した形で、改行とインデントを加えて整理すると以下のようになります。入れ子構造がつかめると、データを見るのが楽になります。
 なお以下はあくまで例で、同じ種類のオブジェクトでも、中身によって構成が違うことがあります。

Userオブジェクト

 Userオブジェクトは、ユーザのID、Screen Name、フォロワー数、地域など様々な情報を含んでいますが、大雑把には以下のように、なっています、jsonデータとstatsuデータが埋め込まれていること、statusデータにはそれ自身のjsonデータも埋め込まれているところがポイントかなと思います。
 他の種類のオブジェクトでもそうなのですが、Tweepyのデータは(hoge=hage, hogee=hagee)というように、丸カッコで括られて、項目名=値という書式で入っています。JSONが埋め込まれる時は、「_json={ }」という項目として埋め込まれ、{ }の中にJSONの書式で、「'hoge':hage, 'hogee':hagee」というようなデータが書き込まれます
 

User(
	【省略】
	_json={
		【省略】
		'status': {【省略】}
		【省略】
	}, 
	【省略】
	status=Status(
		【省略】
		_json={【省略】}
		【省略】
	), 
	【省略】
)

 
 Userオブジェクトの1階層目には、たとえばユーザのscreen nameが入っています。user1という変数名でオブジェクトが与えられたとすると、
 user1.screen_name
 というふうに記述すれば、screen_nameを取り出せます。
 JSONが埋め込まれて階層的になっている場合に、たとえばあえてJSON内の情報を取り出したいとすると(1階層目から直接同じ情報が取れますが)、
 user1._json['screen_name']
のように記述します。jsonから取り出す書式は、Pythonの辞書型と同じと覚えておけばいいですね。
 
 

Statusオブジェクト

 Statusオブジェクトは以下のようになっています。Status(つぶやき)なので、当然、つぶやきのIDやテキストなど様々な特性がデータ項目として埋め込まれていて、その並びの中に、「author」や「user」という項目名でuserオブジェクトが埋め込まれています。
 authorとuserは似たような情報が入ってて混乱しますが、userのほうは既に非推奨(depreciated)となっているので、authorのほうを使ったほうが良いようです*5
 それに加えてJSONも埋まっているので、なかなかややこしいデータになっています。
 

Status(
	【省略】
	author=User(
		【省略】
		_json={【省略】}
		【省略】
	), 
	【省略】
	user=User(
		【省略】
		_json={【省略】}
		【省略】
	), 
	【省略】
	_json={
		【省略】
		'user': {【省略】}
		【省略】
	}, 
	【省略】
)

 
 

RTありのStatusオブジェクト

 リツイートされたものは一気に複雑になります。要は、1階層目ではそのリツイート自体の情報(時刻とか)を表現しなければならず、その中にretweeted_statusという情報を埋め込んで、RTされた元のツイートのデータを入れているわけですね。そしてまたユーザのデータが埋め込まれたり、JSONも埋め込まれたりすることによって、大変複雑になっています。
 結果として階層が深くなっており、
 OBJECT.retweeted_status.author._json['screen_name']
 のような取り出し方があり得ますw
 

Status(
	【省略】
	author=User(
		【省略】
		_json={【省略】}
		【省略】
	), 
	【省略】
	user=User(
		【省略】
		_json={【省略】}
		【省略】
	), 
	【省略】
	retweeted_status=Status(
		【省略】
		author=User(
			【省略】
			_json={【省略】}
			【省略】
		), 
		【省略】
		user=User(
			【省略】
			_json={【省略】}
			【省略】
		), 
		【省略】
		_json={
			【省略】
			'user': {【省略】}
			【省略】
		}, 
		【省略】
	), 
	【省略】
	_json={
		【省略】
		'retweeted_status': {
			【省略】
			'user': {【省略】}
			【省略】
		}
		【省略】
	}, 
	【省略】
)

 
 

Friendshipオブジェクト

 簡単なやつもみてみましょう。
 api.show_friendship(source, target)というメソッドを用いると、特定の2ユーザ(sourceとtarget)間の関係を表示させることができます。もちろんどちらかが自分自身でも構いません。フォローしてるかどうかとか、ブロックしてるかどうかとかがわかります。
 このメソッドの返り値は簡単な構造になっていて、

(
Friendship(【省略】), 
Friendship(【省略】)
)


というものです。source側から見た関係と、target側から見た関係が、それぞれFriendshipオブジェクトになっていて、そのタプルが返されます。
 
 

SearchResultオブジェクト

 api.search()というメソッドがあって、これはキーワードで検索して該当するツイートが得られるというやつなのですが、この返り値はstatusのリストになっています。
 つまり実体としては、
 [Status(), Status(), Status()]
 というようなデータが得られるので、たとえばインデックスで[0]を指定して1個目を取り出したとすると、1件目でヒットしたツイートの内容が、Statusオブジェクトとして取得出来ます。
 
 

レスポンスの中身

 さて、では実際にレスポンスの中身を見ていきたいと思いますが、正直、項目が多すぎて、いちいち説明してるととんでもない分量になりますし、私も何なのか理解してない項目がたくさんあります。
 なので、以下では、レスポンスの取得例を、改行とインデントで整理したテキストを貼り付けて、いくつかの項目についてその意味を述べておくに留めます(すいません)。階層関係を掴みやすくするために、たとえばjsonが埋まっている場合は「##### ここからstatus/_json #####」といったテキストを挟んであります。


 こうやって改行とインデントによって、項目を分離しかつ階層関係が把握されるだけでも、中身は随分と読みやすくなります。私はすべて「肉眼でパース」(笑)して改行とインデントを手作業で入れていったので、全部読んだことになりますが、数百項目を順番に読んで行ってもそんなに疲れませんでした。*6
 各項目は、項目名を見れば何のことなのかだいたい分かると思いますし、Twitter APIが返すJSONの中身に対応しているので、API関連の情報をググれば意味はすぐに突き止められます。Twitter本家のAPIリファレンスを日本語で解説したサイトをみるとかもオススメです。


 以下、膨大な量のテキストを引用形式で貼り付けていきますが、スマホだと右端で折り返されてわけのわからない表示になる可能性があります。また、パソコンでみるにしても、テキストエディタかなんかにコピペして縮小したり拡大したりしながら見たほうがいいかもしれません。

Userオブジェクト

 idはシステム的に振られている数字の並び。
 screen_nameは「@〜」のところ。
 nameってのは表示名(頻繁に変えても大丈夫なやつ)です。
 id_strってのは、idがシングルクォーテーションで囲んであって、文字列型として扱えるやつです。
 statuses_countはツイート数。followers_countはフォロワー数。friends_countはフォロー数。
 protected(True or False)は鍵垢かどうか。色々な処理を書いていると、「相手が鍵垢だとエラーになる処理」とかがあって、エラーを回避するために事前に鍵垢かどうかをチェックする必要が出てきます。
 Followingは自分がフォローしてるかどうか。
 verifiedは認証済みユーザかどうか。
 langは言語、time_zoneはそのまんま。日本人ユーザのデータばかり集めたいときに使ったりとか。
 locationは自分で入力してある居場所で、ツイート(status)に自動でついてくるplaceとは別です。


 ・・・といったところですかね。これらのデータに、
 OBJECT.id
 OBJECT.screen_name
 みたいな書式でアクセスしてください。
 その他詳しくは、Syncerの解説をみるのが良いです。

User(
	time_zone='Tokyo', 
	profile_background_image_url='http://abs.twimg.com/images/themes/theme1/bg.png', 
	listed_count=38, 
	is_translation_enabled=True, 
	profile_background_tile=False, 
	profile_location=None, 
	name='bata', 
	profile_sidebar_border_color='C0DEED', 
	screen_name='statsbeginner', 
	url='https://t.co/6HCF2FYowE', 
	follow_request_sent=False, 
	
	##### ここからuser/_json #####
	_json={
		'time_zone': 'Tokyo', 
		'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 
		'listed_count': 38, 
		'is_translation_enabled': True, 
		'profile_background_tile': False, 
		'profile_location': None, 
		'name': 'bata', 
		'profile_sidebar_border_color': 'C0DEED', 
		'screen_name': 'statsbeginner', 
		'url': 'https://t.co/6HCF2FYowE', 
		'follow_request_sent': False, 
		'id_str': '257791390', 
		'default_profile_image': False, 
		'profile_use_background_image': True, 
	
		##### ここからuser/_json/status #####
		'status': {
			'favorite_count': 1, 
			'possibly_sensitive': False, 
			'coordinates': None, 
			'source': '<a href="http://www.hatena.ne.jp/guide/twitter" rel="nofollow">Hatena</a>', 
			'text': '去年、国立がん研究センターとJTの論争が話題になった頃にあわせて紹介した砂糖の話が、ウェルク事件に絡めて取り上げられていたw / “60年後にばれた米「砂糖業界」の大陰謀(上)「低脂肪ダイエット」のウソ--大西睦子\xa0|\xa0新潮社フ…” https://t.co/BQkMW7m6de', 
			'contributors': None, 
			'created_at': 'Mon Jan 23 05:15:50 +0000 2017', 
			'truncated': False, 
			'retweeted': False, 
			'in_reply_to_screen_name': None, 
			'is_quote_status': False, 
			'in_reply_to_user_id': None, 
			'id_str': '823398817370247168', 
			'retweet_count': 0, 
			'in_reply_to_status_id_str': None, 
			'id': 823398817370247168, 
			'in_reply_to_status_id': None, 
			'entities': {
				'urls': [{
					'display_url': 'htn.to/3i7io9', 
					'expanded_url': 'http://htn.to/3i7io9', 
					'url': 'https://t.co/BQkMW7m6de', 
					'indices': [117, 140]
				}], 
				'user_mentions': [], 
				'symbols': [], 
				'hashtags': []
			}, 
			'favorited': False, 
			'in_reply_to_user_id_str': None, 
			'lang': 'ja', 
			'place': None, 
			'geo': None
		}, 
		##### ここまでuser/_json/status #####
		
		'entities': {
			'description': {'urls': []}, 
			'url': {
				'urls': [{
					'display_url': 'statsbeginner.hatenablog.com', 
					'expanded_url': 'http://statsbeginner.hatenablog.com/', 
					'url': 'https://t.co/6HCF2FYowE', 
					'indices': [0, 23]
				}]
			}
		}, 
		'statuses_count': 13014, 
		'contributors_enabled': False, 
		'profile_link_color': '1DA1F2', 
		'notifications': False, 
		'id': 257791390, 
		'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 
		'profile_sidebar_fill_color': 'DDEEF6', 
		'utc_offset': 32400, 
		'description': '統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
		'profile_text_color': '333333', 
		'followers_count': 1873, 
		'default_profile': True, 
		'profile_image_url': 'http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		'favourites_count': 1088, 
		'location': 'つくば市', 
		'needs_phone_verification': False, 
		'created_at': 'Sat Feb 26 04:59:47 +0000 2011', 
		'profile_image_url_https': 'https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		'protected': False, 
		'friends_count': 818, 
		'following': False, 
		'suspended': False, 
		'is_translator': False, 
		'profile_background_color': 'C0DEED', 
		'translator_type': 'none', 
		'geo_enabled': True, 
		'verified': False, 
		'has_extended_profile': False, 
		'lang': 'ja'
	}, 
	##### ここまでuser/_json #####
	
	default_profile_image=False, 
	profile_use_background_image=True, 
	
	##### ここからuser/stastus #####
	status=Status(
		favorite_count=1, 
		possibly_sensitive=False, 
		coordinates=None, 
		source='Hatena', 
		text='去年、国立がん研究センターとJTの論争が話題になった頃にあわせて紹介した砂糖の話が、ウェルク事件に絡めて取り上げられていたw / “60年後にばれた米「砂糖業界」の大陰謀(上)「低脂肪ダイエット」のウソ--大西睦子\xa0|\xa0新潮社フ…” https://t.co/BQkMW7m6de', 
		contributors=None, 
		created_at=datetime.datetime(2017, 1, 23, 5, 15, 50), 
		in_reply_to_user_id_str=None, 
		source_url='http://www.hatena.ne.jp/guide/twitter', 
		truncated=False, 
		_api=<tweepy.api.API object at 0x117919198>, 
		retweeted=False, 
		in_reply_to_screen_name=None, 
		is_quote_status=False, 
		in_reply_to_user_id=None, 
		id_str='823398817370247168', 
		retweet_count=0, 
		in_reply_to_status_id_str=None, 
		id=823398817370247168, 
		in_reply_to_status_id=None, 
		entities={
			'urls': [{
				'display_url': 'htn.to/3i7io9', 
				'expanded_url': 'http://htn.to/3i7io9', 
				'url': 'https://t.co/BQkMW7m6de', 
				'indices': [117, 140]
			}], 
			'user_mentions': [], 
			'symbols': [], 
			'hashtags': []
		}, 
		favorited=False, 
		
		##### ここからuser/status/_json #####
		_json={
			'favorite_count': 1, 
			'possibly_sensitive': False, 
			'coordinates': None, 
			'source': '<a href="http://www.hatena.ne.jp/guide/twitter" rel="nofollow">Hatena</a>', 
			'text': '去年、国立がん研究センターとJTの論争が話題になった頃にあわせて紹介した砂糖の話が、ウェルク事件に絡めて取り上げられていたw / “60年後にばれた米「砂糖業界」の大陰謀(上)「低脂肪ダイエット」のウソ--大西睦子\xa0|\xa0新潮社フ…” https://t.co/BQkMW7m6de', 
			'contributors': None, 
			'created_at': 'Mon Jan 23 05:15:50 +0000 2017', 
			'truncated': False, 
			'retweeted': False, 
			'in_reply_to_screen_name': None, 
			'is_quote_status': False, 
			'in_reply_to_user_id': None, 
			'id_str': '823398817370247168', 
			'retweet_count': 0, 
			'in_reply_to_status_id_str': None, 
			'id': 823398817370247168, 
			'in_reply_to_status_id': None, 
			'entities': {
				'urls': [{
					'display_url': 'htn.to/3i7io9', 
					'expanded_url': 'http://htn.to/3i7io9', 
					'url': 'https://t.co/BQkMW7m6de', 
					'indices': [117, 140]
				}], 
				'user_mentions': [], 
				'symbols': [], 
				'hashtags': []
			}, 
			'favorited': False, 
			'in_reply_to_user_id_str': None, 
			'lang': 'ja', 
			'place': None, 
			'geo': None
		}, 
		##### ここまでuser/status/_json #####
		
		lang='ja', 
		place=None, 
		geo=None
	), 
	##### ここまでuser/stastus #####
	
	entities={
		'description': {'urls': []}, 
		'url': {
			'urls': [{
				'display_url': 'statsbeginner.hatenablog.com', 
				'expanded_url': 'http://statsbeginner.hatenablog.com/', 
				'url': 'https://t.co/6HCF2FYowE', 
				'indices': [0, 23]
			}]
		}
	}, 	
	statuses_count=13014, 
	contributors_enabled=False, 
	profile_link_color='1DA1F2', 
	notifications=False, 
	id=257791390, 
	profile_background_image_url_https='https://abs.twimg.com/images/themes/theme1/bg.png', 
	profile_sidebar_fill_color='DDEEF6', 
	utc_offset=32400, 
	description='統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
	profile_text_color='333333', 
	suspended=False, 
	followers_count=1873, 
	default_profile=True, 
	profile_image_url='http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
	favourites_count=1088, 
	_api=<tweepy.api.API object at 0x117919198>, 
	location='つくば市', 
	needs_phone_verification=False, 
	created_at=datetime.datetime(2011, 2, 26, 4, 59, 47), 
	profile_image_url_https='https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
	protected=False, 
	friends_count=818, 
	following=False, 
	id_str='257791390', 
	is_translator=False, 
	profile_background_color='C0DEED', 
	translator_type='none', 
	geo_enabled=True, 
	verified=False, 
	has_extended_profile=False, 
	lang='ja'
)

 
 

Statusオブジェクト

 idはツイートのID。ツイートを個別に指定して何かの処理をやる時に必ず使います。
 textがツイートの本文。
 created_atはツイートの日時が入っていて、Pythonのdatetime型のデータが得られます。
 他のツイートへのリプライだった場合はin_reply_to_screen_nameとかに値が入ります。
 retweet_countはRT数。favorite_countはふぁぼ数。
 retweetedとfavorited(True or False)は自分がRT・ふぁぼしたかどうかです。
 placeは位置情報(緯度経度じゃなくて、IPアドレスかなんかをベースに自動で振られるやつ)。上述したとおり、Userオブジェクトに入っているプロフのlocationとは別です。
 sourceで、パソコンからなのかスマホアプリからなのか等が判別できます。
 possibly_sensitiveは何のことかわからないのですが、何かのフィルタリングに使われるやつかな?
 下の例では出てきませんが、スマホ等からのつぶやきで緯度経度情報がある場合は、coordinatesって項目の中に数値が入ります。


 上述したように、authorとuserに似たような情報が入ってますが、userはすでに非推奨となっているので、authorの情報を使ったほうがいいようです。
 その他詳しくはSyncerの解説で確認するのがいいかと。

Status(
	
	##### ここからstatus/author #####
	author=User(
		time_zone='Tokyo', 
		profile_background_image_url='http://abs.twimg.com/images/themes/theme1/bg.png', 
		listed_count=38, 
		is_translation_enabled=True, 
		profile_background_tile=False, 
		name='bata', 
		profile_sidebar_border_color='C0DEED', 
		screen_name='statsbeginner', 
		url='https://t.co/6HCF2FYowE', 
		follow_request_sent=False, 
	
		##### ここからstatus/author/_json #####
		_json={
			'time_zone': 'Tokyo', 
			'description': '統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
			'following': False, 
			'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 
			'listed_count': 38, 
			'is_translation_enabled': True, 
			'profile_background_tile': False, 
			'profile_text_color': '333333', 
			'profile_image_url': 'http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'favourites_count': 1088, 
			'notifications': False, 
			'location': 'つくば市', 
			'profile_use_background_image': True, 
			'name': 'bata', 
			'created_at': 'Sat Feb 26 04:59:47 +0000 2011', 
			'profile_image_url_https': 'https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'screen_name': 'statsbeginner', 
			'protected': False, 
			'profile_background_color': 'C0DEED', 
			'url': 'https://t.co/6HCF2FYowE', 
			'follow_request_sent': False, 
			'friends_count': 800, 
			'default_profile': True, 
			'default_profile_image': False, 
			'followers_count': 1873, 
			'translator_type': 'none', 
			'id_str': '257791390', 
			'statuses_count': 13014, 
			'contributors_enabled': False, 
			'profile_link_color': '1DA1F2', 
			'is_translator': False, 
			'id': 257791390, 
			'entities': {
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'statsbeginner.hatenablog.com', 'expanded_url': 'http://statsbeginner.hatenablog.com/', 'url': 'https://t.co/6HCF2FYowE', 'indices': [0, 23]
					}]
				}
			}, 
			'geo_enabled': True, 
			'profile_sidebar_fill_color': 'DDEEF6', 
			'has_extended_profile': False, 
			'verified': False, 
			'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 
			'lang': 'ja', 
			'utc_offset': 32400, 
			'profile_sidebar_border_color': 'C0DEED'
		}, 
		##### ここまでstatus/author/_json #####
	
		default_profile_image=False, 
		profile_use_background_image=True, 
		entities={
			'description': {'urls': []}, 
			'url': {
				'urls': [{
					'display_url': 'statsbeginner.hatenablog.com', 
					'expanded_url': 'http://statsbeginner.hatenablog.com/', 
					'url': 'https://t.co/6HCF2FYowE', 
					'indices': [0, 23]
				}]
			}
		}, 
		statuses_count=13014, 
		contributors_enabled=False, 
		profile_link_color='1DA1F2', 
		notifications=False, 
		id=257791390, 
		profile_background_image_url_https='https://abs.twimg.com/images/themes/theme1/bg.png', 
		profile_sidebar_fill_color='DDEEF6', 
		utc_offset=32400, 
		description='統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
		profile_text_color='333333', 
		followers_count=1873, 
		default_profile=True, 
		profile_image_url='http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		favourites_count=1088, 
		_api=<tweepy.api.API object at 0x117919198>, 
		location='つくば市', 
		created_at=datetime.datetime(2011, 2, 26, 4, 59, 47), 
		profile_image_url_https='https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		protected=False, 
		friends_count=800, 
		following=False, 
		id_str='257791390', 
		is_translator=False, 
		profile_background_color='C0DEED', 
		translator_type='none', 
		geo_enabled=True, 
		verified=False, 
		has_extended_profile=False, 
		lang='ja'
	), 
	##### ここまでstatus/autor #####
	
	possibly_sensitive=False, 
	coordinates=None, 
	source='Twitter for iPhone', 
	favorite_count=0, 
	text='ボーカル2人って知らなかった/クリスタルキング 大都会 https://t.co/fuCvYig0eu', 
	
	##### ここからstatus/user #####
	user=User(
		time_zone='Tokyo', 
		profile_background_image_url='http://abs.twimg.com/images/themes/theme1/bg.png', 
		listed_count=38, 
		is_translation_enabled=True, 
		profile_background_tile=False, 
		name='bata', 
		profile_sidebar_border_color='C0DEED', 
		screen_name='statsbeginner', 
		url='https://t.co/6HCF2FYowE', 
		follow_request_sent=False, 
		
		##### ここからstatus/user/_json #####
		_json={
			'time_zone': 'Tokyo', 
			'description': '統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
			'following': False, 
			'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 
			'listed_count': 38, 
			'is_translation_enabled': True, 
			'profile_background_tile': False, 
			'profile_text_color': '333333', 
			'profile_image_url': 'http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'favourites_count': 1088, 
			'notifications': False, 
			'location': 'つくば市', 
			'profile_use_background_image': True, 
			'name': 'bata', 
			'created_at': 'Sat Feb 26 04:59:47 +0000 2011', 
			'profile_image_url_https': 'https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'screen_name': 'statsbeginner', 
			'protected': False, 
			'profile_background_color': 'C0DEED', 
			'url': 'https://t.co/6HCF2FYowE', 
			'follow_request_sent': False, 
			'friends_count': 800, 
			'default_profile': True, 
			'default_profile_image': False, 
			'followers_count': 1873, 
			'translator_type': 'none', 
			'id_str': '257791390', 
			'statuses_count': 13014, 
			'contributors_enabled': False, 
			'profile_link_color': '1DA1F2', 
			'is_translator': False, 
			'id': 257791390, 
			'entities': {
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'statsbeginner.hatenablog.com', 
						'expanded_url': 'http://statsbeginner.hatenablog.com/', 
						'url': 'https://t.co/6HCF2FYowE', 
						'indices': [0, 23]
					}]
				}
			}, 
			'geo_enabled': True, 
			'profile_sidebar_fill_color': 'DDEEF6', 
			'has_extended_profile': False, 
			'verified': False, 
			'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 
			'lang': 'ja', 
			'utc_offset': 32400, 
			'profile_sidebar_border_color': 'C0DEED'
		},
		##### ここまでstatus/user/_json #####
		
		default_profile_image=False, 
		profile_use_background_image=True, 
		entities={
			'description': {'urls': []}, 
			'url': {
				'urls': [{
					'display_url': 'statsbeginner.hatenablog.com', 
					'expanded_url': 'http://statsbeginner.hatenablog.com/', 
					'url': 'https://t.co/6HCF2FYowE', 
					'indices': [0, 23]
				}]
			}
		}, 
		statuses_count=13014, 
		contributors_enabled=False, 
		profile_link_color='1DA1F2', 
		notifications=False, 
		id=257791390, 
		profile_background_image_url_https='https://abs.twimg.com/images/themes/theme1/bg.png', 
		profile_sidebar_fill_color='DDEEF6', 
		utc_offset=32400, 
		description='統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
		profile_text_color='333333', 
		followers_count=1873, 
		default_profile=True, 
		profile_image_url='http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		favourites_count=1088, 
		_api=<tweepy.api.API object at 0x117919198>, 
		location='つくば市', 
		created_at=datetime.datetime(2011, 2, 26, 4, 59, 47), 
		profile_image_url_https='https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		protected=False, 
		friends_count=800, 
		following=False, 
		id_str='257791390', 
		is_translator=False, 
		profile_background_color='C0DEED', 
		translator_type='none', 
		geo_enabled=True, 
		verified=False, 
		has_extended_profile=False, 
		lang='ja'
	), 
	##### ここまでstatus/user #####
	
	contributors=None, 
	created_at=datetime.datetime(2017, 1, 22, 6, 5, 33), 
	in_reply_to_user_id_str=None, 
	source_url='http://twitter.com/download/iphone', 
	id=823048940182376452, 
	_api=<tweepy.api.API object at 0x117919198>, 
	retweeted=False, 
	in_reply_to_screen_name=None, 
	is_quote_status=False, 
	in_reply_to_user_id=None, 
	entities={
		'urls': [{
			'display_url': 'youtube.com/watch?v=ADgZso…', 
			'expanded_url': 'https://www.youtube.com/watch?v=ADgZsoSzDp0&feature=share', 
			'url': 'https://t.co/fuCvYig0eu', 
			'indices': [28, 51]
		}], 
		'user_mentions': [], 
		'symbols': [], 
		'hashtags': []
	}, 
	retweet_count=0, 
	possibly_sensitive_appealable=False, 
	in_reply_to_status_id_str=None, 
	truncated=False, 
	in_reply_to_status_id=None, 
	id_str='823048940182376452', 
	favorited=False, 
	
	##### ここから_json #####
	_json={
		'favorite_count': 0, 
		'possibly_sensitive': False, 
		'coordinates': None, 
		'source': '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>', 
		'text': 'ボーカル2人って知らなかった/クリスタルキング 大都会 https://t.co/fuCvYig0eu', 
	
		##### ここから_json/user #####
		'user': {
			'time_zone': 'Tokyo', 
			'description': '統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
			'following': False, 
			'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 
			'listed_count': 38, 
			'is_translation_enabled': True, 
			'profile_background_tile': False, 
			'profile_text_color': '333333', 
			'profile_image_url': 'http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'favourites_count': 1088, 
			'notifications': False, 
			'location': 'つくば市', 
			'profile_use_background_image': True, 
			'name': 'bata', 
			'created_at': 'Sat Feb 26 04:59:47 +0000 2011', 
			'profile_image_url_https': 'https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'screen_name': 'statsbeginner', 
			'protected': False, 
			'profile_background_color': 'C0DEED', 
			'url': 'https://t.co/6HCF2FYowE', 
			'follow_request_sent': False, 
			'friends_count': 800, 
			'default_profile': True, 
			'default_profile_image': False, 
			'followers_count': 1873, 
			'translator_type': 'none', 
			'id_str': '257791390', 
			'statuses_count': 13014, 
			'contributors_enabled': False, 
			'profile_link_color': '1DA1F2', 
			'is_translator': False, 
			'id': 257791390, 
			'entities': {
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'statsbeginner.hatenablog.com', 
						'expanded_url': 'http://statsbeginner.hatenablog.com/', 
						'url': 'https://t.co/6HCF2FYowE', 
						'indices': [0, 23]
					}]
				}
			}, 
			'geo_enabled': True, 
			'profile_sidebar_fill_color': 'DDEEF6', 
			'has_extended_profile': False, 
			'verified': False, 
			'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 
			'lang': 'ja', 
			'utc_offset': 32400, 
			'profile_sidebar_border_color': 'C0DEED'
		}, 
		##### ここまでstatus/_json/user #####
		
		'contributors': None, 
		'created_at': 'Sun Jan 22 06:05:33 +0000 2017', 
		'truncated': False, 
		'retweeted': False, 
		'in_reply_to_screen_name': None, 
		'is_quote_status': False, 
		'in_reply_to_user_id': None, 
		'id_str': '823048940182376452', 
		'retweet_count': 0, 
		'possibly_sensitive_appealable': False, 
		'in_reply_to_status_id_str': None, 
		'id': 823048940182376452, 
		'in_reply_to_status_id': None, 
		'entities': {
			'urls': [{
				'display_url': 'youtube.com/watch?v=ADgZso…', 
				'expanded_url': 'https://www.youtube.com/watch?v=ADgZsoSzDp0&feature=share', 
				'url': 'https://t.co/fuCvYig0eu', 
				'indices': [28, 51]
			}], 
			'user_mentions': [], 
			'symbols': [], 
			'hashtags': []
		}, 
		'favorited': False, 
		'in_reply_to_user_id_str': None, 
		'lang': 'ja', 
		'place': None, 
		'geo': None
	}, 
	##### ここまでstatus/_json #####
	
	lang='ja', 
	place=None, 
	geo=None
)

 
 

RetweetありのStatusオブジェクト

 以下はRTありの場合です。1000項目以上あってヤヴァいですが、UserとStatusを知っていればだいたい分かります。
 1階層目は、「RTである私のツイート」としての情報が入っていて、retweeted_statusの中に、RTされた元のツイートの情報が入っています。たとえば、Status直下の、私自身のツイート情報としてはsourceが'Twitter for Mac'になっていますが、retweeted_status中のsourceは'Twitter for iPhone'になっています。ピコ太郎さんがiPhoneのTwitterクライアントから投稿したツイートを、私がMacのTwitterクライアントからRTしたということです。


 下の例ではたまたま、extended_entitiesが入っているので、詳しいことを知りたければSyncerの解説を。「エンティティはテキストに含まれているURLアドレスやハッシュタグにリンクを付けてリッチテキスト化するための情報です。拡張エンティティはテキストに画像や動画を加えるための情報」です。
 この、entitiesやextended_entitiesは、階層が深くなる代表的な項目ですね。私は今のところ情報として使ったことがありません。

Status(

	##### ここからstatus/author #####
	author=User(
		time_zone='Tokyo', 
		profile_background_image_url='http://abs.twimg.com/images/themes/theme1/bg.png', 
		listed_count=38, 
		is_translation_enabled=True, 
		profile_background_tile=False, 
		name='bata', 
		profile_sidebar_border_color='C0DEED', 
		screen_name='statsbeginner', 
		url='https://t.co/6HCF2FYowE', 
		follow_request_sent=False, 
	
		##### ここからstatus/author/_json #####
		_json={
			'time_zone': 'Tokyo', 
			'description': '統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
			'following': False, 
			'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 
			'listed_count': 38, 
			'is_translation_enabled': True, 
			'profile_background_tile': False, 
			'profile_text_color': '333333', 
			'profile_image_url': 'http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'favourites_count': 1088, 
			'notifications': False, 
			'location': 'つくば市', 
			'profile_use_background_image': True, 
			'name': 'bata', 
			'created_at': 'Sat Feb 26 04:59:47 +0000 2011', 
			'profile_image_url_https': 'https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'screen_name': 'statsbeginner', 
			'protected': False, 
			'profile_background_color': 'C0DEED', 
			'url': 'https://t.co/6HCF2FYowE', 
			'follow_request_sent': False, 
			'friends_count': 775, 
			'default_profile': True, 
			'default_profile_image': False, 
			'followers_count': 1873, 
			'translator_type': 'none', 
			'id_str': '257791390', 
			'statuses_count': 13015, 
			'contributors_enabled': False, 
			'profile_link_color': '1DA1F2', 
			'is_translator': False, 
			'id': 257791390, 
			'entities': {
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'statsbeginner.hatenablog.com', 
						'expanded_url': 'http://statsbeginner.hatenablog.com/', 
						'url': 'https://t.co/6HCF2FYowE', 
						'indices': [0, 23]
					}]
				}
			}, 
			'geo_enabled': True, 
			'profile_sidebar_fill_color': 'DDEEF6', 
			'has_extended_profile': False, 
			'verified': False, 
			'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 
			'lang': 'ja', 
			'utc_offset': 32400, 
			'profile_sidebar_border_color': 'C0DEED'
		}, 
		##### ここまでstatus/author/_json #####
	
		default_profile_image=False, 
		profile_use_background_image=True, 
		entities={
			'description': {'urls': []}, 
			'url': {
				'urls': [{
					'display_url': 'statsbeginner.hatenablog.com', 
					'expanded_url': 'http://statsbeginner.hatenablog.com/', 
					'url': 'https://t.co/6HCF2FYowE', 
					'indices': [0, 23]
				}]
			}
		}, 
		statuses_count=13015, 
		contributors_enabled=False, 
		profile_link_color='1DA1F2', 
		notifications=False, 
		id=257791390, 
		profile_background_image_url_https='https://abs.twimg.com/images/themes/theme1	/bg.png', 
		profile_sidebar_fill_color='DDEEF6', 
		utc_offset=32400, 
		description='統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
		profile_text_color='333333', 
		followers_count=1873, 
		default_profile=True, 
		profile_image_url='http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		favourites_count=1088, 
		_api=<tweepy.api.API object at 0x117919198>, 
		location='つくば市', 
		created_at=datetime.datetime(2011, 2, 26, 4, 59, 47), 
		profile_image_url_https='https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		protected=False, 
		friends_count=775, 
		following=False, 
		id_str='257791390', 
		is_translator=False, 
		profile_background_color='C0DEED', 
		translator_type='none', 
		geo_enabled=True, 
		verified=False, 
		has_extended_profile=False, 
		lang='ja'
	), 
	##### ここまでstatus/author #####
	
	possibly_sensitive=False, 
	
	##### ここからstatus/extended_entities #####
	extended_entities={
		'media': [
			{
				'type': 'photo', 
				'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'source_user_id': 747329673659482113, 
				'source_user_id_str': '747329673659482113', 
				'display_url': 'pic.twitter.com/uP5PYzWhHL', 
				'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'sizes': {
					'large': {
						'resize': 'fit', 
						'h': 1536, 
						'w': 2048
					}, 
					'small': {
						'resize': 'fit', 
						'h': 510, 
						'w': 680
					}, 
					'medium': {
						'resize': 'fit', 
						'h': 900, 
						'w': 1200
					}, 
					'thumb': {
						'resize': 'crop', 
						'h': 150, 
						'w': 150
					}
				}, 
				'indices': [36, 59], 
				'id_str': '823362891273281537', 
				'source_status_id_str': '823362903805804546', 
				'source_status_id': 823362903805804546, 
				'expanded_url': 'https://twitter.com/pikotaro_ppap/status	/823362903805804546/photo/1',
				'id': 823362891273281537, 
				'url': 'https://t.co/uP5PYzWhHL'
			}
		]
	}, 
	##### ここまでstatus/extenced_entities #####
	
	coordinates=None, 
	source='Twitter for Mac', 
	favorite_count=0, 
	text='RT @pikotaro_ppap: PONで華原朋美様とお写真ピコ! https://t.co/uP5PYzWhHL', 
	
	##### ここからstatus/user #####
	user=User(time_zone='Tokyo', 
		profile_background_image_url='http://abs.twimg.com/images/themes/theme1/bg.png', 
		listed_count=38, 
		is_translation_enabled=True, 
		profile_background_tile=False, 
		name='bata', 
		profile_sidebar_border_color='C0DEED', 
		screen_name='statsbeginner', 
		url='https://t.co/6HCF2FYowE', 
		follow_request_sent=False, 
	
		##### ここからstatus/user/_json #####
		_json={
			'time_zone': 'Tokyo', 
			'description': '統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
			'following': False, 
			'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1	/bg.png', 
			'listed_count': 38, 
			'is_translation_enabled': True, 
			'profile_background_tile': False, 
			'profile_text_color': '333333', 
			'profile_image_url': 'http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'favourites_count': 1088, 
			'notifications': False, 
			'location': 'つくば市', 
			'profile_use_background_image': True, 
			'name': 'bata', 
			'created_at': 'Sat Feb 26 04:59:47 +0000 2011', 
			'profile_image_url_https': 'https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'screen_name': 'statsbeginner', 
			'protected': False, 
			'profile_background_color': 'C0DEED', 
			'url': 'https://t.co/6HCF2FYowE', 
			'follow_request_sent': False, 
			'friends_count': 775, 
			'default_profile': True, 
			'default_profile_image': False, 
			'followers_count': 1873, 
			'translator_type': 'none', 
			'id_str': '257791390', 
			'statuses_count': 13015, 
			'contributors_enabled': False, 
			'profile_link_color': '1DA1F2', 
			'is_translator': False, 
			'id': 257791390, 
			'entities': {
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'statsbeginner.hatenablog.com', 
						'expanded_url': 'http://statsbeginner.hatenablog.com/', 
						'url': 'https://t.co/6HCF2FYowE', 
						'indices': [0, 23]
					}]
				}
			}, 
			'geo_enabled': True, 
			'profile_sidebar_fill_color': 'DDEEF6', 
			'has_extended_profile': False, 
			'verified': False, 
			'profile_background_image_url_https': 'https://abs.twimg.com/images/themes	/theme1/bg.png', 
			'lang': 'ja', 
			'utc_offset': 32400, 
			'profile_sidebar_border_color': 'C0DEED'
		}, 
		##### ここまでstatus/user/_json #####
	
		default_profile_image=False, 
		profile_use_background_image=True, 
		entities={
			'description': {'urls': []}, 
			'url': {
				'urls': [{
					'display_url': 'statsbeginner.hatenablog.com', 
					'expanded_url': 'http://statsbeginner.hatenablog.com/', 
					'url': 'https://t.co/6HCF2FYowE', 
					'indices': [0, 23]
				}]
			}
		}, 
		statuses_count=13015, 
		contributors_enabled=False, 
		profile_link_color='1DA1F2', 
		notifications=False, 
		id=257791390, 
		profile_background_image_url_https='https://abs.twimg.com/images/themes/theme1/bg.png', 
		profile_sidebar_fill_color='DDEEF6', 
		utc_offset=32400, 
		description='統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
		profile_text_color='333333', 
		followers_count=1873, 
		default_profile=True, 
		profile_image_url='http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		favourites_count=1088, 
		_api=<tweepy.api.API object at 0x117919198>, 
		location='つくば市', 
		created_at=datetime.datetime(2011, 2, 26, 4, 59, 47), 
		profile_image_url_https='https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
		protected=False, 
		friends_count=775, 
		following=False, 
		id_str='257791390', 
		is_translator=False, 
		profile_background_color='C0DEED', 
		translator_type='none', 
		geo_enabled=True, 
		verified=False, 
		has_extended_profile=False, 
		lang='ja'
	), 
	##### ここまでstatus/user #####
	
	contributors=None, 
	created_at=datetime.datetime(2017, 1, 23, 18, 12, 9), 
	in_reply_to_user_id_str=None, 
	source_url='http://itunes.apple.com/us/app/twitter/id409789998?mt=12', 
	id=823594183499780096, 
	_api=<tweepy.api.API object at 0x117919198>, 
	retweeted=True, 
	in_reply_to_screen_name=None, 
	is_quote_status=False, 
	in_reply_to_user_id=None, 
	
	##### ここからstatus/entities #####
	entities={
		'urls': [], 
		'user_mentions': [{
			'id_str': '747329673659482113', 
			'id': 747329673659482113, 
			'name': 'ピコ太郎(PIKOTARO)(公式)', 
			'indices': [3, 17], 
			'screen_name': 'pikotaro_ppap'
		}], 
		'symbols': [], 
		'hashtags': [], 
		'media': [{
			'type': 'photo', 
			'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
			'source_user_id': 747329673659482113, 
			'source_user_id_str': '747329673659482113', 
			'display_url': 'pic.twitter.com/uP5PYzWhHL', 
			'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
			'sizes': {
				'large': {
					'resize': 'fit', 
					'h': 1536, 
					'w': 2048
				}, 
				'small': {
					'resize': 'fit', 
					'h': 510, 
					'w': 680
				}, 
				'medium': {
					'resize': 'fit', 
					'h': 900, 
					'w': 1200
				}, 
				'thumb': {
					'resize': 'crop', 
					'h': 150, 
					'w': 150
				}
			}, 
			'indices': [36, 59], 
			'id_str': '823362891273281537', 
			'source_status_id_str': '823362903805804546', 
			'source_status_id': 823362903805804546, 
			'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
			'id': 823362891273281537, 
			'url': 'https://t.co/uP5PYzWhHL'
		}]
	}, 
	##### ここまでstatus/entities #####

	##### ここからstatus/retweeted_status #####	
	retweeted_status=Status(

		##### ここからstatus/retweeted_status/author #####	
		author=User(
			time_zone=None, 
			profile_background_image_url=None, 
			listed_count=385, 
			is_translation_enabled=False, 
			profile_background_tile=False, 
			name='ピコ太郎(PIKOTARO)(公式)', 
			profile_sidebar_border_color='C0DEED', 
			screen_name='pikotaro_ppap', 
			url='https://t.co/02EEvEpRWi', 
			follow_request_sent=False, 

			##### ここからstatus/retweeted_status/author/_json #####	
			_json={
				'time_zone': None, 
				'description': '(OFFICIAL)シンガーソングライタ ー「ピコ太郎」と、申しやすっ。目指せ紅白歌合戦とサマソニ。リスペクトシンガー→恩人ジャスティンビーバー、クラフトワーク、M.I.A、杏里、石川さゆり、アリアナグランデ For international inquiries:ppap-world@av.avex.co.jp', 
				'following': False, 
				'profile_background_image_url': None, 
				'listed_count': 385, 
				'is_translation_enabled': False, 
				'profile_background_tile': False, 
				'profile_text_color': '333333', 
				'profile_image_url': 'http://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'favourites_count': 3, 
				'has_extended_profile': True, 
				'notifications': False, 
				'location': '', 
				'profile_use_background_image': True, 
				'name': 'ピコ太郎(PIKOTARO)(公式)', 
				'created_at': 'Mon Jun 27 07:24:13 +0000 2016', 
				'profile_image_url_https': 'https://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'screen_name': 'pikotaro_ppap', 
				'protected': False, 
				'profile_background_color': 'F5F8FA', 
				'url': 'https://t.co/02EEvEpRWi', 
				'follow_request_sent': False, 
				'friends_count': 97, 
				'default_profile': True, 
				'default_profile_image': False, 
				'followers_count': 88696, 
				'translator_type': 'none', 
				'id_str': '747329673659482113', 
				'statuses_count': 1210, 
				'contributors_enabled': False, 
				'profile_link_color': '1DA1F2', 
				'is_translator': False, 
				'id': 747329673659482113, 
				'entities': {
					'description': {
						'urls': []
					}, 
					'url': {
						'urls': [{
							'display_url': 'm.youtube.com/channel/UCKpIO…', 
							'expanded_url': 'https://m.youtube.com/channel/UCKpIOnsk-gcwHXIzuk24ExA', 
							'url': 'https://t.co/02EEvEpRWi', 
							'indices': [0, 23]
						}]
					}
				}, 
				'geo_enabled': False, 
				'profile_sidebar_fill_color': 'DDEEF6', 
				'profile_banner_url': 'https://pbs.twimg.com/profile_banners/747329673659482113/1484911282', 
				'verified': False, 
				'profile_background_image_url_https': None, 
				'lang': 'en', 
				'utc_offset': None, 
				'profile_sidebar_border_color': 'C0DEED'
			}, 
			##### ここまでstatus/retweeted_status/author/_json #####	
			
			default_profile_image=False, 
			profile_use_background_image=True, 
			entities={
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'm.youtube.com/channel/UCKpIO…', 
						'expanded_url': 'https://m.youtube.com/channel/UCKpIOnsk-gcwHXIzuk24ExA', 
						'url': 'https://t.co/02EEvEpRWi', 
						'indices': [0, 23]
					}]
				}
			}, 
			statuses_count=1210, 
			contributors_enabled=False, 
			profile_link_color='1DA1F2', 
			notifications=False, 
			id=747329673659482113, 
			profile_background_image_url_https=None, 
			profile_sidebar_fill_color='DDEEF6', 
			utc_offset=None, 
			description='(OFFICIAL)シンガーソングライタ ー「ピコ太郎」と、申しやすっ。目指せ紅白歌合戦とサマソニ。リスペクトシンガー→恩人ジャスティンビーバー、クラフトワーク、M.I.A、杏里、石川さゆり、アリアナグランデ For international inquiries:ppap-world@av.avex.co.jp', 
			profile_text_color='333333', 
			followers_count=88696, 
			default_profile=True, 
			profile_image_url='http://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
			favourites_count=3, 
			_api=<tweepy.api.API object at 0x117919198>, 
			location='', 
			created_at=datetime.datetime(2016, 6, 27, 7, 24, 13), 
			profile_image_url_https='https://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
			protected=False, 
			friends_count=97, 
			following=False, 
			profile_banner_url='https://pbs.twimg.com/profile_banners/747329673659482113/1484911282', 
			id_str='747329673659482113', 
			is_translator=False, 
			profile_background_color='F5F8FA', 
			translator_type='none', 
			geo_enabled=False, 
			verified=False, 
			has_extended_profile=True, 
			lang='en'
		), 
		##### ここまでstatus/retweeted_status/author #####

		possibly_sensitive=False, 

		##### ここからstatus/retweeted_status/extended_entities #####
		extended_entities={
			'media': [{
				'type': 'photo', 
				'id_str': '823362891273281537', 
				'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'display_url': 'pic.twitter.com/uP5PYzWhHL', 
				'url': 'https://t.co/uP5PYzWhHL', 
				'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
				'sizes': {
					'large': {
						'resize': 'fit', 
						'h': 1536, 
						'w': 2048
					}, 
					'small': {
						'resize': 'fit', 
						'h': 510, 
						'w': 680
					}, 
					'medium': {
						'resize': 'fit', 
						'h': 900, 
						'w': 1200
					}, 
					'thumb': {
						'resize': 'crop', 
						'h': 150, 
						'w': 150
					}
				}, 
				'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'indices': [17, 40], 
				'id': 823362891273281537
			}]
		}, 
		##### ここまでstatus/retweeted_status/extended_entities #####

		coordinates=None, 
		source='Twitter for iPhone', 
		favorite_count=855, 
		text='PONで華原朋美様とお写真ピコ! https://t.co/uP5PYzWhHL', 

		##### ここからstatus/retweeted_status/user #####
		user=User(
			time_zone=None, 
			profile_background_image_url=None, 
			listed_count=385, 
			is_translation_enabled=False, 
			profile_background_tile=False, 
			name='ピコ太郎(PIKOTARO)(公式)', 
			profile_sidebar_border_color='C0DEED', 
			screen_name='pikotaro_ppap', 
			url='https://t.co/02EEvEpRWi', 
			follow_request_sent=False, 

			##### ここからstatus/retweeted_status/user/_json #####
			_json={
				'time_zone': None, 
				'description': '(OFFICIAL)シンガーソングライタ ー「ピコ太郎」と、申しやすっ。目指せ紅白歌合戦とサマソニ。リスペクトシンガー→恩人ジャスティンビーバー、クラフトワーク、M.I.A、杏里、石川さゆり、アリアナグランデ For international inquiries:ppap-world@av.avex.co.jp', 
				'following': False, 
				'profile_background_image_url': None, 
				'listed_count': 385, 
				'is_translation_enabled': False, 
				'profile_background_tile': False, 
				'profile_text_color': '333333', 
				'profile_image_url': 'http://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'favourites_count': 3, 
				'has_extended_profile': True, 
				'notifications': False, 
				'location': '', 
				'profile_use_background_image': True, 
				'name': 'ピコ太郎(PIKOTARO)(公式)', 
				'created_at': 'Mon Jun 27 07:24:13 +0000 2016', 
				'profile_image_url_https': 'https://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'screen_name': 'pikotaro_ppap', 
				'protected': False, 
				'profile_background_color': 'F5F8FA', 
				'url': 'https://t.co/02EEvEpRWi', 
				'follow_request_sent': False, 
				'friends_count': 97, 
				'default_profile': True, 
				'default_profile_image': False, 
				'followers_count': 88696, 
				'translator_type': 'none', 
				'id_str': '747329673659482113', 
				'statuses_count': 1210, 
				'contributors_enabled': False, 
				'profile_link_color': '1DA1F2', 
				'is_translator': False, 
				'id': 747329673659482113, 
				'entities': {
					'description': {'urls': []}, 
					'url': {
						'urls': [{
							'display_url': 'm.youtube.com/channel/UCKpIO…', 
							'expanded_url': 'https://m.youtube.com/channel/UCKpIOnsk-gcwHXIzuk24ExA', 
							'url': 'https://t.co/02EEvEpRWi', 
							'indices': [0, 23]
						}]
					}
				}, 
				'geo_enabled': False, 
				'profile_sidebar_fill_color': 'DDEEF6', 
				'profile_banner_url': 'https://pbs.twimg.com/profile_banners/747329673659482113/1484911282', 
				'verified': False, 
				'profile_background_image_url_https': None, 
				'lang': 'en', 
				'utc_offset': None, 
				'profile_sidebar_border_color': 'C0DEED'
			}, 
			##### ここまでstatus/retweeted_status/user/_json #####

			default_profile_image=False, 
			profile_use_background_image=True, 
			entities={
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'm.youtube.com/channel/UCKpIO…', 
						'expanded_url': 'https://m.youtube.com/channel/UCKpIOnsk-gcwHXIzuk24ExA', 
						'url': 'https://t.co/02EEvEpRWi', 
						'indices': [0, 23]
					}]
				}
			}, 
			statuses_count=1210, 
			contributors_enabled=False, 
			profile_link_color='1DA1F2', 
			notifications=False, 
			id=747329673659482113, 
			profile_background_image_url_https=None, 
			profile_sidebar_fill_color='DDEEF6', 
			utc_offset=None, 
			description='(OFFICIAL)シンガーソングライタ ー「ピコ太郎」と、申しやすっ。目指せ紅白歌合戦とサマソニ。リスペクトシンガー→恩人ジャスティンビーバー、クラフトワーク、M.I.A、杏里、石川さゆり、アリアナグランデ For international inquiries:ppap-world@av.avex.co.jp', 
			profile_text_color='333333', 
			followers_count=88696, 
			default_profile=True, 
			profile_image_url='http://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
			favourites_count=3, 
			_api=<tweepy.api.API object at 0x117919198>, 
			location='', 
			created_at=datetime.datetime(2016, 6, 27, 7, 24, 13), 
			profile_image_url_https='https://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
			protected=False, 
			friends_count=97, 
			following=False, 
			profile_banner_url='https://pbs.twimg.com/profile_banners/747329673659482113/1484911282', 
			id_str='747329673659482113', 
			is_translator=False, 
			profile_background_color='F5F8FA', 
			translator_type='none', 
			geo_enabled=False, 
			verified=False, 
			has_extended_profile=True, 
			lang='en'
		), 
		##### ここまでstatus/retweeted_status/user #####

		contributors=None, 
		created_at=datetime.datetime(2017, 1, 23, 2, 53, 8), 
		in_reply_to_user_id_str=None, 
		source_url='http://twitter.com/download/iphone', 
		id=823362903805804546, 
		_api=<tweepy.api.API object at 0x117919198>, 
		retweeted=True, 
		in_reply_to_screen_name=None, 
		is_quote_status=False, 
		in_reply_to_user_id=None, 

		##### ここからstatus/retweeted_status/entities #####
		entities={
			'urls': [], 
			'user_mentions': [], 
			'symbols': [], 
			'hashtags': [], 
			'media': [{
				'type': 'photo', 
				'id_str': '823362891273281537', 
				'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'display_url': 'pic.twitter.com/uP5PYzWhHL', 
				'url': 'https://t.co/uP5PYzWhHL', 
				'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
				'sizes': {
					'large': {
						'resize': 'fit', 
						'h': 1536, 
						'w': 2048
					}, 
					'small': {
						'resize': 'fit', 
						'h': 510, 
						'w': 680
					}, 
					'medium': {
						'resize': 'fit', 
						'h': 900, 
						'w': 1200
					}, 
					'thumb': {
						'resize': 'crop', 
						'h': 150, 
						'w': 150
					}
				}, 
				'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'indices': [17, 40], 
				'id': 823362891273281537
			}]
		}, 
		##### ここまでstatus/retweeted_status/entities #####

		retweet_count=133, 
		possibly_sensitive_appealable=False, 
		in_reply_to_status_id_str=None, 
		truncated=False, 
		in_reply_to_status_id=None, 
		id_str='823362903805804546', 
		favorited=False, 

		##### ここからstatus/retweeted_status/_json #####
		_json={
			'favorite_count': 855, 
			'possibly_sensitive': False, 

			##### ここからstatus/retweeted_status/_json/extended_entities #####
			'extended_entities': {
				'media': [{
					'type': 'photo', 
					'id_str': '823362891273281537', 
					'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'display_url': 'pic.twitter.com/uP5PYzWhHL', 
					'url': 'https://t.co/uP5PYzWhHL', 
					'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
					'sizes': {
						'large': {
							'resize': 'fit', 
							'h': 1536, 
							'w': 2048
						}, 
						'small': {
							'resize': 'fit', 
							'h': 510, 
							'w': 680
						}, 
						'medium': {
							'resize': 'fit', 
							'h': 900, 
							'w': 1200
						}, 
						'thumb': {
							'resize': 'crop', 
							'h': 150, 
							'w': 150
						}
					}, 
					'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'indices': [17, 40], 
					'id': 823362891273281537
				}]
			}, 
			##### ここまでstatus/retweeted_status/_json/extended_entities #####

			'coordinates': None, 
			'source': '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>', 
			'text': 'PONで華原朋美様とお写真ピコ! https://t.co/uP5PYzWhHL', 

			##### ここからstatus/retweeted_status/_json/user #####
			'user': {
				'time_zone': None, 
				'description': '(OFFICIAL)シンガーソングライタ ー「ピコ太郎」と、申しやすっ。目指せ紅白歌合戦とサマソニ。リスペクトシンガー→恩人ジャスティンビーバー、クラフトワーク、M.I.A、杏里、石川さゆり、アリアナグランデ For international inquiries:ppap-world@av.avex.co.jp', 
				'following': False, 
				'profile_background_image_url': None, 
				'listed_count': 385, 
				'is_translation_enabled': False, 
				'profile_background_tile': False, 
				'profile_text_color': '333333', 
				'profile_image_url': 'http://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'favourites_count': 3, 
				'has_extended_profile': True, 
				'notifications': False, 
				'location': '', 
				'profile_use_background_image': True, 
				'name': 'ピコ太郎(PIKOTARO)(公式)', 
				'created_at': 'Mon Jun 27 07:24:13 +0000 2016', 
				'profile_image_url_https': 'https://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'screen_name': 'pikotaro_ppap', 
				'protected': False, 
				'profile_background_color': 'F5F8FA', 
				'url': 'https://t.co/02EEvEpRWi', 
				'follow_request_sent': False, 
				'friends_count': 97, 
				'default_profile': True, 
				'default_profile_image': False, 
				'followers_count': 88696, 
				'translator_type': 'none', 
				'id_str': '747329673659482113', 
				'statuses_count': 1210, 
				'contributors_enabled': False, 
				'profile_link_color': '1DA1F2', 
				'is_translator': False, 
				'id': 747329673659482113, 
				'entities': {
					'description': {'urls': []}, 
					'url': {
						'urls': [{
							'display_url': 'm.youtube.com/channel/UCKpIO…', 
							'expanded_url': 'https://m.youtube.com/channel/UCKpIOnsk-gcwHXIzuk24ExA', 
							'url': 'https://t.co/02EEvEpRWi', 
							'indices': [0, 23]
						}]
					}
				}, 
				'geo_enabled': False, 
				'profile_sidebar_fill_color': 'DDEEF6', 
				'profile_banner_url': 'https://pbs.twimg.com/profile_banners/747329673659482113/1484911282', 
				'verified': False, 
				'profile_background_image_url_https': None, 
				'lang': 'en', 
				'utc_offset': None, 
				'profile_sidebar_border_color': 'C0DEED'
			}, 
			##### ここまでstatus/retweeted_status/_json/user #####			
			
			'contributors': None, 
			'created_at': 'Mon Jan 23 02:53:08 +0000 2017', 
			'truncated': False, 
			'retweeted': True, 
			'in_reply_to_screen_name': None, 
			'is_quote_status': False, 
			'in_reply_to_user_id': None, 
			'id_str': '823362903805804546', 
			'retweet_count': 133, 
			'possibly_sensitive_appealable': False, 
			'in_reply_to_status_id_str': None, 
			'id': 823362903805804546, 
			'in_reply_to_status_id': None, 

			##### ここからstatus/retweeted_status/_json/entities #####			
			'entities': {
				'urls': [], 
				'user_mentions': [], 
				'symbols': [], 
				'hashtags': [], 
				'media': [{
					'type': 'photo', 
					'id_str': '823362891273281537', 
					'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'display_url': 'pic.twitter.com/uP5PYzWhHL', 
					'url': 'https://t.co/uP5PYzWhHL', 
					'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
					'sizes': {
						'large': {
							'resize': 'fit', 
							'h': 1536, 
							'w': 2048
						}, 
						'small': {
							'resize': 'fit', 
							'h': 510, 
							'w': 680
						}, 
						'medium': {
							'resize': 'fit', 
							'h': 900, 
							'w': 1200
						}, 
						'thumb': {
							'resize': 'crop', 
							'h': 150, 
							'w': 150
						}
					}, 
					'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'indices': [17, 40], 
					'id': 823362891273281537
				}]
			}, 
			##### ここまでstatus/retweeted_status/_json/entities #####			

			'favorited': False, 
			'in_reply_to_user_id_str': None, 
			'lang': 'ja', 
			'place': None, 
			'geo': None
		}, 
		##### ここまでstatus/retweeted_status/_json #####

		lang='ja', 
		place=None, 
		geo=None
	), 
	##### ここまでstatus/retweeted_status #####

	retweet_count=133, 
	possibly_sensitive_appealable=False, 
	in_reply_to_status_id_str=None, 
	truncated=False, 
	in_reply_to_status_id=None, 
	id_str='823594183499780096', 
	favorited=False, 

	##### ここからstatus/_json #####
	_json={
		'favorite_count': 0, 
		'possibly_sensitive': False, 

		##### ここからstatus/_json/extended_entities #####	
		'extended_entities': {
			'media': [{
				'type': 'photo', 
				'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'source_user_id': 747329673659482113, 
				'source_user_id_str': '747329673659482113', 
				'display_url': 'pic.twitter.com/uP5PYzWhHL', 
				'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'sizes': {
					'large': {
						'resize': 'fit', 
						'h': 1536, 
						'w': 2048
					}, 
					'small': {
						'resize': 'fit', 
						'h': 510, 
						'w': 680
					}, 
					'medium': {
						'resize': 'fit', 
						'h': 900, 
						'w': 1200
					}, 
					'thumb': {
						'resize': 'crop', 
						'h': 150, 
						'w': 150
					}
				}, 
				'indices': [36, 59], 
				'id_str': '823362891273281537', 
				'source_status_id_str': '823362903805804546', 
				'source_status_id': 823362903805804546, 
				'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
				'id': 823362891273281537, 
				'url': 'https://t.co/uP5PYzWhHL'
			}]
		}, 
		##### ここまでstatus/_json/extended_entities #####

		'coordinates': None, 
		'source': '<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>', 
		'text': 'RT @pikotaro_ppap: PONで華原朋美様とお写真ピコ! https://t.co/uP5PYzWhHL', 

		##### ここからstatus/_json/user #####
		'user': {
			'time_zone': 'Tokyo', 
			'description': '統計学とプログラミングの勉強ブログを書いています(私は初心者なので専門的なものではない)。剣道初心者で、とりあえず1級審査に向けて稽古中。TX通勤。博士(工学)。', 
			'following': False, 
			'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 
			'listed_count': 38, 
			'is_translation_enabled': True, 
			'profile_background_tile': False, 
			'profile_text_color': '333333', 
			'profile_image_url': 'http://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'favourites_count': 1088, 
			'notifications': False, 
			'location': 'つくば市', 
			'profile_use_background_image': True, 
			'name': 'bata', 
			'created_at': 'Sat Feb 26 04:59:47 +0000 2011', 
			'profile_image_url_https': 'https://pbs.twimg.com/profile_images/517659681313923073/_m3UMIAR_normal.jpeg', 
			'screen_name': 'statsbeginner', 
			'protected': False, 
			'profile_background_color': 'C0DEED', 
			'url': 'https://t.co/6HCF2FYowE', 
			'follow_request_sent': False, 
			'friends_count': 775, 
			'default_profile': True, 
			'default_profile_image': False, 
			'followers_count': 1873, 
			'translator_type': 'none', 
			'id_str': '257791390', 
			'statuses_count': 13015, 
			'contributors_enabled': False, 
			'profile_link_color': '1DA1F2', 
			'is_translator': False, 
			'id': 257791390, 
			'entities': {
				'description': {'urls': []}, 
				'url': {
					'urls': [{
						'display_url': 'statsbeginner.hatenablog.com', 
						'expanded_url': 'http://statsbeginner.hatenablog.com/', 
						'url': 'https://t.co/6HCF2FYowE', 
						'indices': [0, 23]
					}]
				}
			}, 
			'geo_enabled': True, 
			'profile_sidebar_fill_color': 'DDEEF6', 
			'has_extended_profile': False, 
			'verified': False, 
			'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 
			'lang': 'ja', 
			'utc_offset': 32400, 
			'profile_sidebar_border_color': 'C0DEED'
		}, 
		##### ここまでstatus/_json/user #####

		'contributors': None, 
		'created_at': 'Mon Jan 23 18:12:09 +0000 2017', 
		'truncated': False, 
		'retweeted': True, 
		'in_reply_to_screen_name': None, 
		'is_quote_status': False, 
		'in_reply_to_user_id': None, 
		'id_str': '823594183499780096', 

		##### ここからstatus/_json/retweeted_status #####
		'retweeted_status': {
			'favorite_count': 855, 
			'possibly_sensitive': False, 

			##### ここからstatus/_json/retweeted_status/extended_entities #####
			'extended_entities': {
				'media': [{
					'type': 'photo', 
					'id_str': '823362891273281537', 
					'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'display_url': 'pic.twitter.com/uP5PYzWhHL', 
					'url': 'https://t.co/uP5PYzWhHL', 
					'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
					'sizes': {
						'large': {
							'resize': 'fit', 
							'h': 1536, 
							'w': 2048
						}, 
						'small': {
							'resize': 'fit', 
							'h': 510, 
							'w': 680
						}, 
						'medium': {
							'resize': 'fit', 
							'h': 900, 
							'w': 1200
						}, 
						'thumb': {
							'resize': 'crop', 
							'h': 150, 
							'w': 150
						}
					}, 
					'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'indices': [17, 40], 
					'id': 823362891273281537
				}]
			}, 
			##### ここまでstatus/_json/retweeted_status/extended_entities #####

			'coordinates': None, 
			'source': '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>', 
			'text': 'PONで華原朋美様とお写真ピコ! https://t.co/uP5PYzWhHL', 

			##### ここからstatus/_json/retweeted_status/user #####
			'user': {
				'time_zone': None, 
				'description': '(OFFICIAL)シンガーソングライタ ー「ピコ太郎」と、申しやすっ。目指せ紅白歌合戦とサマソニ。リスペクトシンガー→恩人ジャスティンビーバー、クラフトワーク、M.I.A、杏里、石川さゆり、アリアナグランデ For international inquiries:ppap-world@av.avex.co.jp', 
				'following': False, 
				'profile_background_image_url': None, 
				'listed_count': 385, 
				'is_translation_enabled': False, 
				'profile_background_tile': False, 
				'profile_text_color': '333333', 
				'profile_image_url': 'http://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'favourites_count': 3, 
				'has_extended_profile': True, 
				'notifications': False, 
				'location': '', 
				'profile_use_background_image': True, 
				'name': 'ピコ太郎(PIKOTARO)(公式)', 
				'created_at': 'Mon Jun 27 07:24:13 +0000 2016', 
				'profile_image_url_https': 'https://pbs.twimg.com/profile_images/822403634931433472/udAnDIVV_normal.jpg', 
				'screen_name': 'pikotaro_ppap', 
				'protected': False, 
				'profile_background_color': 'F5F8FA', 
				'url': 'https://t.co/02EEvEpRWi', 
				'follow_request_sent': False, 
				'friends_count': 97, 
				'default_profile': True, 
				'default_profile_image': False, 
				'followers_count': 88696, 
				'translator_type': 'none', 
				'id_str': '747329673659482113', 
				'statuses_count': 1210, 
				'contributors_enabled': False, 
				'profile_link_color': '1DA1F2', 
				'is_translator': False, 
				'id': 747329673659482113, 
				'entities': {
					'description': {'urls': []}, 
					'url': {
						'urls': [{
							'display_url': 'm.youtube.com/channel/UCKpIO…', 
							'expanded_url': 'https://m.youtube.com/channel/UCKpIOnsk-gcwHXIzuk24ExA', 
							'url': 'https://t.co/02EEvEpRWi', 
							'indices': [0, 23]
						}]
					}
				}, 
				'geo_enabled': False, 
				'profile_sidebar_fill_color': 'DDEEF6', 
				'profile_banner_url': 'https://pbs.twimg.com/profile_banners/747329673659482113/1484911282', 
				'verified': False, 
				'profile_background_image_url_https': None, 
				'lang': 'en', 
				'utc_offset': None, 
				'profile_sidebar_border_color': 'C0DEED'
			}, 
			##### ここまでstatus/_json/retweeted_status/user #####

			'contributors': None, 
			'created_at': 'Mon Jan 23 02:53:08 +0000 2017', 
			'truncated': False, 
			'retweeted': True, 
			'in_reply_to_screen_name': None, 
			'is_quote_status': False, 
			'in_reply_to_user_id': None, 
			'id_str': '823362903805804546', 
			'retweet_count': 133, 
			'possibly_sensitive_appealable': False, 
			'in_reply_to_status_id_str': None, 
			'id': 823362903805804546, 
			'in_reply_to_status_id': None, 

			##### ここからstatus/_json/retweeted_status/entities #####
			'entities': {
				'urls': [], 
				'user_mentions': [], 
				'symbols': [], 
				'hashtags': [], 
				'media': [{
					'type': 'photo', 
					'id_str': '823362891273281537', 
					'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'display_url': 'pic.twitter.com/uP5PYzWhHL', 
					'url': 'https://t.co/uP5PYzWhHL', 
					'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
					'sizes': {
						'large': {
							'resize': 'fit', 
							'h': 1536, 
							'w': 2048
						}, 
						'small': {
							'resize': 'fit', 
							'h': 510, 
							'w': 680
						}, 
						'medium': {
							'resize': 'fit', 
							'h': 900, 
							'w': 1200
						}, 
						'thumb': {
							'resize': 'crop', 
							'h': 150, 
							'w': 150
						}
					}, 
					'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
					'indices': [17, 40], 
					'id': 823362891273281537
				}]
			}, 
			##### ここまでstatus/_json/retweeted_status/entities #####

			'favorited': False, 
			'in_reply_to_user_id_str': None, 
			'lang': 'ja', 
			'place': None, 
			'geo': None
		}, 
		##### ここまでstatus/_json/retweeted_status #####

		'retweet_count': 133, 
		'possibly_sensitive_appealable': False, 
		'in_reply_to_status_id_str': None, 
		'id': 823594183499780096, 
		'in_reply_to_status_id': None, 

		##### ここからstatus/_json/entities #####
		'entities': {
			'urls': [], 
			'user_mentions': [{
				'id_str': '747329673659482113', 
				'id': 747329673659482113, 
				'name': 'ピコ太郎(PIKOTARO)(公式)', 
				'indices': [3, 17], 
				'screen_name': 'pikotaro_ppap'
			}], 
			'symbols': [], 
			'hashtags': [], 
			'media': [{
				'type': 'photo', 
				'media_url': 'http://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'source_user_id': 747329673659482113, 
				'source_user_id_str': '747329673659482113', 
				'display_url': 'pic.twitter.com/uP5PYzWhHL', 
				'media_url_https': 'https://pbs.twimg.com/media/C20sL--VIAEra5v.jpg', 
				'sizes': {
					'large': {
						'resize': 'fit', 
						'h': 1536, 
						'w': 2048
					}, 
					'small': {
						'resize': 'fit', 
						'h': 510, 
						'w': 680
					}, 
					'medium': {
						'resize': 'fit', 
						'h': 900, 
						'w': 1200
					}, 
					'thumb': {
						'resize': 'crop', 
						'h': 150, 
						'w': 150
					}
				}, 
				'indices': [36, 59], 
				'id_str': '823362891273281537', 
				'source_status_id_str': '823362903805804546', 
				'source_status_id': 823362903805804546, 
				'expanded_url': 'https://twitter.com/pikotaro_ppap/status/823362903805804546/photo/1', 
				'id': 823362891273281537, 
				'url': 'https://t.co/uP5PYzWhHL'
			}]
		}, 
		##### ここまでstatus/_json/entities #####

		'favorited': False, 
		'in_reply_to_user_id_str': None, 
		'lang': 'ja', 
		'place': None, 
		'geo': None
	}, 
	##### ここまでstatus/_json #####

	lang='ja', 
	place=None, 
	geo=None
)

 
 

Friendshipオブジェクト

 先に来てるほうがSourceから見た関係、後で来るほうがTargetからみた関係です。_jsonが含まれないです。
 そのまんまですが、followingはフォローしてる。followed_byはフォローされてる。
 following_receivedとfollowing_requestedは恐らく、前者がフォローリクエストを送って承認されたらTrue、後者はフォローリクエストされて承認した場合にTrueになるやつだと思います。
 marked_spamはスパム報告したアカウントはTrue、blockingはブロックしているアカウントがTrue、blocked_byは逆にブロックされていた場合にTrueですね。botの処理を書いていると、相手からブロックされている場合や相手が鍵垢の場合に単純に実行するとエラーになってしまうような処理も出てくるので、そういう場合に、ブロックされていないかどうかをチェックして処理を分岐させるのに使ったりできます。

(
Friendship(
    followed_by=False, 
    blocking=False, 
    following_received=False, 
    id=257791390, 
    live_following=False, 
    muting=False, 
    notifications_enabled=False, 
    can_dm=False, 
    following=False, 
    following_requested=False, 
    _api=<tweepy.api.API object at 0x11240bef0>, 
    want_retweets=False, 
    id_str='257791390', 
    screen_name='statsbeginner', 
    marked_spam=False, 
    blocked_by=True, 
    all_replies=False
), 
Friendship(
    followed_by=False, 
    following_received=False, 
    id=150598902, 
    following=False, 
    following_requested=False, 
    _api=<tweepy.api.API object at 0x11240bef0>, 
    id_str='150598902', 
    screen_name='InsideCHIKIRIN'
)
)

 
 

Saved Searchオブジェクト

 検索のクエリを保存しといてショートカット的に使うやつですね。
 queryのところが、検索キーワードです。positionってなんだろ?ぐぐったけど分かりません。nameがqueryと異なる場合があるのかは不明。

[
SavedSearch(
	_api=<tweepy.api.API object at 0x11240bef0>, 
	query='Python', 
	id=829013630154788864, 
	id_str='829013630154788864', 
	created_at=datetime.datetime(2017, 2, 7, 17, 7, 6), 
	name='Python', 
	position=None
), 
SavedSearch(
	_api=<tweepy.api.API object at 0x11240bef0>, 
	query='機械学習', 
	id=829013886934212608, 
	id_str='829013886934212608', 
	created_at=datetime.datetime(2017, 2, 7, 17, 8, 7), 
	name='機械学習', 
	position=None
)
]

*1:Twitterの規約では、目的や内容が重複していなければ、複数のアカウントの保有は禁じられていない。

*2:リクエストを投げすぎて制限に引っかかったり、最悪の場合アカウントが凍結されたり。へんなつぶやきやフォロー/アンフォローで人に迷惑をかけたり。

*3:データ収集対象としては、メイン垢のリストも使っている

*4:第二の関門はリクエスト数制限、第三の関門はカーソリングかな。

*5:ずっと悩んでたけどStack Overflowで質問して判明。

*6:簡易的に、データ項目名だけ一覧で取得するには、オブジェクトをdir()に与えればいいです。

Pythonメモ: Pandasのデータフレームに空のデータフレームを合体させたらint型の列がfloat型になってた

 こんな事象に陥る人が他にいるのか分からないのですが、ググって解決しなかった問題が解決したので、せっかくだからメモしておきます。


 Pandasのデータフレームに、整数型で値が入っている列があるとします。

>>> import pandas as pd
>>> import numpy
>>> 
>>> df1 = pd.DataFrame({
...     'ID':[123456789012345678, 123456789012345673, 12345678901234567],
...     'Name':['Ichiro','Jiro','Saburo']
...     },
...     columns = ['ID', 'Name']
... )
>>> 
>>> type(df1['ID'][0])  # 列ごと取り出すとPandasのSeriesですと言われるので
<class 'numpy.int64'>


 このデータフレームに、列の構成は同じで行が空になっているデータフレームをappendで下からくっつけたら、整数型の列がfloat型に変わりました。

>>> df2 = pd.DataFrame({
...     'ID':[],
...     'Name':[]
...     },
...     columns = ['ID', 'Name']
... )
>>> 
>>> df12 = df1.append(df2)
>>> 
>>> type(df12['ID'][0])
<class 'numpy.float64'>
>>> 
>>> print([v for v in df12['ID']])
[1.2345678901234568e+17, 1.2345678901234568e+17, 12345678901234568.0]
>>> 


 しかも桁数が大きいので、指数表示になっていますね。
 Nameはもちろん、文字列型になっています。

>>> type(df12['Name'][0])
<class 'str'>


 空のデータフレームをくっつけるみたいな変なことが起きないように処理を組んでおけばいいと思うのですが、私が書いてたTwitterのbot(仕事関係の情報をつぶやくアカウントを半分botにしています)内のデータ集計の部分でpandasを使っていて、こういう事象が発生し得る状態になってしまっていました。 
 しかも、いったんfloat型になったものがその後の処理で結果的にint型に変換されるようになっていたので、なかなか気づきませんでした。なんで気づいたかというと、これがまたヤバいのですが、桁数が大きいので、指数表示になったときに「...568」で止まって以降の数字が切り上げ(?)されてしまっているように、元の数字に戻らないわけです。
 一応試しにやってみると、

>>> df12[['ID']] = df12[['ID']].astype(numpy.int64) # 整数型に変換する
>>> 
>>> print([v for v in df12['ID']])
[123456789012345680, 123456789012345680, 12345678901234568]


 数字が変わってしまっておりますね。このせいで、私のbot内でも、ユーザIDが指数表示を経て別の数字に変わってしまっているものが一部あり、「そのIDのユーザは見つかりません」というエラーが出ていました。そこから辿っていって、Pandasに空のデータフレームを扱わせてfloat型を経由していることに気づいたわけです。
 
 
 そもそもユーザIDを整数型で持つ必要はなく、文字列型にすればいいわけですが、TwitterのAPIから帰ってくるIDが単なる数字の並びになっていて、int型として認識されていたので、そのままにしてました。
 素人なのでよく知りませんが、IDを整数型にしてるケースってけっこうあるんですかね?

 
 TwitterIDが33bitになったため、値をINT型に入れているとエラーに。 | iconDecotter-Log
 世界規模のWebサービスを作るときにDBのユーザーIDをINT型にしてはいけない理由 | 着ぐるみ追い剥ぎペンギン


 こういう記事をからすると、文字列型にしてるのが当然ってわけでもないんだろうか。メリット・デメリット等、私はよく分かりませんが、文字列のほうが間違いが少なそうなので、あとでbotの修正をしようと思います。
 ちなみに、IDを文字列型として扱いたい場合、Tweepyのレスポンスの中にある「id」という項目ではなく「id_str」という項目を取得すればよいです。