Archive for the ‘Perl’ Category

CGI.pmを使って、CGIを使っていたが、
GETとPOSTが混在した場合の処理については、
注意が必要だったので、
メモしておきます。

パラメータ
test.cgi?key1=val1とPOSTでkey2=val2が来た場合。

  1.  
  2. use CGI;
  3.  
  4. my $cgi = new CGI;
  5. my $val1;
  6. my $val2;
  7.  
  8. $val1 = $cgi->param(‘key1′);
  9. $val2 = $cgi->param(‘key2′);
  10.  
  11. #↑これだと、val2しか取れない
  12.  
  13. $val1 = $cgi->url_param(‘key1′);
  14. $val2 = $cgi->param(‘key2′);
  15.  
  16. #↑これで取得可能
  17.  
  18.  

GETとPOSTが両方とも存在する場合は、POSTが優先される。
GETの値を取りたい場合は、url_paramで取得可能。

実際、どちらで来るかわからない場合は、こんな風に書くのかなぁ
#同じキー値が届いた場合は、POSTを優先させる

  1.  
  2. use CGI;
  3.  
  4. use $cgi = new CGI;
  5.  
  6. my $val1;
  7. my $val2;
  8.  
  9. $val1 = $cgi->param(‘key1′);
  10. $val2 = $cgi->param(‘key2′);
  11.  
  12. $val1 = $cgi->url_param(‘key1′) if( ! defined($val1) );
  13. $val2 = $cgi->url_param(‘key2′) if( ! defined($val2) );
  14.  
  15.  

CPANに登録されているNet::OpenSSHを使用して、
PerlのスクリプトからSSHで接続してみる。

すでに接続先サーバとキーの交換が終わっている場合

  1.  
  2. use strict;
  3. use Net::OpenSSH;
  4.  
  5. my $host = "xxx.xxx.xxx.xxx";
  6. my $ssh = Net::OpenSSH->new($host);
  7. #エラー処理
  8. die "SSH Connection faild:", $ssh->error if( $ssh->error );
  9.  
  10. my $result = $ssh->capture("コマンド");
  11.  
  12.  

これで、実行結果が$resultに入るようになる。
この場合、SSH側のコマンドでエラーが発生した場合、スクリプトはそのエラーを標準エラー出力に表示する。

次に、エラー出力も取得するやりかた

  1.  
  2. use strict;
  3. use Net::OpenSSH;
  4.  
  5. my $host = "xxx.xxx.xxx.xxx";
  6. my $ssh = Net::OpenSSH->new($host);
  7. #エラー処理
  8. die "SSH Connection faild:", $ssh->error if( $ssh->error );
  9.  
  10. my ($result, $errput) = $ssh->capture2("コマンド");
  11.  
  12.  

capture2メソッドを使用することで、エラー出力も取得でき、
スクリプト内で処理可能となる。

非常に便利なライブラリですね。

データベース向けのテストデータを簡単に作るために、
必要となったので、作ってみた。

  1.  
  2. use strict;
  3. use Time::Local qw( timelocal );
  4.  
  5. #2005年から2012年の間のランダムな日時を作成
  6. #2005年1月1日 00:00:00
  7. my $start_date = timelocal( 0, 0, 0, 1, 0, 105 );
  8. #2012年12月31日 23:59:59
  9. my $end_date = timelocal( 59,59,23,31,11,112 );
  10.  
  11. #$start_dateと$end_dateにはエポック秒数が入っている
  12.  
  13. for( 1..2000 ){
  14.     #ランダムな日付を取得
  15.     my $time = $start_date + int( rand( $end_date - $start_date ) );
  16.     #日付の形式に戻す
  17.     my ( $sec, $min, $hour, $mday, $month, $year, $isdst ) = localtime( $time );
  18.    
  19.     #日付の補正
  20.     $year += 1900;
  21.     $month++;
  22.    
  23.     #文字列整形
  24.     my $date_str = spirntf( "%d-%02d-%02d %02d:%02d:%02d",
  25.                             $year, $month, $mday, $hour, $min, $sec );
  26.  
  27.     print "$date_str\n";
  28. }
  29.  

ちょっと値を書き換えれば、ランダムな日時を取得することができる

以前書いた「LWP::UserAgentを使ってHTTPアクセス」
では、Webに公開されているコンテンツにアクセスするためのもの。

今回は、そのURLが正常、転送される、存在しない、エラーなのかを
判断が必要な場合に使用するためのもの。

LWP::UserAgentで普通に書くとHTTPレスポンスが転送の場合、
自動的に転送してくれて、実際のコンテンツにありつけることができる。

ただ、転送してほしくないケースもあるかと思う。
例えば、画像ファイルが存在しない場合に、ブラウザで見ると、
画像が置き換わっているように見え、存在しないことは分かるが、
それは人の目で判断しているのであって、プログラムは判断していない。

そこで、今回はそのURLが正常なのかどうかを判断するものを
作ったので、メモ。

HTTPレスポンスコードについては、
Studying HTTPを参照させていただいた。

  1.  
  2. use LWP::UserAgent;
  3.  
  4. sub check_http_status{
  5.   my $url = shift;
  6.  
  7.   my $ret;
  8.  
  9.   my $ua = LWP::UserAgent->new;
  10.   #タイムアウトの設定
  11.   $ua->timeout(10);
  12.  
  13.   #エージェントの設定
  14.   $ua->agent();
  15.  
  16.   #リクエストの作成
  17.   my $req = HTTP::Request->new(HEAD => $url);
  18.  
  19.   #リファラーを設定
  20.   $req->referer();
  21.  
  22.   #リクエスト実行
  23.   my $res = $ua->simple_request($req);
  24.  
  25.   #結果判断
  26.   if ($res->is_success) {
  27.     $ret = 1;
  28.   }else{
  29.     $ret = 0;
  30.   }
  31.   #実際のレスポンスコードが欲しい場合は、↓
  32.   print $res->code; #レスポンスコードを表示
  33.   #で取得することができる
  34.  
  35.   return $ret;
  36. }
  37.  
  38.  

ポイントは、simple_requestというメソッドを使うこと。
これを使うことによって、転送レスポンスコードを取得することができる。
#LWP::UserAgentのrequestメソッドは、このsimple_requestメソッドを転送等の場合、
#何回か呼び出しを行っている模様

リクエストで「HEAD」としたのは、コンテンツではなく、URLに対するサーバ側のレスポンスコードが重要だったので、
転送量を抑えるために、HEADとした。

これで、実際のURLが正常(200番代)かどうかが分かるようになった。

新規で起こしたサイトのグーグルのサイトマップを作成したいと思い、
Perlで組んでみた。

CGIのパラーメータが入っているURLの登録を行おうとしたときの注意点があったのでメモ

まず、XMLで書く場合は、CGIのパラメータの&をエスケープする必要がある。
「&」⇒「&」としなくてはならない。
また、日本語(非ASCII文字)に関してもURLエンコードをかける必要がある。

このことに注意しながら、HTML::Templateを使って簡単にクエリを作成、
サイトマップに登録することができた。
#登録したばかりなので、どのくらいでインデックスされるかはわからないんですけど。。。

urlエンコードの掛け方

  1.  
  2. use URI::Escape;
  3.  
  4. my $str = "非ASCII文字列";
  5. my $encoded_str = uri_escape($str);
  6.  

もっぱら、Perlはちょろっとした処理を代用するスクリプトとして
多用している。

単純なものであれば、問題ないのだが、
自分でライブラリを作成したり、あるファイルを読み込んだりとしたいときでかつ
cron等で実行したい場合、実行パスが異なってしまうので、
自作ライブラリの場所とか、ファイルのパスを相対パスで書いていると、
エラーになってしまう可能性が高い。

フルパスに書き換えれば、問題ないのだが、
これは、他の環境へ移動したときには、また書き換えが必要になってしまう。

こんなとき便利なものがあったので、メモ

フォルダ構成が以下のようになっている場合
/sample_script/bin/sample.pl
/lib/sample.pm

普通にコマンドラインから実行する場合で自作ライブラリのパスを通す場合
(binがカレントディレクトリ)

  1.  
  2. use strict;
  3. use lib( ../lib);
  4.  

こんな風になるはずである。

しかし、このスクリプトをcron等で動かそうとすると、カレントディレクトリが変わってしまい、
ライブラリのパスが通らなくなってしまう。

そこで、Find::Binを使用する。
Find::Binを使用することによって、実行ファイルのパスが取得できる。

  1.  
  2. use strict;
  3. use Find::Bin;
  4. use lib ( "$Find::Bin/../lib");
  5.  

これで、どの環境に持っていっても、フォルダ構成さえ変えなければ、
特に書き換えが必要がなくなった。

Perlの組み込み関数の一覧を取得する場合、
次のワンライナーを実行すればよい。
便利すぎる

  1.  
  2. perl -MPod::Functions -le ‘print for sort keys %Type’
  3.  

以下のサイトを参考にさせていただきました。

Perlの組み込み関数をワンライナーで取得する

Perlのスクリプトを書いていると、あるサイトのページを取得して、 文字列処理を行いたい場合がある。 そんなときに使えるのが、LWP::UserAgent。 使い方は単純

  1.  
  2. #!/usr/bin/perl
  3.  
  4. use strict;
  5. use LWP::UserAgent;
  6.  
  7. my $url = "http://www.google.co.jp/"
  8.  
  9. my $ua = LWP::UserAgent->new;
  10. HTTP::Request->new(GET => $url);
  11. my $res = $ua->request($req);
  12.  
  13. print $res->content; #取得したHTMLの情報取得
  14.  
  15.  

なお、プロキシを通して行う場合は、

  1.  
  2. #!/usr/bin/perl
  3.  
  4. use strict;
  5. use LWP::UserAgent;
  6.  
  7. my $url = "http://www.google.co.jp/"
  8.  
  9. my $ua = LWP::UserAgent->new;
  10. my $ua->proxy(‘プロトコル’, ‘プロキシサーバのURL’);
  11. HTTP::Request->new(GET => $url);
  12. my $res = $ua->request($req);
  13.  
  14. print $res->content; #取得したHTMLの情報取得
  15.  
  16.  

10進の数値を16進の文字列に変更する方法

  1.  
  2. my $a = 255;
  3. $a = sprintf("%X", $a );
  4. #$a は "FF"になる
  5.  
  6. #0埋めしたい場合
  7. my $b = 10;
  8. $b = sprintf("%02X", $b );
  9.  
  10. #小文字にしたい場合
  11. my $c = 255;
  12. $c = sprintf("%x", $c );
  13.  
  14.  

FireFoxのアドオンのSeleniumIDEを使用して
動作を記録し、そのテストコードをPerlで書き出せる機能がある。

そのPerlのテストコードを動かしてみたときのメモ

まず、そのまま書き出されるPerlのテストスクリプト

  1. use strict;
  2. use warnings;
  3. use Time::HiRes qw(sleep);
  4. use Test::WWW::Selenium;
  5. use Test::More "no_plan";
  6. use Test::Exception;
  7.  
  8. my $sel = Test::WWW::Selenium->new( host => "localhost",
  9.                                     port => 4444,
  10.                                     browser => "*chrome",
  11.                                     browser_url => "http://www.google.co.jp/" );
  12.  
  13. $sel->click_ok("link=28");
  14. $sel->wait_for_page_to_load_ok("30000");
  15. $sel->open_ok("/search?hl=ja&source=hp&q=DZ%E7%A9%BA%E9%96%93&aq=f&aqi=g1&aql=&oq=&gs_rfai=");
  16. WAIT: {
  17.     for (1..60) {
  18.         if (eval { "" eq join(‘,’, $sel->get_all_links()) }) { pass; last WAIT }
  19.         sleep(1);
  20.     }
  21.     fail("timeout");
  22. }
  23. $sel->click_ok("link=NSView » DZ空間");

動かしてみたが、当然モジュールがなくて動かない。

動かすための手順

1,モジュールのインストール

use句に書かれているモジュールのインストールを

CPAN経由で行う。

2.Selenium RCをダウンロード

こちらからSelenium RCをダウンロード

(2010年5月28日現在、バージョン1.0.3)

3.ダウンロードしたSelnium RCを展開

ダウンロードしたフォルダ/selenium-remote-control-1.0.3/selenium-server-1.0.3/selenium-server.jarを起動

#/usr/bin/などに上記jarファイルをmoveしても良い

起動する際は、Terminalで以下のコマンドを実行

java -jar selenium-server.jar

4.Perlのテストスクリプトを編集

今回はほとんど変えずに行った

  1. use strict;
  2. use warnings;
  3. use Time::HiRes qw(sleep);
  4. use Test::WWW::Selenium;
  5. use Test::More "no_plan";
  6. use Test::Exception;
  7.  
  8. my $sel = Test::WWW::Selenium->new( host => "localhost",
  9.                                     port => 4444,
  10.                                     browser => "*firefox",
  11.                                     browser_url => "http://www.google.co.jp/" );
  12.  
  13. $sel->click_ok("link=28");
  14. $sel->wait_for_page_to_load_ok("30000");
  15. $sel->open_ok("/search?hl=ja&source=hp&q=DZ%E7%A9%BA%E9%96%93&aq=f&aqi=g1&aql=&oq=&gs_rfai=");
  16. WAIT: {
  17.     for (1..60) {
  18.         if (eval { "" eq join(‘,’, $sel->get_all_links()) }) { pass; last WAIT }
  19.         sleep(1);
  20.     }
  21.     fail("timeout");
  22. }
  23. $sel->click_ok("link=NSView » DZ空間");

5.テストスクリプトを実行

別ターミナル画面からperlを実行

すると、firefoxが自動的に立ち上がり、処理を行ってくれる。

【おまけ】

会社や学校などでは、プロキシ経由しないといけない場合がある。

firefoxには、profileによって設定を変更することができるので、

profileを指定してfirefoxを自動化する方法は以下の通りである

selenium-serverを起動する際に、以下のコマンドにすることによって

プロファイルを読み込んでFirefoxを立ち上げてくれる(testというプロファイルを使用)

java -jar selenium-server.jar -firefoxProfileTemplate /Users/xxxxx/Library/Application Support/Firefox/Profiles/?????.test/

※1firefoxのプロファイルを作成するには、ターミナルから以下のコマンドを実行することでプロファイルを作成できる

/Applications/Firefox.app/Contens/MacOS/firefox -ProfileManager

※2 作成したプロファイルの保存先は、

~/Library/Application Support/Firefox/Profiles/何か文字列.プロファイル名/

これで、ターミナルからテストを実行することができた。