Slide 1

Slide 1 text

何となくわかってきた Twitter API と 仲よく付き合う方法 2013.6.7 (Twitter) API 勉強会 at 恵比寿 engineyard_jp #apihack @komiya_atsushi 1

Slide 2

Slide 2 text

Agenda 1. 自己紹介 2. 今日のお話の背景 3. Twitter API と仲良く付き合うために 知っておくべき 6 つのこと 4. まとめ 2

Slide 3

Slide 3 text

1. 自己紹介 3

Slide 4

Slide 4 text

KOMIYA Atsushi @komiya_atsushi 4

Slide 5

Slide 5 text

分析力をコアとする 情報最適化企業 5

Slide 6

Slide 6 text

で Twitter API を一心不乱に、ただひたすら しばく機械学習寄りなエンジニアやってます 6

Slide 7

Slide 7 text

#TokyoWebmining 事務局 分析/機械学習/アドテク等のネタで お話していただける講師を募集中デス! 7

Slide 8

Slide 8 text

2. 今日のお話の 背景 8

Slide 9

Slide 9 text

僕と Twitter API •2010 ~ 2011 年 •Twitter API (v1) を認証なしでひたすらしばく お仕事 •特定アカウントからのフォロー・フォロワー 関係をクローリングするなど •2012 年 ~ •Twitter API (v1 → v1.1) を OAuth 認証して ただただ殴るお仕事 •ツイートを蓄積して後から参照できるように するなど 9

Slide 10

Slide 10 text

僕と Twitter API •2010 ~ 2011 年 •Twitter API (v1) を認証なしでひたすらしばく お仕事 •特定アカウントからのフォロー・フォロワー 関係をクローリングするなど •2012 年 ~ •Twitter API (v1 → v1.1) を OAuth 認証して ただただ殴るお仕事 •ツイートを蓄積して後から参照できるように するなど Twitter API を利用して 情報を蓄積したり分析したり するお仕事をしてきました 10

Slide 11

Slide 11 text

今日お話すること •主に Java (& Twitter4J) を用いてツ イートをデータベースに蓄積するに あたって •「えっ何これ? こんな仕様ドキュメント に書いてないじゃん/食い違ってるじゃ ん…」 •「こんなデータが来るとは想定していな かった…」 的なことをゆるく語っていきます 11

Slide 12

Slide 12 text

3. Twitter API と 仲良く付き合う ために知っておく べき 6 つのこと 12

Slide 13

Slide 13 text

【1】 アプリケーション の登録に注意する 13

Slide 14

Slide 14 text

アプリケーション登録時に最も注意すべきこと 14

Slide 15

Slide 15 text

アプリケーション登録時に最も注意すべきこと 15

Slide 16

Slide 16 text

アプリケーション登録時に最も注意すべきこと http://twitter.com/hogehoge Web サイトは準備中だから、 ひとまず Twitter の URL を入れておこう… 16

Slide 17

Slide 17 text

突然の Suspended!!! アプリケーション名 アカウント名 アプリケーション名 (;・∀・)ハッ? 17

Slide 18

Slide 18 text

突然の Suspended!!! アプリケーション名 アカウント名 アプリケーション名 (;・∀・)ハッ? 18

Slide 19

Slide 19 text

突然の Suspended!!! アプリケーション名 アカウント名 アプリケーション名 (;・∀・)ハッ? HTTP ステータスコード 401 メッセージ “Could not authenticate you” が返却されるようになります 19

Slide 20

Slide 20 text

それ、ヘルプセンターに書いてあるよ https://support.twitter.com/articles/438104-api 20

Slide 21

Slide 21 text

それ、ヘルプセンターに書いてあるよ https://support.twitter.com/articles/438104-api 21

Slide 22

Slide 22 text

それ、ヘルプセンターに書いてあるよ https://support.twitter.com/articles/438104-api 22

Slide 23

Slide 23 text

結論 •アプリケーション URL (Website) は ちゃんと入力しましょう •ヘルプセンターをよく読みましょう 23

Slide 24

Slide 24 text

【2】 絵文字に負けない 24

Slide 25

Slide 25 text

絵文字を含むツイート https://twitter.com/alb_komiya/status/342343210422661121 25

Slide 26

Slide 26 text

絵文字を含むツイート https://twitter.com/alb_komiya/status/342343210422661121 26 ツイートを DB に蓄積しよう とすると問題が・・・

Slide 27

Slide 27 text

MySQL 特有の事情 CREATE TABLE status( id BIGINT PRIMARY KEY ,tweet VARCHAR(140) ); 27

Slide 28

Slide 28 text

MySQL 特有の事情 CREATE TABLE status( id BIGINT PRIMARY KEY ,tweet VARCHAR(140) ); java.sql.SQLException: Incorrect string value: '...' for column 'col_name' at row 1 28

Slide 29

Slide 29 text

MySQL 特有の事情 •絵文字(Unicode 追加面の文字)を 含むテキストを DB に格納するには utf8mb4 の文字エンコーディングを指 定する必要があり •かつ、絵文字は VARCHAR 4 文字分消 費するので x 4 した桁数が必要に •参考 •http://blog.k11i.biz/2012/11/utf-8-mysql- jdbc.html 29

Slide 30

Slide 30 text

MySQL 特有の事情 CREATE TABLE status( id BIGINT PRIMARY KEY ,tweet VARCHAR(140) ) ENGINE InnoDB CHARSET utf8mb4; 30 # my.cnf (my.ini) ... [mysqld] character-set-server=utf8mb4

Slide 31

Slide 31 text

結論 •MySQL でツイートを蓄積するときは 絵文字の存在を考慮し、文字エンコー ディングと VARCAHR の桁数に注意し ましょう •CREATE TABLE (~) CHARSET utf8mb4; •character-set-server=utf8mb4 •※ツイートに限らず、「名前」や 「プロフィール」など、フリー入力欄 はすべて考慮する必要があります 31

Slide 32

Slide 32 text

【3】 ヌル文字に 負けない 32

Slide 33

Slide 33 text

再現方法は不明ですが… •ときどきツイートにヌル文字 ¥u0000 が紛れ込むことがあるようです •このようなツイートを PostgreSQL に 投入しようとすると… 33

Slide 34

Slide 34 text

再現方法は不明ですが… •ときどきツイートにヌル文字 ¥u0000 が紛れ込むことがあるようです •このようなツイートを PostgreSQL に 投入しようとすると… org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00 34

Slide 35

Slide 35 text

結論 •PostgreSQL でツイートを蓄積する場 合、ヌル文字を含むツイートは •ヌル文字を除外して取り扱う •諦める …とするのがよいでしょう 35

Slide 36

Slide 36 text

【4】 NFD/NFKD に 負けない 36

Slide 37

Slide 37 text

一見すると 140 文字に見えますが… https://twitter.com/alb_komiya/status/342528279581949952 37

Slide 38

Slide 38 text

でも実際は public static void main(String[] args) throws TwitterException { Twitter twitter = TwitterFactory.getSingleton(); Status status = twitter.showStatus(342528279581949952L); System.out.println("文字数 " + status.getText().length()); char[] chars = status.getText().toCharArray(); System.out.println(chars[0] + " / " + (int)chars[0]); System.out.println(chars[1] + " / " + (int)chars[1]); } // 出力 文字数 280 a / 97 ̈ / 776 38

Slide 39

Slide 39 text

でも実際は public static void main(String[] args) throws TwitterException { Twitter twitter = TwitterFactory.getSingleton(); Status status = twitter.showStatus(342528279581949952L); System.out.println("文字数 " + status.getText().length()); char[] chars = status.getText().toCharArray(); System.out.println(chars[0] + " / " + (int)chars[0]); System.out.println(chars[1] + " / " + (int)chars[1]); } // 出力 文字数 280 a / 97 ̈ / 776 // 出力 文字数 280 a / 97 ̈ / 776 39

Slide 40

Slide 40 text

でも実際は public static void main(String[] args) throws TwitterException { Twitter twitter = TwitterFactory.getSingleton(); Status status = twitter.showStatus(342528279581949952L); System.out.println("文字数 " + status.getText().length()); char[] chars = status.getText().toCharArray(); System.out.println(chars[0] + " / " + (int)chars[0]); System.out.println(chars[1] + " / " + (int)chars[1]); } // 出力 文字数 280 a / 97 ̈ / 776 // 出力 文字数 280 a / 97 ̈ / 776 ä が a と̈ に分解されてたー \(^o^)/ 40

Slide 41

Slide 41 text

でも実際は public static void main(String[] args) throws TwitterException { Twitter twitter = TwitterFactory.getSingleton(); Status status = twitter.showStatus(342528279581949952L); System.out.println("文字数 " + status.getText().length()); char[] chars = status.getText().toCharArray(); System.out.println(chars[0] + " / " + (int)chars[0]); System.out.println(chars[1] + " / " + (int)chars[1]); } // 出力 文字数 280 a / 97 ̈ / 776 // 出力 文字数 280 a / 97 ̈ / 776 ä が a と̈ に分解されてたー \(^o^)/ スペイン語を扱ってるとよく遭遇する? 41

Slide 42

Slide 42 text

Unicode 正規化 •等価な文字や文字の並びを統一的な内 部表現に変換することでテキストの比 較を容易にする、テキスト正規化処理 の一種 •合成:n + ~ → ñ •分解:ñ → n + ~ •参考 •http://ja.wikipedia.org/wiki/Unicode%E6%A D%A3%E8%A6%8F%E5%8C%96 42

Slide 43

Slide 43 text

「合成」しておきましょう •PostgreSQL で のような定義をしている場合は としましょう String text = Normalizer.normalize(Status.getText(), Normalizer.Form.NFKC); CREATE TABLE status( id BIGINT PRIMARY KEY ,tweet VARCHAR(140) ); 43

Slide 44

Slide 44 text

結論 •Unicode の文字合成を積極的にしま しょう •RDBMS に PostgreSQL を利用して ツイートを蓄積する場合、文字合成を しないとカラム桁数超過のエラーが 発生し得ます 44

Slide 45

Slide 45 text

【5】 user が常に在る とは限らない 45

Slide 46

Slide 46 text

search/tweets を 呼び出しているとたまに出くわします •「status[“user”] が存在しないんですけど どういうこと!?」という現象 •今まで調べてきた限りでは以下の状況で発 生するようです 1. あるユーザ @a が “ほげほげ” とつぶやく 2. ユーザ @b がそれを RT する 3. @a がアカウントを削除する(された?) 4. “ほげほげ” で search/tweets すると、 @b の RT が検索に引っかかってしまう 46

Slide 47

Slide 47 text

search/tweets を 呼び出しているとたまに出くわします •「status[“user”] が存在しないんですけど どういうこと!?」という現象 •今まで調べてきた限りでは以下の状況で発 生するようです 1. あるユーザ @a が “ほげほげ” とつぶやく 2. ユーザ @b がそれを RT する 3. @a がアカウントを削除する(された?) 4. “ほげほげ” で search/tweets すると、 @b の RT が検索に引っかかってしまう ツイートした人を表すオブジェクト 47

Slide 48

Slide 48 text

以下の書き方には要注意! QueryResult res = twitter.search(new Query().query("hoge")); for (Status s : res.getTweets()) { String userName = s.getUser().getName(); // 何かの処理… } 48

Slide 49

Slide 49 text

以下の書き方には要注意! QueryResult res = twitter.search(new Query().query("hoge")); for (Status s : res.getTweets()) { String userName = s.getUser().getName(); // 何かの処理… } ここで NullPointerException が 発生するかも \(^o^)/ 49

Slide 50

Slide 50 text

結論 •search/tweets で得られるツイートの オブジェクトでは 、status[“user”] が 存在しない可能性を考慮しましょう •null チェック必須! 50

Slide 51

Slide 51 text

【6】 Twitter の screen_name が 最大 15 文字 であるはずがない 51

Slide 52

Slide 52 text

【6】 Twitter の screen_name が 最大 15 文字 であるはずがない @~ 52

Slide 53

Slide 53 text

Twitter の仕様的には… 省略 https://support.twitter.com/articles/249172 53

Slide 54

Slide 54 text

Twitter の仕様的には… 省略 https://support.twitter.com/articles/249172 最大 15 文字 54

Slide 55

Slide 55 text

Twitter の仕様的には… 省略 https://support.twitter.com/articles/249172 最大 15 文字 のはずなのですが・・・ 55

Slide 56

Slide 56 text

実際は 56

Slide 57

Slide 57 text

実際は 16 文字ありますね… vittoriopasteris 1234567890123456 57

Slide 58

Slide 58 text

では本当の最大文字数は? https://groups.google.com/forum/#!msg/twitter-development-talk/Fff5M- CqFew/h4aVf0edm7sJ 58

Slide 59

Slide 59 text

では本当の最大文字数は? https://groups.google.com/forum/#!msg/twitter-development-talk/Fff5M- CqFew/h4aVf0edm7sJ 最大 20 文字だった時期があるらしい… 59

Slide 60

Slide 60 text

結論 •screen_name は (現行仕様では最大で 15 文字だけれども) 最大 20 文字まで 許容できるようにしましょう 60

Slide 61

Slide 61 text

4. まとめ 61

Slide 62

Slide 62 text

まとめ 1. アプリケーションの登録に注意する 2. ヌル文字に負けない 3. 絵文字に負けない 4. NFD/NFKD に負けない 5. ユーザが常に在るとは限らない 6. Twitter の screen_name が 最大 15 文字であるはずがない 62

Slide 63

Slide 63 text

ご清聴ありがとう ございました! 63