AWAKENINGを実現するためのスクリプトの書き方を少しずつ紹介していこう。スクリプト初心者、Windowsユーザーを対象に書く。
require 'net/http' host = 'homepage1.nifty.com' directory = '/kazuf' h = Net::HTTP.new(host, 80) while htmlfile = DATA.gets htmlfile = htmlfile.chomp resp, data = h.get(directory + "/" + htmlfile, nil) data.each { |i| puts i } end __END__ renewal_2001_03.html renewal_2001_04.html renewal_2001_05.html renewal.html
簡単なプログラムです。コピーしてエディタに貼り付けて、例えばgeturl.rbという名前で保存しましょう。次にDOSプロンプト等を起動して、保存したフォルダに移動しましょう。PCをインターネットに繋いで、コマンドラインで次のように実行してみてください。
C:\Ruby> ruby -Ks geturl.rb[enter]
このホームページの更新日記がコンソール上に次々と表示されたはずです。無論、HTMLのままで。
さて、うまくいきましたか。うまくいかない場合、あなたはRubyを使ったことはありますか。エディタやDOSプロンプト、コマンドラインという言葉の意味がわかっていますか。わからない場合はすぐに会議室で質問してください。[6/18/2001]
さて、いよいよ正規表現によるパターンマッチングを使ってHTMLファイルの特定の部分を取り出してみましょう。
require 'net/http' host = 'homepage1.nifty.com' directory = '/kazuf' h = Net::HTTP.new(host, 80) while htmlfile = DATA.gets htmlfile = htmlfile.chomp resp, data = h.get(directory + "/" + htmlfile, nil) data.each do |i| if /<A NAME="[^"]+">([^<]+)<\/A>/ =~ i puts $1 end end end __END__ renewal_2001_03.html renewal_2001_04.html renewal_2001_05.html renewal.html
そろそろこのスクリプトの目的を説明しましょう。最初のスクリプトから変更した緑色の部分はHTMLファイルの、
あなたはRubyの参考書を紐解いて、正規表現の章を読む必要があるかもしれません。わからなければ、会議室で質問をどうぞ。[6/23/2001]
Rubyをまったくご存知でない方のために少しスクリプトを解説しておきましょう。Perl等のスクリプト言語を知っていれば大体の推測は付くと思いますが、Ruby独特の文法もありますし、大昔(失礼!私もその部類です^^;)、BasicやFortranは齧ったことはあるが、スクリプト言語は初めてという方もいらっしゃるかもしれません。
require 'net/http' host = 'homepage1.nifty.com' directory = '/kazuf' h = Net::HTTP.new(host, 80) while htmlfile = DATA.gets htmlfile = htmlfile.chomp resp, data = h.get(directory + "/" + htmlfile, nil) data.each do |i| if /<A NAME="[^"]+">([^<]+)<\/A>/ =~ i puts $1 end end end __END__ renewal_2001_03.html renewal_2001_04.html renewal_2001_05.html renewal.html
このスクリプトは大きく分けて三つの部分に分かれています。その部分を色分けしてみました。
簡単にHTTPプロトコルによるインターネットへのアクセスを提供するNet::HTTPクラスを使用します。require 'net/http'で使えるようになります。Net::HTTPのオブジェクトをまず作ります。引数として、URLのホスト名とポート名を入力します。この部分が、
h = Net::HTTP.new(host, 80)
です。実際にgetメソッドを使って、サーバーからの応答とデータを受け取るためには、ディレクトリ名とファイル名を指定する必要があります。この部分が、
resp, data = h.get(directory + "/" + htmlfile, nil)
たったこれだけで、サーバーから戻されるヘッダーはrespに、HTMLデータはdataに配列として格納されます。
while〜endの制御文で、DATAオブジェクト(Perlと同様に__END__以下に記述しているデータを一行ずつ読み出せる)を使って、読み出したいHTMLファイル名を変数のhtmlfileに一つずつ取得していく。chompはPerlと同様に改行コード取り除くメソッドです。
data配列から一つずつデータを読み出すのにはイテレータを使います。変数iにデータが順次読み出されます。if〜end文では変数i(HTMLファイルが一行ずつ取り出される)が正規表現によるパターンにマッチすれば、括弧内に対応する正規表現にマッチする部分だけが出力されます。
これだけの仕事をするプログラムをCで書こうとすれば、おそらく数百行も書くことになるでしょう。あなたもそろそろ腕がむずがゆくなってきたのではないでしょうか。是非AWKINGプロジェクトに参加されて、インターネットを自由自在に使いこなしましょう(^^)v[6/24/2001]
更新日記インデックスを作成するスクリプトを簡単にするために更新日記のファイル名の付け方、カテゴリー別のアンカー名の付け方を工夫しました。自分のホームページを対象にする場合にはこういうズルをすることができます。
require 'net/http' require 'net/ftp' # Setup your configuration. ftpsite = '' ftpaccount = '' ftppassword = '' yourdir = '' genfile = 'renewal_index.html' category = { "rn" => "更新履歴", "cw" => "Cygwin", "ps" => "PS2 Linux", "com" => "コミュニケーション", "ai" => "A.I.", "book" => "蔵書目録", "awking" => "AWKING Project", "awk" => "AWK", "net" => ".net", "os" => "Operating System", "tt" => "立花 隆", "perl" => "Perl", "ruby" => "Ruby", "tcl" => "Tcl/Tk", "python" => "Python" } host = 'homepage1.nifty.com' directory = '/kazuf' anchor = Hash.new() h = Net::HTTP.new(host, 80) h.set_pipe($stderr) if $VERBOSE while htmlfile = DATA.gets htmlfile = htmlfile.chomp puts htmlfile begin resp, data = h.get(directory + "/" + htmlfile, nil) rescue Errno::EINVAL end data.each do |i| if /<A NAME="([^_]+)_(\d+)">([^<]*)(?:<A[^>]+>)*([^<]*)(?:<\/A>)*([^<]+)<\/A>/i =~ i anchor[$1 + ":" + htmlfile + "\#" + $1 + "_" + $2] = "#$3#$4#$5" puts "#$3#$4#$5" end end end f = File.new(genfile, "w") f.print <<HERE1 <HTML> <HEAD> <TITLE>更新日記インデックス</TITLE> <META HTTP-EQUIV="Content-Type" content="text/html; charset=SHIFT_JIS"> <style type="text/css"> <!-- BODY{background:#FFFFF0} .item{font-size:12pt;color:blue;font-weight:bold;text-decoration:underline} //--> </style> </HEAD> <BODY> <IMG SRC="http://homepage1.nifty.com/kazuf/png/tsnetworkc3.png" ALIGN=LEFT HSPACE=20 ALT="tsnetworkc3.png">更新日記インデックス <HR> HERE1 cca = "" count = 0 anchor.keys.sort.each do |k| ca, anc = k.split(/:/) if cca != ca if count > 0 f.print "</UL><BR>\n" end f.print "<div class=\"item\">", category[ca], "</div>\n<UL>\n" cca = ca count = count + 1 end f.print "<LI><A HREF=\"", anc, "\">", anchor[k], "</A>\n" end f.print <<HERE2 </UL><BR> <HR> <I><A HREF="http://homepage1.nifty.com/kazuf/index.html">TS Network ☆ミ</A></I> <FONT COLOR="BLUERED">>></FONT> <ADDRESS><A HREF="mailto:kazuf@mars.dti.ne.jp"><kazuf@mars.dti.ne.jp></A></ADDRESS><BR> </BODY> </HTML> HERE2 f.close ftp = Net::FTP.new(ftpsite, ftpaccount, ftppassword) print "#{ftpsite} に接続しました。\n" print "loginしました。\n" ftp.chdir(yourdir) print "#{yourdir} ディレクトリに移動しました。\n" ftp.puttextfile(genfile, genfile) print "#{genfile} を転送しました。\n" ftp.close print "FTPを終了しました。\n" __END__ renewal_2001_03.html renewal_2001_04.html renewal_2001_05.html renewal.html
更新日記インデックスからカテゴリー別専用ページにリンクするように改造。カテゴリー別アンカー名からカテゴリー別専用ページを取得するハッシュを作成しておいて、専用ページがあるかどうかを判定して、ハイパーリンクをカテゴリー項目に付加する。新しく付加したスクリプト部分は赤く表示した。[10/14/2001]
カテゴリー別アンカータグが一行に二つ以上あると抽出できていなかったので、scanを使うように改造した。わたなべさん、中田さん、サジェスチョンありがとうございました。[10/21/2001]
カテゴリー項目をページの最初にまとめて表示するように改造。[10/21/2001]
require 'net/http' require 'net/ftp' # Setup your configuration. ftpsite = '' ftpaccount = '' ftppassword = '' yourdir = '' genfile = 'renewal_index.html' category = { "rn" => "更新履歴", "cw" => "Cygwin", "ps" => "PS2 Linux", "com" => "コミュニケーション", "ai" => "A.I.", "book" => "蔵書目録", "awking" => "AWKING Project", "awk" => "AWK", "net" => ".net", "os" => "Operating System", "tt" => "立花 隆", "perl" => "Perl", "ruby" => "Ruby", "tcl" => "Tcl/Tk", "python" => "Python", "prolog" => "Prolog", "linux" => "Linux", "printing" => "Printing", "hiroshima" => "ひろしま", "an" => "ArrangeNote", "qnx" => "QNX", "web" => "Web Development", "diary" => "日記", "scheme" => "Scheme", } page = { "cw" => "cygwin.html", "awk" => "awk.html", "awking" => "awking.html", "perl" => "perl.html", "python" => "python.html", "tcl" => "tcltk.html", "ruby" => "ruby.html", "scheme" => "scheme.html", "ps" => "ps2linux.html", } host = 'homepage1.nifty.com' directory = '/kazuf' anchor = Hash.new() h = Net::HTTP.new(host, 80) h.set_pipe($stderr) if $VERBOSE while htmlfile = DATA.gets htmlfile = htmlfile.chomp puts htmlfile begin resp, data = h.get(directory + "/" + htmlfile, nil) rescue Errno::EINVAL end data.each do |i| i.scan(/<A NAME="([^_]+)_(\d+)">([^<]*)(?:<A[^>]+>)*([^<]*)(?:<\/A>)*([^<]*)<\/A>/i){|category_name,num,cont_a,cont_b,cont_c| anchor[category_name + ":" + htmlfile + "\#" + category_name + "_" + num] = cont_a + cont_b + cont_c;puts cont_a + cont_b + cont_c} end end f = File.new(genfile, "w") #print "Content-type: text/html\n\n" f.print <<HERE1 <HTML> <HEAD> <TITLE>更新日記インデックス</TITLE> <META HTTP-EQUIV="Content-Type" content="text/html; charset=SHIFT_JIS"> <style type="text/css"> <!-- BODY{background:#FFFFF0} .item{font-size:12pt;color:blue;font-weight:bold;text-decoration:underline} //--> </style> </HEAD> <BODY> <IMG SRC="http://homepage1.nifty.com/kazuf/png/tsnetworkc3.png" ALIGN=LEFT HSPACE=20 ALT="tsnetworkc3.png">更新日記インデックス <HR> HERE1 f.print "<UL>\n" category.keys.sort.each do |j| f.print "<LI><A HREF=\"renewal_index.html\#", j, "\">", category[j], "</A>\n" end f.print "</UL>\n<HR>\n" cca = "" count = 0 anchor.keys.sort.each do |k| ca, anc = k.split(/:/) if cca != ca if count > 0 f.print "</UL><BR>\n" end if page[ca] f.print "<div class=\"item\"><A NAME=\"", ca, "\"><A HREF=\"", page[ca], "\">", category[ca], "</A></A></div>\n<UL>\n" else f.print "<div class=\"item\"><A NAME=\"", ca, "\">", category[ca], "</A></div>\n<UL>\n" end cca = ca count = count + 1 end f.print "<LI><A HREF=\"", anc, "\">", anchor[k], "</A>\n" end f.print <<HERE2 </UL><BR> <HR> <I><A HREF="http://homepage1.nifty.com/kazuf/index.html">TS Network ☆ミ</A></I> <FONT COLOR="BLUERED">>></FONT> <ADDRESS><A HREF="mailto:kazuf@mars.dti.ne.jp"><kazuf@mars.dti.ne.jp></A></ADDRESS><BR> </BODY> </HTML> HERE2 f.close ftp = Net::FTP.new(ftpsite, ftpaccount, ftppassword) print "#{ftpsite} に接続しました。\n" print "loginしました。\n" ftp.chdir(yourdir) print "#{yourdir} ディレクトリに移動しました。\n" ftp.puttextfile(genfile, genfile) print "#{genfile} を転送しました。\n" ftp.close print "FTPを終了しました。\n" __END__ renewal.html renewal_2001_09.html renewal_2001_08.html renewal_2001_07.html renewal_2001_06.html renewal_2001_05.html renewal_2001_04.html renewal_2001_03.html