Seaside Laboratory

Posts

怪盗ロワイヤル用ウィンクツール作成記 (JavaScript 前編)

ページの内容も読まずに適当にクリックする方式だと無理が出てきたので、ちゃんと HTML 読んで解析する方式に変えることにした。

とは言っても、HTML 読むのはそう簡単な話ではなかったりする。Windows アプリケーションだと WinSock を使って HTTP 通信をすることになるが、IP アドレスの処理といった低レベル層のコードを書かなければならずかなり面倒。お手軽な Perl や PHP あたりに逃げたいところだが、一般的な Windows 環境ではスクリプトを実行できないし、GUI の実装には向いていない。仮にこれらの問題が解消されたとしても、ゲーム内の HTML を読むには事前にログインする必要があって、ログイン時の SSL 通信や認証 Cookie の送受信といった面倒な処理を実装しなければならない。今まで何回か簡単な HTTP クライアントや CGI Proxy を作ったことがあるけど、この手の処理をマジメに実装しようとすると意外と大変なことになったりする。

で、色々考えた結果たどり着いたのが JavaScript。Ajax の基幹技術として使われている XMLHttpRequest はブラウザ付属のオブジェクトだけあってかなり強力で、オブジェクトにリクエストをするだけで面倒な通信処理を全てこなしてくれる。しかも HTML を組み合わせて使うので GUI 面もバッチリ。

ということで、前置きが長くなってしまったが今回は JavaScript を使ってウィンクツールを作成することに決定。XMLHttpRequest はクロスドメインの制約で他ドメインとの通信ができないが、IE だとローカル実行時は問題なく動作するので IE 専用とした。

まず、簡単なページの送受信クラスを作成。

function Browse()
{
    this._xhr = new XMLHttpRequest();
    this._userAgent = null;

    /**
     * 連想配列をクエリ文字列に変換
     *
     * @param Object params パラメータ連想配列
     * @return String クエリ文字列
     */
    this.getQueryStringByArray = function(params)
    {
        var pairs = new Array();

        for (var name in params)
        {
            pairs.push(escape(name) + '=' + escape(params[name]));
        }

        return pairs.join('&');
    };

    /**
     * ユーザーエージェントの変更
     *
     * @param String userAgent ユーザーエージェント
     * @return void
     */
    this.setUserAgent = function(userAgent)
    {
        this._userAgent = userAgent;
    };

    /**
     * リクエストの送信
     *
     * @param String method メソッド
     * @param String url URL
     * @param Object params パラメータ連想配列
     * @return String 送信結果
     */
    this.sendRequest = function(method, url, params)
    {
        var body = undefined;

        this._xhr.open(method, url, false);

        // ユーザーエージェントが指定されている場合はリクエストに含める
        if (this._userAgent !== null)
        {
            this._xhr.setRequestHeader('User-Agent', this._userAgent);
        }

        // POST の場合は送信パラメータをセット
        if (method == 'POST')
        {
            // パラメーターを送信するので Content-Type を指定する
            this._xhr.setRequestHeader('Content-Type' , 'application/x-www-form-urlencoded');

            // パラメーターの指定があったか
            if (params !== undefined)
            {
                // 配列を文字に変換
                body = this.getQueryStringByArray(params);
            }
        }

        this._xhr.send(body);

        return this._xhr.responseText;
    };

    /**
     * GET リクエスト
     *
     * @param String url URL
     * @return Object 送信結果
     */
    this.getPage = function(url)
    {
        return this.sendRequest('GET', url);
    };

    /**
     * POST リクエスト
     *
     * @param String url URL
     * @param Object params パラメータ連想配列
     * @return Object 送信結果
     */
    this.postPage = function(url, params)
    {
        return this.sendRequest('POST', url, params);
    };
}

Ajax の場合は open 時に非同期モードを指定をしてレスポンスを高めるのが一般的だけど、今回の場合は逐次処理を行うので同期モードを指定する。

このクラスには最低限の機能は備わっているので、

var browse = new Browse();
browse.getPage('http://example.com/');

というコードを書くだけで簡単にページを取得することができる。

長くなったので後半へ続く。