twillはWebブラウジングのための簡単なスクリプト言語です。twillを使ってWebを巡回したり、定型的なWebアクセス操作を自動化することができます。twillは単体で動作することもでき、独自のスクリプト言語twill言語もサポートします。またPythonのためのAPIもサポートしていて、より高度な使い方をしたい場合、PythonからAPIを介してtwillを使うことになると思います。twill言語は現在(2012.1)unicodeのサポートが完全ではなく、twillスクリプト上で日本語を使うことができません。しかし、PythonからAPIを使って呼び出せばこの問題を回避することができます。
インストール
twillの内部構造
twill言語とtwillスクリプト
twill language reference
twillスクリプト
サンプルコードの解析
コメント
データ型
変数
任意の文字列をスクリーンに出力(echo)
指定されたURLに移動(go)
フォームに値を入力(formvalue)
フォームのボタンを押す(submit)
現在のページのHTMLの内容をスクリーンに表示(show)
現在のページをファイルに保存(save_html)
日本語対応
Pyton APIとPythonスクリプトからのwtill制御
twill's Python API
Pythonスクリプトからのtill制御
フォームの情報を調べる
Googleで日本語キーワードを検索
ここでは、twill 0.9 をWindowsにインストールした際の記録をもとに説明します。
twillをインストールする前に、Pythonをインストールしておく必要があります(twillのインストーラがPythonを使うことと、twillがPythonの一部として組み込まれるためです)。実験ではPython 2.7の環境にインストールしました。
twillプロジェクトのホームからダウンロードのリンクを探して配布パッケージをダウンロードします。このインストールを行ったときは0.9のみは配布されていました。http://darcs.idyll.org/~t/projects/twill-0.9.tar.gzからtwill-0.9.tar.gzをダウンロードしました。
ダウンロードしたファイル(tar.gz)を解凍します。
twillのインストールにはいくつかの方法があります。推奨される方法は、Pythonにeasy_installを組み込んで、easy_installを使ってtwillをインストールする方法ですが、それがどうもうまくいきませんでした(これがうまくいけば配布パッケージをダウンロードする必要はないかもしれません)。そこで、もう一つの方法、配布パッケージに含まれるインストーラsetup.pyを実行しました。これは、Pythonのスクリプトになっていて、以下のように単純にスクリプトとして実行します。
python ez_setup.py
Python 2.7ではこれですんなりとtwillがインストールできました。インストールが成功すれば、Pythonのルートの下のScripts/以下にtwill-sh.exeがインストールされていると思います。このディレクトリ(Python/Scripts)にパスを通しておきます。
Python 3.xではおそらくsetup.pyは使えません。最初、Python 3.2の環境へのインストールを試みたのですが、ez_setup.pyがPython 2用に書かれているためそのままで実行できません。Python 2のスクリプトをPython 3用に書き換えるツール 2to3.py がPythonのルートの下のScript/にあって、これで変換できると思ったのですが、完全に変換することができず、結局Python 2.7に入れ替えることにしました。
twillの実行ファイルはtwill-sh.exeです。インストールに成功して、パスを設定してあれば、以下のようにtwill-shが起動できるはずです。
C:>twill-sh -= Welcome to twill! =- current page: *empty page*>>はtwill-shのプロンプトです。twill-shを終了するには、exitを入力します。
twillの全体的な仕組みを理解することは、twillの理解を深めるために意味のあることだと思います。twill's Python APIの冒頭に、twill内部構造に関する簡単な説明があります。以下のこれを要約し、さらに補足を追加したものです。
twillは本質的にmechanizeパッケージのシェルとして働きます。MechanizeはWebブラウジングのためのモジュールで、Python以外にもPerlやRubyなどにも移植されているようです。twillのすべてのコマンドはcommands.pyに実装されています。そしてPythonの一般的なパーサーpyparsingを使って入力の構文解析を行い、Pythonコマンドに変換します(parse.pyを参照)。インタラクティブなシェル動作と入力行の読み取り(readline)は標準Pythonライブラリのcmdモジュールを介して実装されています。
twillは独自の言語 twill言語をサポートし、それをスクリプトファイル(twillスクリプト)に実装することができます。twillにtwillスクリプトを実行させるには、以下のコマンドを実行します。
twill-sh twill_script
twill_scriptにはtwillスクリプトのファイル名を指定します。
twillのプロジェクトのホームページにtwillスクリプトの簡単なサンプルがあります。ここで紹介されているサンプル、「Example: searching Google and going to the first hit」を解析してみたい思います。
このスクリプトは5行からなる単純なスクリプトですが、以下の処理を実行します。
このスクリプトを実行すると、twillプロジェクトのホームページhttp://twill.idyll.org/が開くはずです。
ソースは以下のようになっています。
setlocal query "twill Python" go http://www.google.com/ fv 1 q $query submit btnI # use the "I'm feeling lucky" button show
1行目は変数queryに値"twill Python"をセットしています。twill言語では値をセットするときは変数名のみを書けば良いのですが、参照するときは変数名の先頭に「$」をつける必要があります。
2行目はブラウジングコマンド go を使ってGoogle(http://www.google.com/)に移動します。
3行目のfvはformvalueコマンドの省略形です。書式は、
formvalue formnum fieldname value
で、formnumで指定されたフォームのfieldnameで指定されたフィールドの値をvalueにセットします。この例ではformnumに1、fieldnameにq、value に$query、つまり"twill Python"が指定されています。formnumとfieldnameがGoogleのページのどこを指しているかはGoogleのページを見なければ特定できませんが、全体のながれから、おそらく検索ボックスと思われます。つまり、この行では検索ボックスにキーワード「twill Python」を入力しています。
4行目のsubmitはボタンをクリックするためのコマンドです。submitは仕様によれば、引数が与えられなければ、前回クリックされたボタンをクリックし、引数が与えられれば、その引数で与えられた位置(n番目)のボタンをクリックするはずで、引数は数値であるはずですが、この例では「btnI」となっています。これは仕様とつじつまが合いませんが、ボタン名を指定することもできるようです。ボタン名の調べ方はフォームの情報を調べるを参照してください。
5行目のshowコマンドは現在のページのHTMLを表示します。
twillスクリプトでは「#」以降はコメントとして無視されます。
twillの言語仕様でデータ型に関する記述は見つかりません。サンプルスクリプトでは文字列を「"」で囲んでいますが、文字列中に空白文字が無ければ必ずしも「"」で囲む必要はないようです。たとえば、以下の例では変数aに"nekoya#という文字列を設定していますが「"」は使っていません。それでもエラーにはならず、echoで正しく表示されます。
setlocal a nekoya echo "a" = $a
変数を使う場合、ローカルとグローバルのいずれかのスコープを選択することができます。ローカル変数のスコープはスクリプトファイル内に限定され、グローバル変数のスコープははスクリプトファイルを超えることができます(グローバル変数については未検証)。 変数の代入に代入演算子はなくはsetglobalまたはsetlocalコマンドを使って代入します。twillでは変数の宣言と定義と代入が一体となっています。
setlocal name value setglobal name value
nameには変数名を、valueには変数の値を指定します。以下は変数への値の代入の例です。
setlocal url "https://books-nekoya.jp/" setglobal year 2012
すでに作った変数に新しい値を代入する場合も、代入演算子がないのでsetlocalやsetglobalを使います。
setglobal year 2011 .. setglobal year 2012
変数を参照する場合は変数名の先頭に「$」を付けます。「$」を付け忘れると、それは文字列として解釈されるようです。
setglobal year 2011 echo "year = "$year
スクリーンに任意の文字列を表示するには、echoコマンドを使います。
echo string
twillの言語仕様では、stringは「表示する文字列」とだけ書かれていますが、ここには文字列を複数指定することができます(つまり文字列のリスト)。さらに、変数の値を参照させることもできます。
setlocal url "https://books-nekoya.jp/" setglobal year 2011 echo "year = " $year ", URL = " $URL
ブラウザを任意のURLに移動させるには、goコマンドを使います。
go urlurlには移動先のURLを指定します。
go "https://books-nekoya.jp/"
指定されたフォームの指定されたフィールドに値を入力すには、formvalueコマンドを使います。コマンド名には省略名fvを使うこともできます。
formvalue formnum fieldname value
formnumにはフォーム番号を指定します。fieldnameにはフィールドの名前を指定します。valueには設定する値を指定します。 これらの引数に何を設定すれば良いか、判断に迷うかもしれません。フォームの情報を調べるに書いたように、 twillのbrowserオブジェクトのshowforms関数を使って、現在のHTMLのフォーム情報を調べることができます。 twillのサンプルスクリプトでは、Googleの検索ボックスにキーワードを入力するために、以下のようなコードを書いています。
fv 1 q "keyword"
フォームのボタンを押すにはsubmitコマンドを使います。
submit [n]
nが指定された場合、n番目のボタンを押します。「n番目」とは詳しい説明がありませんがHTML上での出現順だと思われます。 nを省略すると、前回に押したボタンを押します。
言語仕様で述べられている仕様と、twillのホームページにあるサンプルスクリプトのsubmitの書式はことなっています。submitにはもうひとつ以下の書式があると思われます。
submit btnx
btnxのxにボタン名の先頭の文字を指定することでボタンを特定させます。この仕様があると考える根拠についてはサンプルコードの解析にまとめてあります。
showコマンドはtwillが現在訪れているページのHTMLのソースをスクリーンに表示します。このコマンドは引数を持ちません。
show
save_htmlコマンドはtwillが現在訪れているページのHTMLをファイルに書き出します。
save_html [filename]
filenameが省略されると、現在のURLに書き出します。filenameに相対パスを指定した場合、現在のURLからの相対と解釈されるのではないかと考えています。たとえば、次のスクリプトはAmazonのトップページを開いて、それをローカルに保存するつもりで書いたPythonスクリプトですが、パーミッションの問題で書き込めません。
#coding: UTF-8 from twill.commands import * go("http://www.amazon.co.jp/") save_html("./amazon.html")
ファイル名を次のようにフルパスで指定すると問題は解決されます。
save_html("c:/tmp/amazon.html")
twill言語の現状の仕様では文字列をASCIIとして扱うため、日本語などの文字を扱うことができません。文字コード直接指定するためのエスケープや、数値配列のデータ構造もサポートされないので、twill言語上から日本語を扱うことは現状ではできないと思われます。しかし、Python API経由なら日本語(UTF8)を扱うことができます。日本語対応が必要な処理は、twillスクリプトではなく、PythonスクリプトからAPI経由でtwillを実行する方法をとる必要があります。
Pythonのスクリプトからtwillを使うには2つの方法があります。
最初の方法は、twillのコマンドが実装されているファイルcommands.pyをインポートして、twill言語が使うコマンド関数をPythonから直接使う方法です。以下はその例です。
#coding: UTF-8 from twill.commands import * go("http://www.google.co.jp/?hl=ja&oe=utf8") ustr =u"ねこや書店 古本" fv(1, "q", ustr.encode('utf-8')) submit("btnG") show()
この方法はシンプルで、コマンドもtwill言語のサポートするコマンドに一対一で対応しますので分かりやすいです。上記のサンプルを見て分かるようにコマンドの呼び出しはcommands.py内の関数を呼び出しますので、Pythonの関数呼び出し規約で呼び出す必要があります(引数を()で括ったり、「"」で括ったり)使いにくい面もあります。この方法ではコマンドからの戻り値を取得することができません。
もうひとつの方法は、get_browser関数を使ってブラウザオブジェクトを取得し、ブラウザオブジェクトを使ってtwillを使う方法です。この方法もそれほど面倒ではありませんし、自由度はこの方法の方が高いです。get_browser関数を使うにはget_browserをインポートする必要があります。以下に例を示します。
#coding: UTF-8 from twill import get_browser b = get_browser() from twill.commands import * go("http://www.google.co.jp/?hl=ja&oe=utf8") b.showforms()
すべてのコマンドがブラウザオブジェクト経由で使えるわけではなく、前に説明した方法のようにtwill言語の使う関数も併用する必要があるようです。
ブラウザオブジェクトのshowforms関数を使うと、現在のページのフォームの情報を調べることができます。こうして調べた情報はformvalueコマンドの引数に何を設定すれば良いか決定する際の参考になります。
#coding: UTF-8 from twill import get_browser b = get_browser() from twill.commands import * go("http://www.google.co.jp/?hl=ja&oe=utf8") b.showforms()
twillのプロジェクトのホームページにGoogleで検索する例が紹介されていますが、日本語のキーワードを検索しようとすると少し工夫が必要となります。まず、twillスクリプトでは日本語を扱えないので、PythonからAPIを使って、twillを使う必要があります。Puthonからなら、UTF8もShiftJISも検索ボックスに設定することができますが、これだけでは検索結果のページが文字化けしてしまいます。これを回避する方法をいろいろ試してみましたが、GoogleのURLオプションでエンコーディングを設定するとうまくいくようです。以下に文字化けを解消したスクリプトを示します。
#coding: UTF-8 from twill.commands import * go("http://www.google.co.jp/?hl=ja&oe=utf8") ustr =u"ねこや書店 古本" fv(1, "q", ustr.encode('utf-8')) submit("btnG") show()
この例では、URLオプションで出力エンコード(oe)をutf8に設定した状態で、キーワードをutf-8で設定しています。hl=jaは省略してもいいかもしれません。同じようにURLオプションとつじつまが合えば、ShiftJISでキーワードを設定することもできるかもしれません。