Twitter APIの開発者登録の追いメール

Twitter APIの開発者登録のやり取りが面倒になったというのが去年くらいの開発者界隈の出来事でした。

qiita.com

最近新たに開発したいモノが出てきたので、登録手続きをしてみました。
相変わらず英語が難しく、それでも何とかコンプリートしてあとは結果待ちとなったのですが、上記のリンクにある「Twitter 社から Twitter API の使用用途についての確認メール」が来てしまい、サスペンド状態になりました。
待っていればそのうち通るかと思ったのですが、いろいろ検索すると半年待ちとか恐ろしい情報まで出てくる始末。
これは何とか対応しなければと取り掛かったものの、このメール、どこかのアドレスにアクセスしてフォームを埋めるとかではなく、質問を呼んで答えをメールに返信するというネイティブ向けみたいなアナログな方法。
普通に読んでもいまいち質問の意図がわからず、Gmailの翻訳を使ってもイマイチ内容が見て取れず、日英翻訳があまり進歩してないことにガッカリしながらも、ガイドになるページを見つけ助かる。

apurixy.moo.jp

とは言うものの、このページを読んでもTwitter社が何をしたいのかイマイチわからず、ところどころで「I do not understand the meaning of the question well, but I think that it is fine as it is」とサンドウィッチマンのような返答をする。

で、Qの下にAを書くようなテキストでプレーンなメールを送ったら1時間後に「審査通ったゾイ」って返事がすぐに来た。

本当に審査が通ったのかロボット避けなのか分からんが、とにかく上手く行ったという話でした。

こういうニュースを見て他人事だと思ってたのだが、どうやら自分も使ってたらしい。

togetter.com

そう言えば、動かなくなってたな、なんでだろう?と思ってたのがまさにこれだった。
何もかも忘れる。

というわけで、別のサービスを探すことにする。
昔のメモを見ると、ずいぶんとYQLカラミで苦労していたようで、代替サービス探しの旅に出たこともあったり、結局諦めて戻ってきた事もあったりしたようだ。
メモは大事だ。

ググって最初に見つかったのがこれ
無料枠には制限があるようだが、個人で使う分には収まりそう。
rss2json.com
ササッとtwitterログインして、使用方法は他のサービスとだいたい似たようなもので、URLとAPIキーとqueryで渡して戻りを受け取るだけ。
ほら簡単でしょと思ったが、どうやら機能的に問題あり。
解釈するRSSのタグが仕様どおりの標準的なもの(title、pubDateとか)だけらしく、拡張タグ(?)みたいなもの、例えば何ていうタグは無視される。
使えないことはないのだが、機能的に大幅な後退になるのでゴミ箱へ。

次に出てきたのがこれ

blog.apitore.com

どうやら平たく言ってAPIを小売りするサービスの中にある店子らしい
apitore.com

使い方としては特に複雑ではなくアカウント取得してAPIキーを使えばいいだけらしい。

で、使ってみたのだが、最初のケースと同じ、RSSのタグ以外は無視される。同じライブラリを使ってるのか、それともそういう仕様が正しいのか。

と、ここまで来て、自分が欲しかったのはRSSJSONに変換するのではなく、XMLJSONに変換するツールだったのだと気づく。

結局はライブラリなどちゃんとしたものは使わず、このJavascriptのfunctionをコピペさせてもらった
https://gist.github.com/chinchang/8106a82c56ad007e27b1

シンプルなソースだったのでいろいろと不安だったのだが、ここでようやく目標は達成された。

xmljsonに変換するwebサービスって需要あるのかなと思った。

GASによるtwitter投稿、1-legedバージョン

この辺の話の続き
miz999.hatenablog.com

ようやく認証画面のないtwitter投稿(いわゆる1-leged)が上手く行ったのでソースに起こしてみる

今まではgistにペタペタ貼ってましたが、管理が面倒なのでgithubに正式ではないがforkしました

github.com

詳細はREADMEで

Google Apps Scriptのjavascriptがスクレイピング言語として優れてる点

スクレイピングとはすなわち、他のサイトからファイルを持ってきて、それに何らかの処理を行うわけで、それを他のjavascriptで行うと、例えばnode.jsだと

function scrape_nantoka(url) {
    return new Promise((resolve, reject) => {
        var client = http.get(url_rank, function (res) {
            var data = ''
            if (res.statusCode === 200) {
                res.setEncoding('binary');
                res.on('data', function (chunk) {
                    data += chunk
                })
                res.on('end', function () {
                    resolve(url)
                })
            }
            else {
                reject();
            }
        })
        client.on('error', function (e) {
            console.log('problem with request: ' + e.message);
        })
    });
}

こんな感じになるわけで(コードは適当)、「データを取ってきて処理する」という作業の都合上、callbackで受けてそこから処理関数を呼ぶか、上記のソースにちょっと入ってるPromiseで受けて、awaitで待つとかなってるわけです。これはプレーンなjavascriptxmlHttpRequestでも同じ構造です。

「await, asyncのおかげで格段に同期処理が便利になった」というのがjavascript界の空気なのですが、あくまでasync配下の処理が同期になるだけで、例えば、5ページ分スクレイピングして、それに対して処理を行うとなると、その5ページ分をawaitしてやることになり、処理はやっぱり複雑になってしまいます。

さらに言えば、仮に並列に走っていい作業(DBにガンガン放り込むとか)だとしても、特定のサイトに対し力いっぱいアクセスすると迷惑あるいは逮捕の可能性もあるわけです。そうならないための作法としてsleepを入れてやるのですが、javascriptにはsleepがありません。で、setTimeoutを使うわけなのだが、そこでもやっぱりコールバック地獄か、await地獄になるわけです。

ここまで話してきて、そもそも論で言えば、javascriptスクレイピングをやるというのは無茶というか根本的に向いてないのです。止めてはいけないブラウザのための言語であるjavascriptであり、参考例として出したnode.jsのソースもそもそも論で言えばサーバサイド言語なわけで、何もかも間違ってるわけです。

そこで、GASの登場になるわけです。 GASの素晴らしいところは、ネットワーク越しのファイル取得関数 UrlFeftchApp.fetch() が同期関数になっているところです。 ちなみに今どきSHIFT-JISとか使ってるサイトのために文字コードを変えたかったら UrlFetchApp.fetch().getContentText("Shift_JIS") とかやります。 この「同期関数が必要」という哲学を感じるのはちゃんとsleep(Utilities.sleep(msec))が用意されてるところです。

正しい使いやすいクライアントサイドのjavascriptとしてgoogleはこのjavascriptを単体でリリースするべきだと思います。 あるいは他の実装系がもっと同期処理を考えるべきだと。

このページは大変に参考になるので必読です。 qiita.com

Google Apps Scriptからtwitter投稿するちょっとした面倒くささ その3

一応目的は達成できたのだが、認証画面の無いOauthをちょっと追ってみる。
やりたいのはこれ
Single user OAuth with examples — Twitter Developers

件のOauthのライブラリの中に .setAccessToken()という関数がある

/**
 * Sets the access token and token secret to use (optional). For use with APIs
 * that support a 1-legged flow where no user interaction is required.
 * @param {string} token The access token.
 * @param {string} secret The token secret.
 * @return {Service_} This service, for chaining.
 */
Service_.prototype.setAccessToken = function(token, secret) {
  this.saveToken_({
    public: token,
    secret: secret,
    type: 'access'
  });
  return this;
};

本来は認証画面で認証したあとに取得したtokenをセットする関数なのだが、コメント読むと'1-legged'と書いてあり、要するにやり取りが一回のパターン(tokenをもらわないパターン)であろう。

で、これでsetAccessToken(AccessToken, AccessTokenSecret)して動かしたが

Invalid or expired token. (code: 89)

が返ってきてしまう。何かがおかしいのか、そもそも間違っているのか。

Single user OAuthできているpython-twitterの方もソースを追ってみるが、結構入り組んだ構造になっていて面倒になった。

というわけで、心が折れたので誰か何かやってくれないだろうか。ライブラリ書いてるGoogleの中の人とか。

Google Apps Scriptからtwitter投稿するちょっとした面倒くささ その2

昨日に続いてGASのTwitter投稿スクリプトをいじっている

くだんの投稿スクリプトを扱ってるページを見ると、使うライブラリのバージョンを12以下に推奨してる。最新の15だと動かないようだ。
これは要するに廃止されたsetProjectKey()という関数を使ってるようで、それを使わないようにするだけである。
元のgistのソースのsetProjectKey()を使っているたった一行をコメントアウトしてもいいのだが、いちおうfork機能があるようなので使ってみる。
これで最新のバージョン15が使えるが、まだ問題がある。
callbackのURLにも使ってる「プロジェクトキー」はサポート終了で、これからは「スクリプトID」を使うようになる。
スクリプトIDはプロジェクトキー同様にプロジェクトのプロパティのページで見れる。
よって、今までtwitterのサイトのコールバックに登録していたURLもプロジェクトキーの部分をスクリプトIDを使うようにする。

https://script.google.com/macros/d/[GASのスクリプトID]/usercallback

それらの修正を入れたのがこちら
https://gist.github.com/miz999/c83b5de622fc510918b4a7c1f4ac45bf


で、バージョン15を使いたかった理由があって、バージョン14でURL encodingに関するバグフィクスが入っている。
バージョン12を使ってるときにこのバグに当たったようで、ツイート文の中に'='があるとそれをセパレータとして処理してしまう。
最新バージョンを入れるとこの障害が無くなる。

Google Apps Scriptからtwitter投稿するちょっとした面倒くささ

今まではpythontwitter投稿してて、いわゆるBOTみたいなものを作ってたのですが、その時の作法としてはtwitterの開発者ページから
ConsumerKey = "”
ConsumerSecret = ""
AccessToken = ""
AccessTokenSecret = ""
を取得して、それをソースに書き込めばOKという感じでした。

ところが今回、GASから同じことをやろうといろいろ調べてそのとおりにやってみると、と認証画面(許可しますか?みたいなアレ)が出ました。

このページのように同じグーグル謹製のライブラリを使っているようです
qiita.com

pythonでやっていた時には出なかったのに何故?」と調べてみると、どうやらAccessTokenらを開発者ページから取得する手法は"Single-user OAuth"と言うらしく、twitter以外ではあまり見ない手法のようです

Single user OAuth with examples — Twitter Developers

なんかOauthの仕組みの中にあるような無いような感じなのですが、Oauthが色々ありすぎるのとOauthがなんか複雑(上記リンクの中でも"By using a single access token, it is not necessary to implement the entire OAuth token acquisition dance."と表現されてるくらい)なので、ぼんやりした理解になりました。

pythonでやってたことをGASでもできないだろうかと、python-twitterのソースや上記のライブラリを見てたのですが、python-twitterの方はOath側のソースも相当追わなければならない感じだし、GASの方はその構造がない感じなので面倒になりました。
GitHub - bear/python-twitter: A Python wrapper around the Twitter API.

そもそも論で言えば、上記のTwitterのSingle-user OAuthのページ
に呼び出し側のサンプルコードはあるのに、どういう認証なのかさっぱりわかりません。

というわけで、GASで認証画面でピコピコやることにしました。

私はOauthが苦手です。できれば関わり合わずに生きていきたいです。