Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Twitter api (partially)_escapes_tweets

2020/11/24 【初心者歓迎】TwitterAPI LT会@オンライン
https://uniquevision.connpass.com/event/193985/

Twitter API はツイートを(一部)エスケープして来る

  • Be the first to comment

  • Be the first to like this

Twitter api (partially)_escapes_tweets

  1. 1. Twitter API はツイートを(一部) エスケープして来る
  2. 2. ツイートの取得 私は UV で Twitter キャンペーンに関わる仕事をよくしています。 #〇〇 というハッシュタグをつけてツイートしてね! とかいうあれ。 また時折、ハッシュタグをつけたツイートの内 XX と一緒にツイートした人にだけ特別な返信をしたい。 あるいは、YY とツイートした人には返信しない。 という需要があったりします。
  3. 3. 取得したツイートのテキストチェック そんな時は、#〇〇 というハッシュタグを含んだツイートを全て取得して 取得した後に、XXやYYといったテキストを含んでいないかチェックします。 ここで面倒な仕様に巻き込まれました。
  4. 4. 実際のコードではないがテスト用にこんなかんじ、(Ruby) require 'oauth' consumer = OAuth::Consumer.new( "YOUR CONSUMER KEY", "YOUR CONSUMER SECRET", site:'https://api.twitter.com/' ) endpoint = OAuth::AccessToken.new( consumer, "YOUR ACCESS TOKEN", "YOUR ACCESS SECRET" )
  5. 5. endpoint はさっき作ったやつ require 'json' search_url = 'https://api.twitter.com/1.1/search/tweets.json' search_res = endpoint.get( search_url + '?' + URI.encode_www_form([ ["q","from:スクリーン名 #20201124_test_tweet"] ]) ) # 最初の1件のツイート内容 p JSON.parse(search_res.body, {:symbolize_names => true})[:statuses].first[:text] # => "#20201124_test_tweet テスト"
  6. 6. なんか変 これだけなら普通。 当時、ツイート内容に「&」が含まれる場合、それが大文字でも小文字でもマッ チングする様にしようとしていました。 API にはハッシュタグをパラメーターとして与えて、回収したツイートのテキス トに正規表現を当てる。 text.match?(/XX & YY/) これがさっぱりマッチしない。
  7. 7. 実体参照っぽい さっきのサンプルコードは「#20201124_test_tweet テスト」とツイートした直 後のもの。 今度は「#20201124_test_tweet black&white」とツイートして試してみます。 「black&white」ですって。 実体参照やないか。 p JSON.parse(search_res.body, {:symbolize_names => true})[:statuses].first[:text] # => "#20201124_test_tweet black&white"
  8. 8. 実体参照 HTMLなどで直接記述できない文字や記号を表記する際に用いられる方法。 そのままHTMLに突っ込むと HTML タグを生成されたりするのでこんな形にエ スケープする。 require "cgi" p CGI.escapeHTML('"<black & white>"') # => "&quot;&lt;black &amp; white&gt;&quot;"
  9. 9. 対象記号は? とりあえず ascii 記号を放り込んでみる。 => !"#$%&'()*+,-./:;<=>?@[¥]^_`{|}~ 目に留まるのは「&amp;」「&lt;」「&gt;」の3つ。 puts JSON.parse(search_res.body, {:symbolize_names => true})[:statuses].first[:text] # => #20201124_test_tweet !"#$%&amp;'()*+,-./:;&lt;=&gt;?@[¥]^_`{|}~
  10. 10. 対象記号は? 最初は HTML エスケープしてるのかな?と思ったけど XML の CharData として処理してると考えるのが1番それっぽい。 require "cgi" str = "!¥"#$%&'()*+,-./:;<=>?@[¥¥]^_`{|}~" puts CGI.escapeHTML(str) # => !&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[¥]^_`{|}~ puts str.encode(xml: :attr) # => "!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[¥]^_`{|}~" puts str.encode(xml: :text) # => !"#$%&amp;'()*+,-./:;&lt;=&gt;?@[¥]^_`{|}~
  11. 11. 検索ではどうなる? どちらでも同じツイートが取得できた。 ・・・? URI.encode_www_form([ ["q","from:スクリーン名 #20201124_test_tweet black&white"] ]) URI.encode_www_form([ ["q","from:スクリーン名 #20201124_test_tweet black&amp;white"] ])
  12. 12. V2 ではどうなっている? > We’re building a new Twitter API with a modern and more sustainable foundation as well as an improved developer experience. とのことなので少しは期待をして試してみよう。 特定のツイートを回収できそうなのは Tweet lookup かな? 詳しい使い方は省略、さっきと同じ様に認証情報4つ組で呼び出してみる。
  13. 13. ダメでした。 url = "https://api.twitter.com/2/tweets" res = endpoint.get( "https://api.twitter.com/2/tweets?ids=1331104166027018241" ) puts JSON.parse(res.body, {:symbolize_names => true})[:data].first[:text] # => #20201124_test_tweet black&amp;white
  14. 14. ちなみに この様な現象は私が確認した限りでは 2007 年ごろからネット上の一部で話題に 上がっている。 いつまで経っても状況が変化しないということは、 1, Twitter としては問題を感じていない 2,問題と思っていても対処できない (すでにDBにこの形で保存してしまっていて過去のツイート全てに対処するのが 困難など) のどちらかではないかと思っていた。
  15. 15. ただ、古い記事では (記事1, 記事2, 記事3) >「<」と「>」のみエスケープされていて、「&」と「"」はされていない と書かれており、今回の結果と食い違う 2016 年ごろの記事では (記事1) >「&」と「<」と「>」(全て半角)がエスケープされている と記載されており、今回の結果に適う。 => 実は状況は変化している・・・? 私は諦めて「&」「<」「>」は扱わないことにした。

×