Ruby の Mechanize の wiki のよてい

Mechanize::Form



HTML上にあるフォーム(<form>…</form>)ひとつを表すクラスです。

フォームコントロールへのアクセス
  1. このクラスが提供するメソッドで各種フォームコントロール(入力欄、チェックボックス等)のオブジェクトを探す
  2. 探した入力欄などのオブジェクトのvalueを直接入力や項目選択で適当に変更する
  3. このクラスが提供するメソッドで、このクラスが表現するURLへフォームデータを送信
という流れになります。
コントロール名HTML探すメソッド
1行入力欄<input type="text">#field_with
複数行入力欄<textarea>#field_with
パスワード<input type="password">#field_with
隠しコントロール<input type="hidden">#field_with
ラジオボタン<input type="radio">#radiobutton_with
チェックボックス<input type="checkbox">#checkbox_with
選択メニュー<select>#field_with
送信ボタン<input type="submit">#button_with
リセットボタン<input type="reset">#button_with
イメージボタン<input type="image">#button_with
汎用ボタン<button>#button_with
ファイル送信<input type="file">#file_upload_with
たとえば、
<form name="f1" action="/search">
  <input type="text" name="q">
  <input type="submit" value="送信">
</form>
という HTML 片で表される入力欄に文字列 "Ruby" を入力し、フォームの(1つしかない)送信ボタンを押すには
# name が f1 な <form> を探す
agent.page.form_with(:name => 'f1'){|form|
  # name が q な入力欄を探す
  form.field_with(:name => 'q'){|field|
    field.value = 'Ruby'
  }
  # フォームに submit ボタンがあれば「押」して送信
  form.click_button
}
とします。
HTML のフォームコントロールとサーバに送るデータの対応を自力で読み解ける程度の HTML に関する知識がどうしても必要です。

データの送信

保持するフォームコントロール中で「有効」なものだけを集め、HTML での出現順とは無関係に送信値を作り、#action の URL に HTTPメソッド #method で送信します。
Mechanize はパースした HTML を UTF-8 として扱っているので、入力欄の value などの指定も UTF-8 でなければなりません。
  • HTML パースに用いる Nokogiri の返り値が UTF-8 固定なので Mechanize のメソッドも UTF-8
  • ユーザーが指定するフォームデータ文字列も UTF-8 でなければならない(アップロードファイルを除く)
  • 送信データは #page オブジェクトの Mechanize::Page#encoding に Iconv 経由で名前も値も変換された上で送信
という処理になっています。
送信文字データの中に UTF-8 から Mechanize::Page#encoding へ変換できない文字が含まれていた場合、処理できません。
require 'rubygems'; require 'mechanize'
agent = Mechanize.new{|a| a.user_agent_alias = 'Windows IE 7'}

# meta が charset=Shift_JIS でフォームのあるページの例
agent.get('http://www.google.com/webhp?hl=ja&lr=lang_ja&ie=Shift_JIS&oe=Shift_JIS')
p agent.page.encoding
agent.page.form_with(:name => 'f'){|form|
  # 「はしごだか」盒兇鮓〆
  form.field_with(:name => 'q').value = '盒'
  # 検索結果のページ(はしごだか含む)を正しい文字エンコーディングで再パース(今回無関係)
}.click_button.encoding = 'CP932'
puts agent.page.title
結果(UTF-8のはしごだかはiconvの考える素のShift_JISには含まれないので変換できませんでしたエラー):
"Shift_JIS"
Iconv::IllegalSequence: "\351\253\231\346\251\213"
        from $GEMLIB/mechanize-1.0.0/lib/mechanize/util.rb:34:in `iconv'
変換可能であるエンコーディング名を #page オブジェクトの Mechanize::Page#encoding= で指定してください(送信時の変換に必要なのは #page メソッドの返す Page オブジェクトのエンコーディング情報です)。よくある例として、Windows で使われる Shift_JIS で送信したい場合、拡張文字が含まれるなら CP932(日本語パッチ済み iconv なら Windows-31J も可)になります。
require 'rubygems'; require 'mechanize'
agent = Mechanize.new{|a| a.user_agent_alias = 'Windows IE 7'}

# meta が charset=Shift_JIS でフォームのあるページの例
agent.get('http://www.google.com/webhp?hl=ja&lr=lang_ja&ie=Shift_JIS&oe=Shift_JIS')
p agent.page.encoding
agent.page.form_with(:name => 'f'){|form|
  # 「はしごだか」盒兇鮓〆
  form.field_with(:name => 'q').value = '盒'
  # フォームの送信文字エンコーディングをCP932に
  form.page.encoding = 'CP932'
  # 検索結果のページ(はしごだか含む)を正しい文字エンコーディングで再パース(今回無関係)
}.click_button.encoding = 'CP932'
puts agent.page.title
結果:
"Shift_JIS"
盒 - Google 検索
ユーザーが指定した文字列だけではなく、もともとの HTML の hidden に記述されていた「文字エンコードチェック用文字」などが引っかかることもあります。
なお、あまりない例なのですが、フォーム送信用にencoding=を「使い捨て」ていた場合、それ以降のページ内検索メソッドはうまく動作しません。
agent.get(euc_uri).form('f'){|form|
  form['text'] = '(通称たちざき)'
  # EUC-JPのページからなぜかCP932で送る
  form.page.encoding = 'CP932'
}
# urlのHTMLがCP932として解釈不能な場合はパース結果が利用できない
agent.visited_page(euc_url).title #=> ???
# ので、戻す
agent.visited_page(euc_url).encoding='EUC-JP'
agent.visited_page(euc_url).title #=> "タイトル"


## Yahoo!でのRubyとMechanizeの検索結果にこのwikiが含まれるかをUTF-8で表示してほくほくするスクリプト
require 'rubygems'
require 'mechanize'
# 検索ボックスに入れる語
search_word = 'Ruby Mechanize'
# 検索結果に含まれていて欲しいサイトのてきとうURL
re_my_site = Regexp.new(Regexp.quote('w.livedoor.jp/ruby_mechanize'))

agent = Mechanize.new

# Yahoo!検索にアクセスしてページを取得
agent.get('http://search.yahoo.co.jp/')
# ↑に含まれるフォームから、name = "w" であるフォームをひとつ取り出す
agent.page.form_with(:name => 'w'){|f|
  # <input name=p id=yschsp size=54 ... な検索ボックスのvalueに検索語を設定
  # f.field_with(:name => 'p').value = search_word
  # 最近はめんどいので入力欄限定の Hash 風記法でドンさらに倍
  f['p'] = search_word
  # ラジオボタンとして2つめ(配列1要素目)の「日本語のページのみ」ラジオボタンをチェック
  f.radiobuttons[1].check
  # HTML で submit と指定されているボタンを押して普通にフォームデータを送信し、結果を受け取る
  f.click_button
}

# 検索結果から「<li>の中にあった<a>」を表すNokogiriノードオブジェクトをsearchで探し、
# href 属性の値が re_my_site とマッチするようなものをすべて抽出
hit_urls = agent.page.search('li a').find_all{|e| re_my_site =~ e['href']}
if hit_urls.empty? then
  puts 'no result'
else
  # 「<a>タグを表すNokogiriオブジェクト」のinner_textメソッドはタグで挟まれた文字列
  puts hit_urls.map{|e| "#{e.inner_text}\n#{e['href']}"}.join("\n")
end
結果(UTF-8):
Mechanize - Ruby Mechanize wiki (ja ...
http://w.livedoor.jp/ruby_mechanize/d/Mechanize
Mechanize::Form::Button - Ruby ...
http://w.livedoor.jp/ruby_mechanize/d/Mechanize::Form::Button



フォームを表す Mechanize::Form オブジェクトを生成します。
ユーザーが使用することはありません。
引数 node は Nokogiri から抽出したこのフォームのノードのオブジェクトです。Hash でも動作しなくもないです。
引数 mech は Mechanize オブジェクトです。#click_button などでサーバアクセスする時に使います。
引数 page は このフォームを含んでいた Mechanize::Page オブジェクトです。送信文字列の文字エンコーディングの決定に使用します。

#fields から、指定した名前を持つ入力欄や選択メニューを Hash 風にひとつ抽出し、その現在の値を返します。
該当する入力欄などが無かった場合は nil を返します。
agent.page.form_with(:name => 'f1'){|f|
  # ようは Hash のようにアクセス
  p f['q']
  # 以下と同じ
  p f.field_with(:name => 'q').value
}
引数は #field が受け付けるもので、通常は文字列か正規表現です。
Mechanize::Page#forms_with など、配列を返すメソッドと併用していると「さてこの [] の中には何が入るでしょうか」のようなクイズが可能な状態になるので、使用には注意をしてください。
# なんだこれ
agent.page.form_with(:name => 'f')['q']
agent.page.forms_with(:name => /\Af/)[1]

#fields から、指定した名前を持つ入力欄や選択メニューの値を Hash 風に更新します。
value を返します。
agent.page.form_with(:name => 'f1'){|f|
  # ようは Hash のようにアクセス
  f['q'] = 'Ruby'
  # 以下と同じ
  p f.field_with(:name => 'q').value = 'Ruby'
}
第 1引数の field_name は #field が受け付けるもので、通常は文字列か正規表現です。
該当する入力欄などが無かった場合は、#add_field! でその field_name と value を持つ入力欄が新規に作成されます。field_name 部分が間違っていてもエラーなどは出ません。

このフォームの送信先 URL を文字列で返します。
デフォルトは元の form 要素の action 属性の値です。Mechanize::Util.html_unescape で HTML エスケープがアンエスケープされています。action 属性自体が存在しない不正なフォームに対しては NoMethodError を発生させます。HTML 上で action="" だった場合は空文字列 "" を返しますが、このオブジェクトが Mechanize::Page#forms で作成されたもので、 HTML で action="" だった場合は、空文字列ではなく #page.uri が返ります。
相対 URL もそのまま返ります(送信時に絶対 URL がフォームのあるページの URL から計算されます)。mailto: などは動作せず、実質 http: や https: などの Mechanize が動作可能なスキームの URI に限定されます。
action="" で、page.uri として base 要素の URL が使用されてしまっていているような場合には #action= で再設定してください。

このフォームオブジェクトに field_name という名前と value という値を持つ Mechanize::Form::Field オブジェクトを新規に追加します。
追加の終わった #fields を返します。
擬似的な入力ペアを手動で追加する必要があるときに使います。
button_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::Button 継承オブジェクトを #buttons から探し、最初のものを返します。
# b という名前のボタンを明示的に押して送信
page.form_with(:name => 'f1'){|form|
  ...
  form.click_button(form.button_with(:name => 'b'))
}
動作は #xxxx_with を参照してください。
有効なメソッドと値のペアは Mechanize::Form::Button のメソッドと返り値になります。

このフォームに含まれるボタンを、Mechanize::Form::Button およびそれを継承したボタンクラスのオブジェクトにして配列にして返します。
フォームに該当するボタンが含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
Mechanize::Form::Button で返る
  • <input type="button"> # name は無くてよい
  • <button> # name は無くてよい、ただし <button type="reset"> は Mechanize ではボタンとみなさない
Mechanize::Form::ImageButton で返る
  • <input type="image" name="***"> # name 必須
Mechanize::Form::Submit で返る
  • <input type="submit"> # name は無くてよい
Mechanize::Form::Reset で返る
  • <input type="reset" name="***"> # name 必須
以下の 3種類はこのメソッドの返り値には含まれません。どうしても欲しい場合は #page から Mechanize::Page#parser 経由で HTML ノードを直接探してください。
  • name 属性のない type="image" な input 要素
  • name 属性のない type="reset" な input 要素
  • type="reset" な button 要素
送信ボタンと一般ボタンの2つに限っては、name 属性が無いものも含まれています(普通の #fields での入力欄等は name 必須です)。ボタンは歴史的に無名であることが多いので、特別扱いされています。配列として添え字アクセスをする場合や Mechanize::Form#click_button で先頭のボタンを自動使用するような場合には注意をしてください。
配列要素は必ずしも出現順ではなく、「HTML 上での <input type=buttonかsubmitかreset>」の次に「HTML 上での <button>」の順に格納されています。<button> が無ければ出現順なのですが。
<input type="submit"> の形の送信ボタンだけを出現順に返して欲しい場合は #submits を使用してください。リセットボタンだけを返して欲しい場合は #resets がありますが、Mechanize 1.0.0 時点で利用用途がありません。imagebuttons は Mechanize 1.0.0 時点で存在しません。
条件による抽出は #button_with#buttons_with で行うことができます。

ファイルなどのアップロードに用いられる「参照ボタン」は #file_uploads に含まれています。
ラジオボタンは名称がボタンですが #radiobuttons をどうぞ。
送信ボタンを送信のために押したいだけの場合はわざわざボタンを探すのではなく #click_button のデフォルト値の利用も検討してください。
Mechanize ではリセットボタンを送信データリセットのために押すことはできません(機能が無いので送信ボタンとみなしてそのまま送信されます)。
イメージボタンと似ていますが、<area> を使用するいわゆるクリッカブルマップ(クライアントサイドクリックマップ)は Mechanize::Page#links に含まれています。
buttons_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::Button オブジェクトを #buttons から探し、全てを配列で返します。
動作は #xxxxs_with を、条件については #button_with を参照してください。
checkbox_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::CheckBox オブジェクトを #checkboxes から探し、最初のものを返します。
# <label>  CMで知った </label> な欄をチェック
page.forms[0].checkbox_with(:label => '  CMで知った ').check
# ラベルに「CMで知った」という文字列が含まれている欄をチェック
page.forms[0].checkbox_with(:label => /CMで知った/).check # UTF-8
# value 属性 が 32 なチェックボックス欄からチェックをはずす 
page.forms[0].checkbox_with(:value => '32').uncheck
動作は #xxxx_with を参照してください。
有効なメソッドと値のペアは Mechanize::Form::CheckBox を参照してください。

このフォームに含まれるチェックボックスを Mechanize::Form::CheckBox オブジェクトにして配列で返します。
name 属性は必須です。フォームに name 属性の設定されたチェックボックスが含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="checkbox" name="***">
配列要素は HTML 上での単純な出現順になります。
条件による抽出は #checkbox_with#checkboxes_with で行うことができます。
checkboxes_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::CheckBox オブジェクトを #checkboxes から探し、全てを配列で返します。
動作は #xxxxs_with を、条件については #checkbox_with を参照してください。
click_button(button=buttons.first)

このフォームの現在のデータを、フォームの最初のボタンが押されたものとみなしてフォーム内に指定された形式で送信先に送信し、結果のページを履歴に追加した上で返します。
送信ボタン指定がデフォルトでついてる #submit です。#buttons の最初のボタンが使用されます。送信ボタンがフォーム内に 1つだけという一般的な状況の場合、通常の Web ブラウザの動作とほぼ同様になっています。通常はこのメソッドを使ってください。普通に利用される無名なリセットボタンは押下の対象になりませんが、name のついたリセットボタンが送信ボタンより前に配置されていた場合は誤動作してリセットボタンの name と value を送信してしまいます。
Button オブジェクトを指定することもできます。#submit に直接渡されるので詳細はそちらで。submit とは違い、追加ヘッダを指定することはできません。

#fields から、field_name と一致する名前を持つ入力欄または選択メニューのオブジェクトを全て削除します。
削除後の #fields を返します。
field_name は文字列でなければなりません。
オブジェクト自体を削除してしまうことに注意してください。通常はフォーム部品の value 相当を真にしない(nil等を指定)ことで送信使用回避は充分なはずです。

このフォームデータを送信する際のエンコードに使用すべきエンコーディング形式の名称を文字列で返します。
デフォルトはフォームの enctype 属性の値です。enctype 属性が無かった場合は "application/x-www-form-urlencoded" が返ります。
#submitt の引数の追加ヘッダなどで上書きされない限り、このメソッドの返り値でエンコードされ、このメソッドの返り値が Content-Type: リクエストヘッダに記載されて送信されます。Mechanize 1.0.0 が対応しているエンコーディング形式は "application/x-www-form-urlencoded" と "multipart/form-data" の2つです。
再設定は #enctype= で行いますが、追加ヘッダで修正不可能な「ファイルアップロード欄があるのにenctype属性が誤っててMechanizeが誤動作する」という場合以外は使う機会がないと思われます。
ファイルアップロード時の送信マルチパートデータ内に記述する Content-Type 行は Mechanize::Form::FileUpload#mime_type を参照してください。
field_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::Field オブジェクトを #fields から探し、最初のものを返します。
# name が q な入力欄に 'val' をセット
page.forms[0].field_with(:name => 'q').value = 'val'
# list1 という選択メニューの2項目目をチェック
page.forms[0].field_with(:name => 'list1').options[1].check
動作については #xxxx_with を参照してください。
有効なメソッドと値のペアは Mechanize::Form::FieldMechanize::Form::SelectList のメソッドと返り値になります。

このフォームに含まれる入力欄と隠しフィールド、選択メニューを配列にして返します。
フォームに name 属性の設定された該当要素が含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
Mechanize::Form::Text で返る
  • <input type="text" name="***"> # 一行入力欄
Mechanize::Form::Field で返る
  • <input type="password" name="***"> # 入力がマスクされるパスワード入力欄
  • <input name="***"> # type が無いもの、Mechanizeで対応クラスの無い type のもの
  • <textarea name="***"> # 複数行入力欄
Mechanize::Form::Hidden で返る
  • <input type="hidden" name="***"> # 画面に表示されないもの
Mechanize::Form::Textarea で返る
  • <input type="textarea" name="***"> # 仕様上は存在しないエラー処理
Mechanize::Form::SelectList で返る
  • <select name="***"> # ひとつだけ項目が選択可能なドロップダウンメニュー
Mechanize::Form::MultiSelectList で返る
  • <select multiple name="***"> # Ctrlキー等で複数項目が選択可能なドロップダウンメニュー
どの場合も、要素の name 属性は必須です。name のない入力欄やメニューは生成がキャンセルされ、返り値に一切含まれません。このフォーム内でネストしていた場合であっても、配列が入れ子になるようなことはありません。
条件による抽出は #field_with#fields_with で行うことができます。
なお、配列内のオブジェクトの種類の順番は内部の都合でぐちゃぐちゃになっています。配列としての添え字アクセスではなく、極力 field_with 等で条件抽出するようにしてください。配列要素としてアクセスしたい場合は、それぞれのクラスのオブジェクトだけにアクセスできる #texts#hiddens#textareas をお勧めします。これらは出現順になっています。なお、selectlists は Mechanize 1.0.0 時点では存在しません。
何らかの理由で fields そのものを HTML 上での出現順にどーしても並べたいという場合は sort してください。
require 'rubygems'; require 'mechanize'
html = <<HTML
<html><title>test</title><body><form>
<select name="one"></select> <input type="text" name="two"> <textarea name="three"></textarea>
</form></body></html>
HTML
agent = Mechanize.new
page = Mechanize::Page.new(URI.parse('http://localhost/'), {'content-type'=>'text/html'}, html, '200', agent)
agent.__send__(:add_to_history, page)

p agent.page.forms[0].fields.map{|f| f.name}
p agent.page.forms[0].fields.sort.map{|f| f.name}
結果:
["two", "three", "one"]
["one", "two", "three"]
fields_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::Field 継承オブジェクトを #fields から探し、全てを配列で返します。
動作については #xxxxs_with を参照してください。
有効なメソッドと値のペアは Mechanize::Form::FieldMechanize::Form::MultiSelectListMechanize::Form::SelectList のメソッドと返り値になります。
複数の Field オブジェクトに値を設定したい場合は #set_fields も利用できます。
file_upload_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::FileUpload オブジェクトを #file_uploads から探し、最初のものを返します。
# upload という名前のアップロード欄からローカルの 001.jpg を指定して送信
page.form_with(:name => 'f1'){|form|
  form.file_upload_with(:name => 'upload').file_name = './001.jpg'
  form.click_button
}
動作は #xxxx_with を参照してください。
有効なメソッドと値のペアは Mechanize::Form::FileUpload を参照してください。

このフォームに含まれるファイルアップロード欄を Mechanize::Form::FileUpload オブジェクトにして配列で返します。
name 属性は必須です。フォームに name 属性の設定されたファイルアップロード欄が含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="file">
配列要素は HTML 上での単純な出現順になります。
条件による抽出は #file_upload_with#file_uploads_with で行うことができます。
file_uploads_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::FileUpload オブジェクトを #file_uploads から探し、全てを配列で返します。
動作は #xxxxs_with を、条件については #file_upload_with を参照してください。

このフォームオブジェクトを作成したときに使用した HTML ノードを Nokogiri::HTML::Element 等で返します。
このフォーム自体を表すノードが返ります。中身的には Nokogiri::HTML.parse(このformタグ) です。
他のクラスと揃えるなら本当は node というメソッド名であるべきですが、いろいろあってまだ提供されていません。
Mechanize::Page#form_with では class 属性や id 属性による選択ができないので、この form_node メソッドが利用されます。
# <form id="exform"> なフォームを id 属性の値で抽出
# form_with(:id => 'exform') に該当
form = agent.page.forms.find{|f| f.form_node['id'] == 'exform'}

このフォームに指定した名前の入力欄や選択メニューがあれば真を返します。
#fields に含まれるオブジェクトの Mechanize::Form::Field#name メソッドの返り値と field_name を eql? で文字列比較し、一致したものがひとつでもあれば true を、無ければ false を返します。
引数 field_name は文字列でなければなりません。正規表現を使用したい場合は #field_with に渡して結果をチェックしてください。
fill_login_field(page) if page.field_with(:name => /login/)

このフォームに指定した値の入力欄や選択メニューがあれば真を返します。
#fields に含まれるオブジェクトの Mechanize::Form::Field#value メソッドの返り値と value を eql? で文字列比較し、一致したものがひとつでもあれば true を、無ければ false を返します。
引数 value は文字列でなければなりません。正規表現を使用したい場合は #field_with に渡して結果をチェックしてください。
入力欄の値を変更していた場合は、変更後の値と比較されます。

このフォームに指定した名前の隠し入力欄があれば真を返します。
#hiddens に含まれるオブジェクトの Mechanize::Form::Hidden#name メソッドの返り値と field_name を == で文字列比較し、一致したものがひとつでもあれば true を、無ければ false を返します。
引数は文字列でなければなりません。正規表現を使用したい場合は #field_with に渡して結果をチェックしてください。
#hiddens に含まれない隠し入力欄は探せません。

このフォームに含まれる隠し入力欄を Mechanize::Form::Hidden オブジェクトにして配列で返します。
入力欄の name 属性は必須です。このフォームに name 属性の設定された隠し入力欄が含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="hidden" name="***">
#fields から Mechanize::Form::Hidden クラスのオブジェクトを探して返しています。
残念ながら hidden_with のような条件抽出メソッドはありません。#field_with#fields_with で代用してください。

このフォームが持つ入力欄や選択メニューの名前を入力状態に関わらず全て集め、配列として返します。
#fields に含まれるオブジェクトの Mechanize::Form::Field#name メソッドの返り値を集めて、配列にして返します。
順番は #fields 依存で、HTML 上での出現順をおおむね反映していません。

このフォームの送信時に使用する HTTP メソッドを大文字文字列で返します。
デフォルトは元の form 要素の method 属性の値です。method 属性自体が無かった場合は GET を返し、method="" だった場合はこのメソッドは空文字列 "" を返します(送信には失敗します)。
再設定は #method= から行います。

フォームに含まれる入力欄や選択メニューの値の取得や設定に、名前と同じメソッド名を使うことができます。
agent.page.form_with(:name => 'f').field_with(:name => 'q').value = 'Ruby'
と書く代わりに、入力欄選択と Mechanize::Form::Field#value= メソッド部分を「飛ばし」て、
agent.page.form_with(:name => 'f').q = 'Ruby'
と書けるようにします。ちょうど、#[]= メソッドを利用するところの
agent.page.form_with(:name => 'f')['q'] = 'Ruby'
と同じようなものになります。
一応最短記述なのですが、Ruby 標準の method_missing を利用しているので、このフォームオブジェクトが持っているメソッド名と被る場合は動作しません。
page.forms[0].field_with(:name => 'field').value
のつもりで
page.forms[0].field
と書くと、#field メソッドの呼び出しだと思われてエラーになります。Ruby のメソッド名には - を含むこともできないので、
page.forms[0].field_with(:name => 'field-data').value
のつもりで
page.forms[0].field-data
と書いてもエラーになります。
どうしてもメソッドチェーンの見かけで書きたいというのでなければ、#[]#[]= で Hash のように記述したほうが簡便だと思います。
page.forms[0].field_with(:name => 'field').value
page.forms[0]['field']

page.forms[0].field_with(:name => 'field-data').value
page.forms[0]['field-data']
この場合は field という名前も field-data という名前も問題なく動作しますし、後日「このqメソッドってマニュアルのどこに書いてあるの?」と悩むこともなくなります。

このフォームの名前を文字列で返します。
デフォルトは元の form 要素の name 属性の値です。name 属性が無かった場合は nil を返します。
再設定は #name= から行います。

このフォームが所属する Mechanize::Page オブジェクトを返します。
agent.page.form_with(:name => 'f1'){|form|
  p agent.page == form.page #=> true
}
通常、Form.new の引数で指定されたページと同一オブジェクトが返りますが、手動作成時などで無指定だった場合には nil を返します。
radiobutton_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::RadioButton オブジェクトを #radiobuttons から探し、最初のものを返します。
# <label> 男性</label> なラジオボタンのみ on
page.forms[0].radiobutton_with(:label => ' 男性').check
# ラベルに「男性」という文字列が含まれているラジオボタンのみ on
page.forms[0].radiobutton_with(:label => /男性/).check # UTF-8
# value 属性 が e2 なラジオボタンのみ on
page.forms[0].radiobutton_with(:value => 'e2').check
動作は #xxxx_with を参照してください。
有効なメソッドと値のペアは Mechanize::Form::RadioButton を参照してください。

このフォームに含まれるラジオボタンを Mechanize::Form::RadioButton オブジェクトにして配列で返します。
name 属性は必須です。フォームに name 属性の設定されたラジオボタンが含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="radio" name="***">
チェック用のグループなどは配列上考慮されず、ふつうに出現順に配列要素に追加されますが、チェックを行う際は、この配列の中で排他処理が行われます。
条件による抽出は #radiobutton_with#radiobuttons_with で行うことができます。
radiobuttons_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という引数 pattern を満たす Mechanize::Form::RadioButton オブジェクトを #radiobuttons から探し、全てを配列で返します。
# gender という名前で括られる「ラジオボタングループ」の2個目をチェック
page.forms[0].radiobuttons_with(:name => 'gender')[1].check
動作は #xxxxs_with を、条件については #radiobutton_with を参照してください。
有効なメソッドと値のペアは Mechanize::Form::RadioButton を参照してください。

#fields で扱う入力欄や選択メニューに、値を一度に複数設定します。
引数の name_and_value_hash が返ります。
form[0].field_with(:name => 'name1').value = 'val1'
form[0].field_with(:name => 'name2').value = 'val2'
という2つの入力欄に対する処理を
forms[0].set_fields('name1' => 'val1', 'name2' => 'val2')
と Hash を用いて一発で書くことができます。
name に該当するものは文字列か Symbol で指定します。to_s されているので正規表現は使用できません。name メソッドの返り値以外で検索することはできません。
name に相当する入力欄がフォームに複数含まれていて、先頭の入力欄以外に値をセットしたいという場合は、 index を要素 2の配列か Hash のペアで指定します。
form[0].fields_with(:name => 'name1')[index1].value = 'val1'
form[0].fields_with(:name => 'name2')[index2].value = 'val2'

forms[0].set_fields('name1' => ['val1', index1], 'name2' => ['val2', index2])
forms[0].set_fields('name1' => {index1 => 'val1'}, 'name2' => {index2 => 'val2'})
のどちらかで表現できます。index は #fields_with が返す配列に対するもので、0 から始まります。
submit(button=nil)
submit(button=nil, headers={})

このフォームの現在のデータを、フォーム内に指定された形式で送信先に送信し、結果のページを履歴に追加した上で返します。
引数でボタンを指定されない限り、送信ボタンの名前と値を送ることはありません(通常の Web ブラウザとは違う動作)。これが困る場合は必ず引数に Button を指定するか、最初のボタンつき submit を行う #click_button メソッドを使用してください。
追加ヘッダが必要な場合は第 2引数で指定することもできます。
内部では Mechanize#submit を agent.submit(self, button, headers) な感じで利用しています(agentはMechanize::Page::Form.newでの引数)。引数の button と headers の扱いに関してはそちらを参照してください。

このフォームに指定した名前の送信ボタンがあれば真を返します。
#submits に含まれるオブジェクトの Mechanize::Form::Submit#name メソッドの返り値と button_name を == で文字列比較し、一致したものがひとつでもあれば true を、無ければ false を返します。
引数は文字列でなければなりません。正規表現を使用したい場合は #button_with に渡して結果をチェックしてください。
#submits に含まれないボタンは探せません。

このフォームに含まれる送信ボタンを、Mechanize::Form::Submit オブジェクトにして配列にして返します。
フォームに送信ボタンが含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="submit">
#buttons から Mechanize::Form::Submit クラスのオブジェクトを探して返しています。name 属性がない送信ボタンも含まれます。
残念ながら submit_with のような条件抽出メソッドはありません。#button_with#buttons_with で代用してください。
<button> は <button type="submit"> で送信ボタンとして機能しますが、Mechanize 1.0.0 時点ではこのメソッドでは扱いません。#buttons には含まれるのでそちらを使用してください。

このフォームに指定した名前の一行入力欄があれば真を返します。
#texts に含まれるオブジェクトの Mechanize::Form::Text#name メソッドの返り値と field_name を == で文字列比較し、一致したものがひとつでもあれば true を、無ければ false を返します。
引数は文字列でなければなりません。正規表現を使用したい場合は #field_with に渡して結果をチェックしてください。
#texts に含まれない一行入力欄は探せません。

このフォームに含まれる一行入力欄を Mechanize::Form::Text オブジェクトにして配列で返します。
入力欄の name 属性は必須です。このフォームに name 属性の設定された一行入力欄が含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="text" name="***">
#fields から Mechanize::Form::Text クラスのオブジェクトを探して返しています。
残念ながら text_with のような条件抽出メソッドはありません。#field_with#fields_with で代用してください。

このフォームが持つ入力欄や選択メニューの値を入力状態に関わらず全て集め、配列として返します。
#fields に含まれるオブジェクトの Mechanize::Form::Field#value メソッドの返り値を集めて、配列にして返します。
順番は #fields 依存で、HTML 上での出現順をおおむね反映していません。入力欄の値を変更していた場合は、変更後の値が返ります。
xxxx_with(pattern){|tgt| optional_non_ensure_block}
xxxx_with(name_str){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という条件を満たす Xxxx オブジェクトを #xxxxs から探し、最初のものを返します。
該当がない場合は nil を返します。
おおむね以下と同様のことを行っています。
# 一緒一緒
tgt = form.xxxx_with(:mes => value)
tgt = form.xxxxs.find{|e| value === e.__send__(:mes)}
引数 pattern は条件を表す Hash または文字列 name_str です。name_str の場合は {:name => name_str} という Hash とみなします。
Object#__send__ 経由で処理されるので、send できないようなもの、send の結果が意図に沿わないものは pattern のキーには不適です。フォームコントロールの選択で一般的な id 属性による選択は Mechanize 1.0.0 では行えません。class による選択も行えません。
# Object#id の結果が比較されて悲しいことに
form.field_with(:id => 'firstname')
どうしても id や class で抽出したい場合は、元の配列に対して find をかけてください。
# id でさがす
form.fields.find{|field| field['id'] == 'firstname'}
# class でさがす
form.fields.find{|field| field['class'] == 'cities'}
比較は value の === メソッドが使用されるので、正規表現を Hash の値にすることができます。メソッド返り値は UTF-8 なので、正規表現も UTF-8 にしてください。
# 「送信」という文字列がとにかく含まれているボタン
form.button_with(:value => /送信/) # utf-8
pattern にペアを複数指定した場合、全てを満たすものをひとつ抜き出します(どれかを満たすもの、ではありません)。
ブロックを取った場合、処理結果がまるごとブロックに渡ります。満たすものがない場合でも nil が渡ってしまうので注意してください(たいていエラーで動作しないことでしょう)。ブロックの返り値はメソッドの返り値オブジェクトに同じです。
xxxxs_with(pattern){|tgt| optional_non_ensure_block}

{メソッド名 => 返り値} という条件を満たす xxxx オブジェクトを #xxxxs から探し、全てを配列で返します。
該当がない場合は空の配列 [] を返します。

#xxxx_with の「複数探せる版」です。内部で find ではなく find_all してます。
# だから一緒だってば
tgts = form.xxxxs_with(:mes => value)
tgts = form.xxxxs.find_all{|e| value === e.__send__(:mes)}
pattern にペアを複数指定した場合、全てを満たすもののみを抜き出します(どれかを満たすものとにかく全部、ではありません)。
ブロックを取ることもできますが、配列要素が順に渡るのではなく結果の Array オブジェクトが 1個そのまま渡されます。要素ごとに逐次処理をしたい場合はこのメソッド付属のブロックではなく Array#each のブロックを使用してください。


送信先 URL を返す #action メソッドの返り値を文字列 url_str に変更します。
引数 url_str は URL として有効な文字列を指定します。相対 URL でも構いません。URI オブジェクトはエラーになります。

フォーム送信データに、引数の Button オブジェクトの名前と値を追加します。ユーザーが使用することはありません。
追加指示したボタンの配列を返します。
Mechanize::Form::Button オブジェクトを #click_button などで送信するように指示したときに内部で呼ばれています。データの追加だけで、送信は行いません。

このフォームが持つ送信用データの配列を返します。ユーザーが使用することはありません。 が、(この順番で)配列の配列として返ります。
name と value が UTF-8 ではなく、なおかつ #page にエンコーディングが設定されていた場合、UTF-8 から Mechanize::Page#encoding へ Iconv 経由で変換されたものが返り値の配列に格納されます。Mechanize::Util.from_native_charset を参照してください。
name の存在しないボタンも配列中に追加されていますが、name 相当が nil のペアは実際に送信文字列を作成する際に削除されます。

フォームデータの送信エンコーディング方法を返す #enctype メソッドの返り値を文字列 type に変更します。
引数 type は文字列です。通常は "application/x-www-form-urlencoded" で、ファイルアップロードをするときは "multipart/form-data" になります。これ以外には対応していません。

HTTP 送信メソッドを返す #method メソッドの返り値を文字列 upcase_verb に変更します。
引数 upcase_verb は HTTP 送信メソッドとして有効な大文字文字列を指定します。HTML のフォームから送信ボタンで送信する場合は GET と POST の 2つしか動作しません。PUT 等を行いたい場合は Mechanize#put 等を使用します。

このフォームの名前を返す #name メソッドの返り値を文字列 str に変更します。
引数 str は文字列で指定します。
name を変更すると実際の送信データも影響を受けるので気をつけてください。

このフォームに指定した名前のリセットボタンがあれば真を返します。
#resets に含まれるオブジェクトの Mechanize::Form::Reset#name メソッドの返り値と button_name を == で文字列比較し、一致したものがひとつでもあれば true を、無ければ false を返します。
引数は文字列でなければなりません。正規表現を使用したい場合は #button_with に渡して結果をチェックしてください。
#resets に含まれないボタンは探せません。

このフォームに含まれるリセットボタンを、Mechanize::Form::Reset オブジェクトにして配列にして返します。
フォームに name 属性の設定されたリセットボタンが含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="reset" name="***">
#buttons から Mechanize::Form::Reset クラスのオブジェクトを探して返しています。name 属性のないリセットボタンは buttons に含まれないので、この resets の返り値にも含まれません。
残念ながら reset_with のような条件抽出メソッドはありません。#button_with#buttons_with で代用してください。
Mechanize 1.0.0 時点ではフォームリセットの機能自体がないので、type="reset" としてのボタンの期待される動作を実現する手段がありません。Mechanize::Form#click_button などに渡すと送信ボタンとみなして送信を行います。

実際に GET や POST で送信する文字列をこのフォームの現在のデータから作成して返します。ユーザーが使用することはありません。
通常の GET や POST の場合は Mechanize::Util.build_query_string#build_query の返り値が渡されます。name 相当が nil のもの(name 属性のない送信ボタンなど)はここで弾かれます。
multipart の場合は適切なヘッダつきで実データを送信しようとします。Mechanize::Form::FileUpload を参照してください。

サーバへ渡す内容を確認したい場合は #build_query の配列を確認するか、#log を有効にしてログ出力を確認するかしてください。
なお、送信される文字列のペアは #build_query の配列の順番になっています。今のところラジオボタンのあたりが HTML 上での出現順にあまり沿っていません。サーバによっては自動プログラムからの送信であることをここで検知して弾くかもしれません。

このフォームに指定した名前の複数入力欄があれば真を返します。
#textareas に含まれるオブジェクトの Mechanize::Form::Textarea#name メソッドの返り値と field_name を == で文字列比較し、一致したものがひとつでもあれば true を、無ければ false を返します。
引数は文字列でなければなりません。正規表現を使用したい場合は #field_with に渡して結果をチェックしてください。
#textareas に含まれない複数行入力欄は探せません。

このフォームに含まれる複数行入力欄を Mechanize::Form::Textarea オブジェクトにして配列で返します。
入力欄の name 属性は必須です。このフォームに name 属性の設定された複数行入力欄が含まれていない場合は空の配列 [] を返します。
該当する HTML は以下の通り。
  • <input type="textarea" name="***">
type="textarea" というものは仕様上存在しません が、なぜか特別扱いされており、なおかつ本来の <textarea> には Mechanize 1.0.0 時点では対応していません。
#fields から Mechanize::Form::Textarea クラスのオブジェクトを探して返しています。
残念ながら textarea_with のような条件抽出メソッドはありません。#field_with#fields_with で代用してください。
×

この広告は60日間更新がないwikiに表示されております。

管理人のみ編集できます