2008年5月1日木曜日
2008年3月18日火曜日
Ruby: Mechanize GUIDE.txt 日本語訳
追記2014-10-13: ここに最新版をおいた: http://voidptrjp.blogspot.jp/2014/10/mechanize-guide.html
http://mechanize.rubyforge.org/mechanize/ にある GUIDE.txt を訳してみた。
チュートリアルとしてよくできていると思う(原文的な意味で)。
- ルー語っぽい箇所などを、若干修正[2008/3/31]
- 訳微修正。SyntaxHighlighterでコード部分を整理[2010/8/5]
GUIDE.txt
Path: GUIDE.txt Last Update: Tue Dec 04 19:36:28 -0800 2007
WWW::Mechanizeをはじめよう
このガイドは、Mechanize を使い始めるためのものです。このガイドを読み終わるまでに、ページをフェッチしたり、リンクをクリックしたり、フォームをうめてサブミットしたり、Webページ内から必要なデータを取り出したり、、と、お望みのいろいろな便利なことができるようになるとよいです。このガイドは、Mechanize を使ってできることの、表面的なほんとにちょっとしたスクラッチです。だけども、はじめるには十分な情報となるとよいです!
ページをフェッチしよう!
最初のことを最初に。mechanize を require して、新しい mechanizeオブジェクトを生成しましょう:
require 'rubygems' require 'mechanize' agent = WWW::Mechanize.new
さて、ページをフェッチするためのエージェントが使えます。グーグルをエージェントでフェッチしてみよう:
page = agent.get('http://google.com/')
なにがおこった? 我々は mechanize に対して、グーグルのメインページを取ってくるようにたのみました。Mechanize は、任意のセットされたクッキーを格納し、そしてグーグルが送ってきた任意のリダイレクトをたどりました。エージェントは、ページを我々に返しました。このページからデータを取り出したり、クリックするためのリンクを探したり、うめるためのフォームを見つけることができます。
つぎに、クリックするためのいくつかのリンクを探してみましょう。
リンクを見つける
Mechanize は、ページをGETしたり、POSTしたり、またはフォームをSUBMITしたとき、ページ・オブジェクトをひとつ返します。ページがフェッチされたら、エージェントはページをパースして、リンクの一覧表をページ・オブジェクト内に作ります。
それでは、グーグルのホームページをフェッチしたので、すべてのリンクを表示してみよう:
page.links.each do |link| puts link.text end
リンクの一覧を表示できます。だけど、Mechanize はクリックするリンクを見つけるのに役立つ、いくつかショート・カットを用意してます。たとえば、テキストが ‘News’ であるようなリンクをクリックしたい、としましょう。ふつうは、このようにしなければなりません:
page = agent.click page.links.find { |l| l.text == 'News' }
でもMechanize には、ショートカットがあります。上記の代わりに、このようにできるのです:
page = agent.click page.links.text('News')
このショートカットは、「名前が ‘News’ であるような全てのリンクを探せ」という意味です。もしかしたら読者は「そのテキストのリンクは、複数ありうるのに!」と考えているかもしれません。そしてそれは正しい!もしクリック・メソッドに、リンクの一覧を渡した場合、Mechanize は最初のひとつをクリックします。もし二つ目のリンクをクリックしたいのなら、このようにやりましょう:
agent.click page.links.text('News')[1]
適切なリンクを以下のように探すこともできます:
page.links.href('/something')
もしくはそれらを一緒につなげて、適切なテキストと適切なhrefのリンクを探すこともできます:
page.links.text('News').href('/something')
これらのショートカットは、frame, iframe, formのようなものをフェッチしたときの任意のリストに対して、使えます。さて我々はリンクのクリックの仕方を知りました。つぎに、フォームをうめるようなもっと複雑なことをやってみましょう。
フォームをうめる
グーグルの例の続きをやりましょう。以下がコードです:
require 'rubygems' require 'mechanize' agent = WWW::Mechanize.new page = agent.get('http://google.com/')
もしページが表示できれば、ひとつのfという名前のフォームがあり、2組のボタンと2,3のフィールドがあります:
pp page
いまフォームの名前がわかりましたので、ページをフェッチしてみましょう:
google_form = page.form('f')
Mechanize で、フォーム・インプット・フィールドにアクセスする方法はいくつかありますが、一番便利な方法は、オブジェクトのアクセッサを利用する方法です。では、フォーム上の ‘q’ という名前のフォーム・フィールドに、‘ruby mechanize’と入力して見ましょう:
google_form.q = 'ruby mechanize'
値をセットして、フォームを表示し、以下のような行が見えることを確認してください:
#<WWW::Mechanize::Field:0x1403488 @name="q", @value="ruby mechanize">
名前 ‘q’ に対応する値が変わっていた場合は、成功です!つぎにフォームをサブミットしてボタンを押し、結果を見てみましょう:
page = agent.submit(google_form, google_form.buttons.first) pp page
今やったことは、検索フィールドに文字をいれて「検索」ボタンを押したのと同じことです。ボタンなしでフォームをサブミットした場合、テキスト・フィールドに入力してリターン・キーを打ったのと同じです。
コードを全部見てみましょう:
require 'rubygems' require 'mechanize' agent = WWW::Mechanize.new page = agent.get('http://google.com/') google_form = page.form('f') google_form.q = 'ruby mechanize' page = agent.submit(google_form) pp page
ここまでで、スクリーン・スクレーピングをやってみました。フォームについて、もう少し深く見てみましょう。スキップしたくなる前に!
フォーム・テクニック応用編
このセクションでは、フォームで可能な入力フォームで違ったタイプの使用法について、触れたいと思う。パスワードやテキストエリア・フィールドは、テキスト・フィールドと同じように扱われ得る。セレクト・フィールドは、テキスト・フィールドにとても似ているが、関連するオプションがたくさんある。ひとつのオプションを選んだとき、mechanize はそれ以外のオプションを非選択にする (マルチセレクトでなければ!)
たとえばリスト上のひとつのオプションを選択しよう:
form.fields.name('list').options[0].select
今、チェック・ボックスとラジオ・ボタンを見てみよう。チェックボックスを選択するには、ただこのようにすればいい:
form.checkboxes.name('box').check
ラジオ・ボタンは、チェック・ボックスによく似ているが、同じ名前のその他のラジオ・ボタンをアンチェックする方法を知っている。チェック・ボタンと同じように、ラジオ・ボタンをチェックしてみよう:
form.radiobuttons.name('box')[1].check
Mechanize はまた、ファイルのアップロードも簡単にできる!ファイル・アップロード・フィールドを探し、ファイル名を教えてやるのだ:
form.file_uploads.file_name = "somefile.jpg"
データをいじる
Mechanize は、HTMLをパースするために hpricot を使っている。これはなにを意味するか? mechanize で得たページを、hpricotオブジェクトのように扱えるということだ。 Mechanize をデータを取り出したいページのナビゲートに使った後、hpricotのメソッドで取り出せる:
agent.get('http://someurl.com/').search("//p[@class='posted']")
このパワフル・スクレーパに関するさらなる情報については、 HpricotBasics を参照してほしい。
2008年3月16日日曜日
Ruby: OptionParser (optparse.rb) の使い方
2014-05-13追記: 最新の OptionParser の網羅的機能については、「Ruby OptionParser クラスのリファレンス」 を参照してください。
OptionParser: コマンドライン・オプション解析のためのクラス
コマンドライン・オプションを解析するための方法として、従来からGNU の getopt 系のAPIが使われてきた (Getopt,GetoptLong)。Ruby ではこれらに加えて、optparse.rb の OptionParser クラスを利用する方法があるようだ。
ドキュメントは、たとえば http://stdlib.rubyonrails.org/ などに見つけることができる。
ここでこの OptionParser クラスは、従来の getopt 系クラスと使い勝手がだいぶ違うため、使いにくいという意見が散見される。実際、私も使ってみてその感があった。そこで、リファレンス・ドキュメントから主要な機能を抜き出して、使い方をまとめてみた。
OptionParserクラスの主要な機能および記述の方法
OptionParser は、コマンドラインの配列 ARGV を与えられると、その配列を解析しオプションのタイプに応じた処理を行う。ここで、「オプションのタイプに応じた処理」とは、実際には実装者が作りこむものである。
具体的には以下の3点を記述することになる:
- オプションの定義
- 定義されたオプションを指定したときの処理の定義
- ヘルプ・メッセージの定義
以下にサンプルコードを示す。
#! /usr/bin/ruby #filename: test-optparse.rb #author: http://voidptr.seesaa.net #date: Mar. 11th, 2008 #desc: #ref.: http://stdlib.rubyonrails.org # #### require 'optparse'; require 'ostruct'; require 'pp'; #### Option Parse Method. def option_parse( args ) #Prepare. ost = OpenStruct.new; #default option values. # # ost.help = ""; ost.file = ""; ost.kind = ""; ost.logfile = "test.log"; ost.verbose = false; ost.arr = []; # op = OptionParser.new do |opars| opars.banner = "NAME "+" #{$0} [options]"; opars.separator ""; opars.separator ""; #display -h description at tail of the help message. # # #on_headだと、help表示のとき他のオプションとの間に改行される。 #お好みで。 #opars.on_head( "--version", "show the version." ) do opars.on( "--version", "show the version." ) do puts "green 1.0.0"; exit 1; end #オペランドありオプション(基本形; オペランドFILEは、必須) # # opars.on( "-f FILE", "specify a file" ) do |f| ost.file = f; end #オペランドありオプション(基本形+; オペランドKINDは必須で、値は選択式・短縮形も可) #-k a で、-k afterと同じ。-k b で、-k before と同じ意味。 # # opars.on( "-k KIND", [:before, :after], "select a kind {before, after}" ) do |k| ost.kind = k; end #オペランドありオプション(基本形++; オペランドは、省略可) # # # opars.on( "-l [LOGFILE]", "specify the logfile." ) do |l| if ( l != nil ) then ost.logfile = l; end end #フラグタイプのオプション (オプションは長い形式もあり; offの形式も同時に定義) # # opars.on( "-v", "--[no-]verbose", "verbose mode switch." ) do |v| ost.verbose = v; end #フラグタイプのオプション # on_tail で、オプション定義の〆 # opars.on_tail( "-t", "--tasukete", "show this message." ) do puts opars; exit 1; end end #endof do |opars|. #### #オプションなしの場合. # # if ( args == [] ) then #ヘルプを表示。 puts op; exit 1; end # op.parse!( args ); #必須オプションのチェック # # if ( ost.file == "" ) then e = OptionParser::ParseError.new; e.reason = "file was NOT specified (#{ost.file})."; throw e; exit 1; end # ost; end #endof option_parse #### Do. options = option_parse(ARGV) #### Result. pp ARGV; puts ""; pp "Dumper #{options}" puts "name: #{$0}"; ####endof filename: test-optparse.rb
コードについて
OptionParser を newする際に、コード・ブロックを渡している。このコード・ブロック内でオプションの定義、処理、ヘルプメッセージの定義を記述する。
これら3要素は、このコード・ブロック内にすべてまとめて記述することになる —-つまり、ロジックとデータは煮込みすぎたスープのようにどろどろに熔けてしまっている。これは、OptionParserの特徴だ。
一般的には、このようなかたちはプログラミング・ポリシーとしてもオブジェクト指向的にもよろしからざることと思われる。グット・デザイン教会からは破門されるかもしれない。
ただ、ことコマンドライン・オプション処理に限っていえば、この方式はとても楽なのだ; 各オプションとそれらの説明を、一元管理できる。
2008年2月29日金曜日
Ruby: irb, ruby console で日本語入力ができない?
いつのまにか、そうなっていたのでいじってみた。
解決法
Step 1. ナチュラルインプットを無効にする
再起動を促される。
これをおこなうと、なぜか言語バーがデスクトップに表示されなくなった。
また、コンパネの地域と言語のオプション>テキストサービスと入力言語にも、Microsoft Natural Input が消えた。
Step 2. IME使用の設定を行う
IMEのバー(これも言語バー?)が、デスクトップ右下に表示される。
また、irb・ruby console ともに、Alt+漢字で日本語入力可能に。ウマー
解決法
Step 1. ナチュラルインプットを無効にする
(1) コントロールパネル>地域と言語のオプション>テキストサービスと入力言語
で、Natural Input を選択。
(2) プロパティ>詳細設定>「詳細なテキストサービスをオフにする」を、チェック
再起動を促される。
これをおこなうと、なぜか言語バーがデスクトップに表示されなくなった。
また、コンパネの地域と言語のオプション>テキストサービスと入力言語にも、Microsoft Natural Input が消えた。
Step 2. IME使用の設定を行う
IME の詳細設定>システムの構成ペイン内>「詳細なテキストサービスをオフにする」を、チェック
IMEのバー(これも言語バー?)が、デスクトップ右下に表示される。
また、irb・ruby console ともに、Alt+漢字で日本語入力可能に。ウマー
2008年1月29日火曜日
Ruby: 数字に桁区切りを入れたい(その2)
前回 は、数字を区切るためのインスタンス・メソッドを作成した。
今回はこのクラス
Price
に、コンストラクタと比較演算メソッドを、追加しよう。Price.new
の引数として、文字列、または、整数をとるものとする。オープンクラス を使って、クラスに機能を追加した。
class Price
public
include Comparable
#Constructer
#
def initialize( p_ )
@val_orig = p_.to_s;
@val_s_wo_d = del_digit_delimiter( "#{@val_orig}" );
@val_s_w_d = add_digit_delimiter( @val_s_wo_d );
@val_i = @val_s_wo_d.to_i;
end
def <=>(other)
self.val_i <=> other.val_i;
end
end
コンストラクタ:
initialize
では、4種類のインスタンス変数: val_orig
, val_s_wo_d
, val_s_w_d
, val_i
; が生成される。
それぞれ、オリジナルの値、桁区切りなしの値、桁区切りありの値、数値変換時の値、となる。
インスタンス・メソッド:
<=>
は、クラス Price
のオブジェクト同士の大小比較を行うために、定義した[1]。References:
- [1] 『プログラミングRuby 第2版 言語編』; ‘Mixin’, p.101
2008年1月24日木曜日
Ruby: 数字に桁区切りを入れたい (その1)
数字に桁区切りを入れたい。
クラスPriceをつくってみよう。
内部で文字列と数字で値を保存する。
[追記]2013-04-13 3の倍数桁のときに、左端にカンマが付いてしまうため修正: (?=\d)を追加した。
クラスPriceをつくってみよう。
内部で文字列と数字で値を保存する。
class Price
protected
def add_digit_delimiter( v_ )
#remove comma from v_.
v_.gsub(/[,]/){ |c| "" };
#adding commas from lower, each 3-digits.
v_.reverse.gsub(/[[:digit:]]{3}(?=\d)/){|d| "#{d},"}.reverse;
end
[追記]2013-04-13 3の倍数桁のときに、左端にカンマが付いてしまうため修正: (?=\d)を追加した。
def del_digit_delimiter( v_ )これで、メインとなる処理はできた。
v_.gsub(/,/){|d| ""};
end
��
��
2007年12月5日水曜日
Overloading methods in Ruby
Ruby では、メソッドなどのいわゆる多重定義(オーバロード;overload)ができない。
したがって、引数の異なる複数のコンストラクタを持つことも、できないという話。
その回避策は:
[ruby-list:30553] Re: 名前の異なるコンストラクタを複数持つには?
多重定義は、抽象化のひとつの手だとおもうのだが、Rubyのこのような仕様はC++使いからすると、あんまりうれしくない。
したがって、引数の異なる複数のコンストラクタを持つことも、できないという話。
その回避策は:
[ruby-list:30553] Re: 名前の異なるコンストラクタを複数持つには?
多重定義は、抽象化のひとつの手だとおもうのだが、Rubyのこのような仕様はC++使いからすると、あんまりうれしくない。
登録:
投稿 (Atom)