ブログのフィードを取得 [フィードとは]

2004年10月

2004年10月 1日

持ち逃げしたい

電話がかかってきた.

「愛知にあります○○なんですが,どうもお世話になります.実はですね,そちらに間違えて7000万円振り込んでしまいまして

いや,豪快すぎだろ,それ.

コメントを投稿

| コメント (2) | 雑記 |

2004年10月 2日

奈良・京都

今日から旅行である.

本当はゆっくり京都だけのつもりだったのだが,出足が遅かったせいで宿を確保できなかったのである.

そこで,近間ということで奈良に宿を取り,ついでにブラブラすることにしたのである.

新幹線にはそこそこ乗っているのだが,考えてみると,ほぼ北陸方面で,新幹線の代名詞とも言える東海道新幹線にはあまり縁がない.

今回は自由席の旅だ.時刻を気にしないで済むので,私は自由席が好きだ.(毎日遅刻しているような人間が時刻を守れるわけがない)驚いたことに東海道新幹線はバカバカ10分毎ぐらいに出ているので本当に何にも考えずに済む.たいへんありがたい.

しかし,席を確保した今,腹が減ってしかたがないのだが,何も売りに来ない.京都までこのままなのか?

ひからびるぞ,おい.

すっかり忘れていたのだが,とったのは旅館.外観がこぎれいなホテル風だったので,違和感なくホテルだと思っていたのだが,部屋はしっかり和室で,久しぶりの畳にそれだけで満足していた.

その日の夕食

でもって,豪勢な和食の夕食!幸せだ~.

ホテル屋上への階段

近くには東大寺があり,ライトアップされるので,テラスから眺めるといいですよ,とのこと.行ってみたら,階段がこんなだ.BGMはジャズ.......和風をねらいたいのか,洋風をねらいたいのか??

コメントを投稿

| コメント (2) | 旅行記 |

2004年10月 3日

鹿の角の意思あるところ

Sousui
鹿の角を切ってるそうだから見に行こうと思ってるんだ.
I君
じゃ,血が――
Sousui
いや,血は出ないだろう?爪切るのといっしょだろ.
I君
違うでしょう.
Sousui
だってだなあ,インコのクチバシ切ってやっても,血,出ないじゃないか.
I君
悪いですけど,昔,鳩が窓にぶつかって落ちたんですけど――
Sousui
死んじゃったの?
I君
はい,血,ダラダラ出てましたよ.クチバシから.
Sousui
いや,それはクチバシから出てたんじゃなくて,根元イッちゃったとか,鼻血だったとか,口から血吐いてたとか――.
I君
そうですかねぇ.
Sousui
そうだって.爪と同じ.
I君
でもですね,爪は根元が伸びるじゃないですか――
Sousui
角は先が伸びるっての?
I君
そうですよ.あれは先の細胞が意思を持って――
Sousui
(笑いころげている)
I君
いや,だって,枝分かれするんですよ,奴ら
Sousui
しかしな,角を切って血だらけになるんだったら観光客に見せないと思うぞ.
I君
そう…です…ね――
Sousui
だろ?
I君
血だらけの角が転がってる――見せませんね.そんな気がしてきました…

春日大社に見に行ったけど,やはり血まみれの行事ではなかったことをここに明記しておく.

コメントを投稿

| 雑記 > よく分からない会話集 |

2004年10月 5日

京都って始発駅じゃないんだよなあ

新幹線,おもいっきり席取れなかったよ.

そもそも,自由席車両が3両しかないことに驚いてはいたんだけど.JRってそんなもんだったっけ.

まあ,2時間ぐらいだからいいや.

コメントを投稿

| コメント (2) | 旅行記 |

2004年10月 6日

ATOKで変換候補に半角数字を出す設定

アラビア数字はたいてい半角で書くことにしているのに,普通の文章に混じった数字はATOKでは全角文字しか出てこなくていらついてたのですが,やっと設定を見つけました.

てっきり「半角全角変換」のところかと思っていたら,「追加する候補」ってところなんだもん.いやぁ,苦労した.

全角半角といえば,私は癖で,空白は半角が標準になるように設定しているんですが,これは多数派なんでしょうかね?

お話を書くときは全角空白が多くなるんだけど,もう,全角空白はShift+Spaceというのが染みついちゃっているので特段設定を変えることはないです.

コメントを投稿

| PC/Web |

2004年10月 7日

23時40分は深夜なのかと思っている時点で問題なのかもしれない

昨晩,そろそろ寝ようかと思っていたら,PCのスピーカーがパタンと倒れた.薄型だし,もともと不安定な場所にあったので,不思議には思っていなかったのだが,直後,揺れが来た.

うわ,結構長い地震やなあとふと見上げると,MDケースとその横に置いている時計が落ちそうになっている.

落ちる~落ちる~と見つめていたら,とうとうMDケースが音を立てて落っこちてきた.

落下地点,枕の横.

危ない,危ない.

コメントを投稿

| コメント (2) | 雑記 |

2004年10月 9日

Apacheアクセスログと私(レンサバのアクセスログはCGIで参照できるのか)

せっかくRubyで遊んでいるので,アクセスログを整形するcgiを作れんもんかと考えた.いや,その前に,さくらインターネットのレンタルサーバーって(スタンダード契約)アクセスログ参照できるのかなあ.

そーゆーわけで,試しのコードを書いてみる.

#!/usr/local/bin/ruby

$SAFE = 1
logfilename = "../../log/access_log_20041009"
logfile = open(logfilename)

print "Content-Type: text/plain; charset=EUC-JP\n\n"

10.times{
  log = logfile.gets
  print log
}
logfile.close

おお,うまくいくじゃないか.

そういや,過去ログの方は圧縮してあるけど,これは展開できんのかな.

え~と,gunzipはあるんか?プログラムはwhichで探すんだっけ.どうも,違和感あるんだよな,このUNIXコマンド.どうしてもwhereと打ちたくなってしまう.

まあ,ともかくだ.usr/bin/gunzipにあることは分かった.が,これ,cgiで動かせるんかな?

ともかく,ファイルを開いているところの2行を以下の通り差し替えてみる.

logfilename = "../../log/access_log_20040908.gz"
logfile = open("|gunzip -c #{logfilename}")

動くやんけ

なんか,意図したことがすんなりいくと,逆にびっくりしてしまうな.ま,なんにせよ,これで,なんかできそうな気がしてきた.

コメントを投稿

| PC/Web > Ruby |

たのしいRuby -Rubyではじめる気軽なプログラミング-

評判がいいので買ってみた.語り口がやさしく,好感をもった.この場合のやさしいは「優しい」の方だ.丁寧なのである.分かりやすく伝えようという気持ちがにじみ出ているように思う.

たのしいRuby 第2版 Rubyではじめる気軽なプログラミング

コメントを投稿

| PC/Web > Ruby |

2004年10月10日

おごり

後輩のIがわざわざ私におごりに来てくれるという.これ幸いと,上野にて合流した.長いこと合っていなかったので,見つけられる自信がなく,あやうく,同じぐらいの年頃の人待ち顔の人に声を掛けそうになったが,自分がそもそも人の顔を見分ける能力に劣ることを思い出してやめておいた.案の定,違う人だった.少ししたら,もっと似た人が現れ,それが本人だった.

無事,合流して,まずは国立科学博物館へ行った.ENIACを見るためである. 今まで見た展示会のたぐいで一番興味深く,おもわずいつもなら買わない目録まで買ってしまった.最後に残った印象が,ゲーム機の方に奪われてしまっていたのは許して欲しい.(懐かしくってさ)

その後,上野公園をうろついてから駅に戻ったのだが,「疲れた」とのこと.すっかり忘れてた――いや,体力ありそうだったので,遠慮しなかった――のだが,私はエスコートをすると,どうも相手を歩かせすぎるらしいのだ.(相手を筋肉痛にさせた覚えがある)

まあ,気を取り直して飲むべく池袋へ.

今回,店の選定は任されていたので,いくつか見当をつけておいたのだ.(おごりだし,払えんようなところだと困るしな)

1店目
入ったとたん,異様な盛り上がり.結婚式の2次会らしき物をしていて,貸し切りだった.

すごすごと引き下がって,別な店へ.

I
今日,なんなんですかね.また結婚式帰りっぽい人が.
Sousui
大安なんじゃないか?
2店目
エレベーターの扉が開いたが,内扉が開かない.手で開けてみると,中は真っ暗だった.
Sousui
なんだ,こりゃ!?店なくなったってことか?
I
そういうことじゃないですか?

おそるおそる,3店目に向かう.

I
3度目の正直って言いますからね.……それとも,2度あることは3度あるですかね?

3度目の正直でした

が.

予約の団体客が必要のない盛り上がりを見せております

Sousui
なんなんだ,今日は.そういう巡り合わせなのか?!

そういう巡り合わせだったんでしょう.

まあ,飯はうまかったです.多謝.

コメントを投稿

| 雑記 |

2004年10月11日

Apacheアクセスログと私(まずは最新のログファイルを得る)

最新のアクセスログを整形して表示することを考える.

まずは,ファイル名の指定である.

さくらインターネットの提供するApacheログファイルは,決められたディレクトリに「access_log_YYYYMMDD」の名前で格納される.YYYYは西暦4桁,MMは月の2桁表示,DDは日の2桁表示である.最新のファイルはこの名前,前の日のファイルは「access_log_YYYYMMDD.gz」と云う形で圧縮されている.

まず,ここで,TimeクラスやDateクラスでYYYYMMDDにする方法が分からず,関数を作るしかないかとあきらめ,以下の通り関数を作った.

#日付をYYYYMMDDの形式の文字列にする関数
def date_fmt(date)
  date_year = date.year.to_s
  date_month = sprintf("%02d", date.month)
  date_day = sprintf("%02d", date.day)
  return date_year + date_month + date_day
end

さて,ログファイルは,毎日5時前後に作成される.つまり,単純に今日の日付からログファイル名を指定すると,ファイルがまだ作成されていない可能性がある.ここでまた,条件設定だの繰り返し方だのですったもんだしたが,最新のログファイル名を得る関数を作る.

#最新のログファイル(圧縮なし)を取得する関数
def lastlog()
  last = Date.today
  last_s = date_fmt(last)
  #今日の日付から初めて,
  #最新のファイルが見つかるまでログファイルの名前を変える
  logfilename = ""
  i = 0
  until FileTest.exist?(logfilename) do
    last_s = date_fmt(last-i)
    logfilename = LOG_DIR + "access_log_" + last_s
    #ファイルが見つからず無限ループに陥るのを防ぐため,
    #10回でやめる
    i += 1
    break if i == 10
  end
  return logfilename
end

なんか,関数をサブルーチンのように使っちゃってるけど,いいのかなあ.メインの方に書くとごちゃごちゃしてきたから分けたんだけど.

定数「LOG_DIR」は,ログファイルの格納ディレクトリの絶対パスで,「/home/[ユーザー名]/log/」という文字列である.

ファイルがなかったときの処理は,普通なら1日引くだけでいいはずなんだけど,何らかの理由で無かったときのために,10回繰り返している.もっとうまい処理方法はないのだろうか?

ここまでやっといてなんだけど,Dir.globで存在するファイル名を特定する方法の方が良かったんじゃなかろうか?

そこで,Dir.globでいろいろとやってみたんだけど,SecurityErrorが出る.う~ん,なんて名前のファイルがあるか分かってしまうような命令はよろしくないってことかなあ.

ともかく,最新ファイルは取得できるようになった.

2004年10月15日追記

最新のログファイル(圧縮なし)を取得する関数は,until文を使うとiを明示的にカウントアップしなければならないのが美しくないなあと思い,forで書き直した.

logfilename = ""
for i in 0..10
  #ファイルが見つからず無限ループに陥るのを防ぐため,10回だけ判定
  last_s = date_fmt(last-i)
  logfilename = LOG_DIR + "access_log_" + last_s
  break if FileTest.exist?(logfilename) #ファイルがあったらループを抜ける
end
コメントを投稿

| PC/Web > Ruby |

Ruby de CGI―Rubyで作るインタラクティブWebサイト

『Ruby de CGI―Rubyで作るインタラクティブWebサイト』

文章がちょっと変.といっても,敬体にしそこなった日本語表現があちこちに出てくるってだけだから,気にならない人は気にならないだろう.あと,HTMLやCSSについての記述,例はツッコム人はツッコムだろうなぁ.

それをおいとけば,サンプルの解説は丁寧です.また,入門書ではあまり見かけない,セキュリティの確保についても解説があって重宝です.

Ruby de CGI―Rubyで作るインタラクティブWebサイト (単行本)

コメントを投稿

| PC/Web > Ruby |

2004年10月12日

Apacheアクセスログと私(ログ1行から各データを得る)

いよいよ整形して,と思い,どう書こうか迷う.アクセスログ1行1行を空白で分割して,それぞれに適当な見出しを付けて表示すればいいだけなんだが,条件判断に使いそうな項目もある.そこで,クラスを作ってみることにした.


#アクセスログクラス

class Accesslog

  def initialize(line)

    @@all = line.chomp.split(/\s/)

    datetime = @@all[3]

    %r|\[(\d+)/(\w+)/(\d+):(\d+):(\d+):(\d+)| =~ datetime

    @@day, @@month, @@year, @@hour, @@minute, @@second = $1, $2, $3, $4, $5, $6

  end

  def ip #IPアドレスを返す

    return @@all[0]

  end

  def year #年を返す

    return @@year

  end

  def month #月を返す(数値)

    return MONTH[@@month.downcase]

  end

  def day #日を返す

    return @@day

  end

  def hour #時を返す

    return @@hour

  end

  def minute #分を返す

    return @@minute

  end

  def second #秒を返す

    return @@second

  end

  def requestURI #呼ばれたURIを返す

    return @@all[6]

  end

  def status #ステータスコードを返す

    return @@all[8]

  end

  def referer #リファラーを返す

    return @@all[10]

  end

  def user_agent #ユーザーエージェントを返す

    i = 11

    ua = ""

    #空白で区切った結果バラバラになったUA名をつなぐ

    while @@all[i]

      ua = ua + " " + @@all[i]

      i += 1

    end

    return ua

  end

end

……あのですね,クラスってこんな風に使うもんなんでしょうか?おかしなことをしている感がものすごくするんですが.ただ,メインの流れで書いとくよりも,どっかにまとめとく方が,万が一ログの形式が変わってもdefの中を書き換えるだけで対応できるなあと思ったんです.

ちなみに,MONTHは,英語の月名を数字にするためのハッシュ定数.こんな具合になってます.


MONTH = {"jan" => 1, "feb" => 2, "mar" => 3, "apr" => 4, "may" => 5, "jun" => 6, "jul" => 7, "aug" => 8, "sep" => 9, "oct" => 10, "nov" => 11, "dec" => 12}

たのしいRuby』に書いてあった物を流用しました.ハッシュって,こんな時に便利なんだなーと飲み込んだ例文でした.

コメントを投稿

| コメント (1) | PC/Web > Ruby |

2004年10月15日

Apacheアクセスログと私(ログを順番に整形出力)

いよいよ,アクセスログを整形する部分を作る.

CGIクラスの使い方が分からなかったり,繰り返しを抜ける条件を間違ったり,例によってすったもんだあったあげく,作ったのがコレ.


logfile = open(lastlog())

ignore = Regexp.new(IGNORE_FILE + "$")

topuri = Regexp.new("^" + URI_SELF)

while logline = logfile.gets

  line = Accesslog.new(logline)

  unless ignore =~ line.requestURI

    print "<dt>Datetime</dt><dd>#{line.year}年#{line.month}月#{line.day}日"

    print "#{line.hour}時#{line.minute}分#{line.second}秒</dd>\n"

    print "<dt>IP Address</dt><dd>#{line.ip}</dd>\n"

    print "<dt>Access URI</dt><dd>#{line.requestURI}</dd>\n"

    print "<dt>Referer</dt><dd>"

    case line.referer

      when topuri

        print "(サイト内)</dd>\n"

      when "-"

        print "(ダイレクトアクセス)</dd>\n"

      else

        print "<a href=\"#{line.referer}\">#{line.referer_unencode}</a></dd>\n"

    end

    print "<dt>User Agent</dt><dd>#{line.user_agent}<hr></dd>\n"

  end

end



logfile.close



footer_out()


header_outは,ヘッダ部分を表示する部分.

以前に考えていたとおり,画像等へのアクセスは省きたかったので,ignoreという正規表現クラスを作って,リクエストされたファイル名の末尾と比べている.IGNORE_FILEは,今のとこ,IGNORE_FILE = "css|jpg|gif|js|mid"こんな感じ.

出力してみたら,refererとuser_agentの文字列が「"」でくくってあったので,Accesslogクラスの初期化部分にちょっと追加.


@all.each{|s|

  s.delete!('"')

}


リファラーの表示は外部からだけの物にしたかったので,caseで場合分けしている.それから,検索文字列をエンコードするべく,Accesslogクラスにreferer_unencodeメソッドを追加.


def referer_unencode #リファラーを返す(アンエンコード済)

  ref = CGI.unescape(@all[10])

  return NKF.nkf("-e", ref)

end

以下がヘッダ表示部.引数にページタイトルをもらって表示する.

#ヘッダー表示関数

def header_out(title)

  cgi = CGI.new("html4") #HTML 4.0 Strict

  print cgi.header("charset" => "euc-jp","language" => "ja")

  print <<EOF

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html lang="ja">

<head>

<meta http-equiv="Content-Style-Type" content="text/css">

<title>#{title}</title>



<link rel="stylesheet" href="#{STYLE_FILE}" type="text/css">

</head>

<body>

<h1>#{title}</h1>

<dl class="log">

EOF

end

CGIクラスの使い方を詳説しているとこ,無いかなあ.いまいち分からんでなあ.

ちなみに,STYLE_FILEは表示をいじるための外部スタイルファイル.私はこのごろ,ほぼ,外部スタイルシートで表示をいじっていない.HTMLコードによけいな物が無くて綺麗だし,ページに統一感を出すのが楽だから.

フッタは以下の通り.


#フッター表示関数

def footer_out

  print <<EOF

</dl>

</body>

</html>

EOF

end

出力結果

(cgiで表示した物を保存して,適当なところで後ろを省略したもの)

検索文字列の変換がうまくいかない.どうも,nkfだとUTF-8は扱えないらしい.今後の課題だなぁ.

コメントを投稿

| PC/Web > Ruby |

2004年10月17日

Apacheアクセスログと私(エラーログを拾う)

アクセスログを眺めていて思ったんだが,ステータスコードでエラーを返している行を拾えば,便利なんじゃないだろうか.特に,404 Not Foundを拾うことができれば,サイト内のリンク切れをつぶすことができる.

そこで,スクリプトを改造,改造.

とりあえず,普通のログを吐くときとエラーログを吐くときに場合分けをするため,引数を取ることにした.ここで,CGIクラスとまた格闘してしまった(やっぱ,例文が欲しいよう).

begin
  cgi = CGI.new
  mode = cgi.params["mode"].to_s #モード取得
  file = lastlog() #最新ファイル取得
  logfile = open(file)
  case mode
    when "view"
      log_view(file) #生ログ表示
    when "error"
      errorlog_view(file) #エラーログ表示
    else
      print "Content-Type: text/plain; charset=EUC-JP\n\n"
      print "有効なモードを取得できません."
  end
rescue StandardError
    error_out()
rescue ScriptError
    error_out()
end

error_out()は,エラーを表示してデバッグしやすくするための物で,『Ruby de CGI―Rubyで作るインタラクティブWebサイト』のものをそのまま持ってきている.

と,場合分けするところは比較的すぐにできたのだが,肝心のエラー表示部でエラく苦労してしまった.そのまま出力しても分かりにくいだろうからとステータスコード順に並べようとしたら,はまったのである.変数にとりあえずエラーの行を保持しようとハッシュのハッシュをいじっていたら,何がどれを指すやら分からなくなった上,型の違いではまった!う~ん,Rubyは型を気にしなくていいのね~と思っていたのが間違いの元でした.なんとか完成させたのが以下のコード.

def errorlog_view(file)
  header_out("エラーログ")
  logfile = open(file)
  error = Hash.new
  error_count = Hash.new
  #エラー行を見つけてとりあえずハッシュに保持
  while logline = logfile.gets
    line = Accesslog.new(logline)
    status = line.status
    if /^[4|5]/ =~ status #ステータスコード400台と500台だけ処理
      unless error.key?(status)
        error[status] = Hash.new
        error_count[status] = 0
      end
      error_count[status] += 1 #ステータスエラーのカウンター
      #ステータスエラーの行を保持
      error[status][error_count[status]] = line
    end
  end
  error.sort.each{|status, value|
    print "<h3>" + status.to_s + " " + STATUS[status] +"</h3>\n"
    print "<ol>"
    error_line = error[status]
    error_line.sort.each{|count, line|
      print "<li><dl class=\"log\">\n"
      print "<dt>Access URI</dt><dd>#{line.requestURI}</dd>\n"
      print "<dt>Datetime</dt><dd>#{line.year}年#{line.month}月#{line.day}日"
      print "#{line.hour}時#{line.minute}分#{line.second}秒</dd>\n"
      print "<dt>IP Address</dt><dd>#{line.ip}</dd>\n"
      print "<dt>Referer</dt><dd>"
      case line.referer
        when "-"
          print "(ダイレクトアクセス)</dd>\n"
        else
          print "<a href=\"#{line.referer}\">#{line.referer_unencode}</a></dd>\n"
      end
      print "<dt>User Agent</dt><dd>#{line.user_agent}</dd>\n"
      print "</dl><hr>\n"
    }
    print "</ol>"
  }
  footer_out()
end

型違いではまったのは,「error[status] = Hash.new」のところ.ハッシュのハッシュを使っているので,ハッシュを入れとかなければいけないのに,""を入れていた.これだと文字列なんだよね…….

lineの保持さえうまくいけば,表示するところは簡単.並べ替えて全部表示する.STATUSという定数はハッシュで,ステータスコードをエラーメッセージにするための物.

#ステータスコードをメッセージにするためのハッシュ定数
STATUS = {"400" => "Bad Request",
          "401" => "Unauthorized",
          "402" => "Payment Required",
          "403" => "Forbidden",
          "404" => "Not Found",
          "405" => "Method Not Allowed",
          "406" => "Not Acceptable",
          "407" => "Proxy Authentication Required",
          "408" => "Request Timeout",
          "409" => "Conflict",
          "410" => "Gone",
          "411" => "Length Required",
          "412" => "Precondition Failed",
          "413" => "Request Entity Too Large",
          "414" => "Request-URI Too Long",
          "415" => "Unsupported Media Type",
          "416" => "Requested Range Not Satisfiable",
          "417" => "Expectation Failed",
          "500" => "Internal Server Error",
          "501" => "Not Implemented",
          "502" => "Bad Gateway",
          "503" => "Service Unavailable",
          "504" => "Gateway Timeout",
          "505" => "HTTP Version Not Supported"
}

400番台と500番台をここで拾うようにしたので,生ログ出力では拾わないことにした.

エラーログの出力結果はこんな感じ.

しまった,robots.txtとか/MSOffice/cltreq.asp~とか/favicon.icoは省いた方がよかったかなぁ.

ちなみに,robots.txtはロボット型検索エンジンのロボットさんが探しに来る物で,行儀のいいロボットならこのファイルの指示にしたがってくれる.MSOfficeなんたらかんたらは,IE+MS Office環境でWebディスカッション機能が有効になっていると探しに来るんだったと記憶する.で,favicon.icoはご存じ,IEなんかのお気に入りで表示されるアイコン.faviconのログは何か遊べそうだなあ.ちょっと調べてみるか.

コメントを投稿

| PC/Web > Ruby |

2004年10月18日

Apacheアクセスログと私(favicon.icoへのアクセスを捕まえてみる)

favicon.icoについて調べていたが,ブラウザによる挙動の違いが定かには分からなかった.少なくとも,IE5系でお気に入りに入れた瞬間にログを残すことがあるらしいというのが分かったぐらい.他のブラウザだと,登録したブックマーク等から飛んだときにアクセスしようとする物もあるようだ.

しょうがないから,とりあえず,見に来たUAごとにカウントすることにした.errorlog_view()でエラー行をハッシュに保存したあとを以下のように変える.

#得られた行を並べ替えて表示
count_robot = Hash.new(0) # robots.txtを探しに来た回数を入れるハッシュ
count_fav = Hash.new(0) # /favicon.icoを探しに来た回数を入れるハッシュ
error.sort.each{|status, value|
  print "<h3>" + status.to_s + " " + STATUS[status] +"</h3>\n"
  print "<ol>\n"
  error_line = error[status]
  error_line.sort.each{|count, line|
    #アクセスされたファイルによって処理を分ける
    request = line.requestURI
    case request
      when %r|^/MSOffice/cltreq.asp|
      when %r|^/_vti_bin/owssvr.dll|
        # /MSOffice/cltreq.asp~ や /_vti_bin/owssvr.dll は無視
      when "/robots.txt"
        count_robot[line.user_agent] += 1
      when "/favicon.ico"
        count_fav[line.user_agent] += 1
      else
        print "<li><dl class=\"log\">\n"
        print "<dt>Access URI</dt><dd>#{request}</dd>\n"
        print "<dt>Datetime</dt><dd>#{line.year}年#{line.month}月#{line.day}日"
        print "#{line.hour}時#{line.minute}分#{line.second}秒</dd>\n"
        print "<dt>IP Address</dt><dd>#{line.ip}</dd>\n"
        print "<dt>Referer</dt><dd>"
        case line.referer
          when "-"
            print "(ダイレクトアクセス)</dd>\n"
          else
            print "<a href=\"#{line.referer}\">#{line.referer_unencode}</a></dd>\n"
        end
        print "<dt>User Agent</dt><dd>#{line.user_agent}</dd>\n"
        print "</dl><hr>\n"
      end
  }
  print "</ol>\n"
}
#ロボットのアクセス回数を表示
print "<h3>robots.txtへのアクセス</h3>\n"
print "<ul>\n"
count_robot.each{|crawler,count|
  print "<li>#{count}回:#{crawler}</li>\n"
}
print "</ul>\n"
#お気に入りアイコンへのアクセス回数を表示
print "<h3>favicon.icoへのアクセス</h3>\n"
print "<ul>\n"
count_fav.each{|ua,count|
  print "<li>#{count}回:#{ua}</li>\n"
}
print "</ul>\n"
#フッタ表示
footer_out()

うわ,びびった~.1度でまともに動いたよ.珍しい.

表示結果はこんな感じ

今度はページ内を遷移する様子を表示する部分を作ろうか.

コメントを投稿

| PC/Web > Ruby |

2004年10月19日

今年は年休消化できないなぁ

課長
会議でまた怒られちゃったよ.お前の課は年休の消化率が悪いって.ちょっと,みんなにメール回して年休とれっていってくんない?
T係長
分かりました.
課長
Oさんとこも,取ってね.
O係長
は,大丈夫です.うちの係は11月頭に代わり番で取る計画です.

O係長,確かそれ,年休じゃなくて,代休の消化……

コメントを投稿

| 雑記 > よく分からない会話集 |

Apacheアクセスログと私(サイト内遷移の様子)

ページ内をどんな風に移動しているか表示することを考える.

欲しいのは,htmlを見に来た記録だから,以前作った生ログ表示と同じ条件で行を省く.その後の行の保持はエラーログ表示と似たような動作だ.1つのファイルの閲覧時間も把握できるといいから,次のファイルへのアクセス時間から前のファイルへのアクセス時間を引いて表示させることとする.

#ページ内遷移表示関数
#IPアドレス順に並び替えて,requestしたファイルを表示する.
def trace_view(file)
  header_out("ページ内遷移")
 
  logfile = open(file)
  ignore = Regexp.new(IGNORE_FILE + "$")
  #必要な行をとりあえずハッシュに保持
  trace = Hash.new
  trace_count = Hash.new
  while logline = logfile.gets
    line = Accesslog.new(logline)
    unless ignore =~ line.requestURI #無視するファイルは処理しない
      #必要行lineをtrace[ip][trace_count[ip]に入れていく.
      save_line(trace, trace_count, line.ip, line)
    end
  end
  #得られた行を並べ替えて表示
  trace.sort.each{|ip, value|
    print "<h3>" + ip + "</h3>\n"
    print "<h4>" + line.user_agent + "</h4>\n"
    print "<ol>\n"
    access_time = Array.new
    trace[ip].sort.each{|count, line|
      access_time[count] = Time.mktime(line.year, line.month, line.day, line.hour, line.minute, line.second)
      unless count == 1
        period = access_time[count] - access_time[count - 1]
        if period >= 60
          minute = period.divmod(60)
          print "<br>\n↓<br>\n↓ " + minute[0].to_i.to_s + "分"
          print minute[1].to_i.to_s + "秒<br>\n↓</li>\n"
        else
          print "<br>\n↓<br>\n↓ " + period.to_s + "秒<br>\n↓</li>\n"
        end
      end
      print "<li>" + line.requestURI
      print "(#{line.month}月#{line.day}日"
      print "#{line.hour}時#{line.minute}分#{line.second}秒)"
    }
    print "</li>\n"
    print "</ol>\n"
  }

  footer_out() #フッタ表示
end

save_lineは新たに作った関数で,引数に4つ取る.これは,前に作ったエラーログ表示部と共通で使う.

#必要行を保持する関数
#第1引数,第2引数はハッシュで,2つ揃ってハッシュのハッシュを作り,
#lineを保持する.
#termは,保存するときのハッシュのキーになる
def save_line(saver, saver_count, term, line)
  unless saver.key?(term)
    saver[term] = Hash.new
    saver_count[term] = 0
  end
  saver_count[term] += 1 #ステータスエラーのカウンター
  #ステータスエラーの行を保持
  saver[term][saver_count[term]] = line
end

表示結果

ありゃ?UserAgentがずれてないか?

表示を自分好みにする段階で,最初にこなければ行けないタグがどれで,くれ返さなければいけないのがどこで――と考えているうちに訳が分からなくなった.……美しくないなあ.

あと,秒数から分+秒の表記にするのがうまいこといっていない.これぐらい,メソッドありそうなんだけど,どんなもんだろ.

それに,ロボットの遷移と人の遷移は処理分けたいよなあ.

コメントを投稿

| PC/Web > Ruby |

2004年10月20日

二転三転

水曜日は定時で帰るよう通達がある.しかし,我が部署は通達破りで悪名をはせていた.

当然,今日もそうなるはずだった.というのは,17時半以降に仕事が入ることが確実だったからである.昼間が,暇で暇で仕方がないのがなお腹立たしい.

しかし,今日は通達の様相からして違った.

「台風の被害に遭わぬよう,即刻帰れ」

「今日は監事が見回ります」

以上の二点を受け,部長が,部署内に内線を掛けまくり,また,会う人会う人に今日は早く帰ってねと言い続ける.

最後通牒に,定時で電気消す宣言.

おかげで,今日やるはずだった仕事を放り出し,時間差出勤のせいで18時15分が定時だというのに,18時には帰路についていた.

まあ,降って沸いた幸運だと思うことにしよう.

珍しく,19時前に帰宅してしまったので,NHKを見たら,おお,今度の台風はすごいんすね.買い物に行きたかったけど,おとなしくしていよう.

コメントを投稿

| 雑記 |

Apacheアクセスログと私(バグ取り)

今日はバグ取り等々をやることにする.

まず,エラー表示部.

エラー表示と言いつつ,robots.txtとかfavicon.icoへのアクセスを表示もすることにしたのだが,「エラーログの保持」→「エラーデータのあるステータスコードを見出しとして出力」→「エラーログの表示(ただし,robots.txtなどの場合は出力せず)」という流れにしていたため,「404 Not Found」と見出しを書いたあと,robots.txtとfavicon.icoしかエラーがない場合,見出しだけ出ているというお間抜けな状態だった.

考えてみれば,処理しないなら,そもそもエラーログを保持する必要もない.だから,リクエストファイルによる場合分けは先にしてしまうことにする.

それから,ハッシュのハッシュにしときながら,2つめのハッシュのキーは1, 2, 3...でしかなく,どう考えても,Arrayでこと足りるなと考えるに,難しく考えすぎたかと思い直し,コードを書き換えてみた.

#エラーログ表示関数
def errorlog_view(file)
  #エラー行を保持するためのハッシュ
  error = Hash.new
  #エラーを表示するかどうかのフラグ.(status => 1 or 0)の形になる.
  flg_error_view = Hash.new(0)
  # /robots.txtを探しに来た回数を入れるハッシュ
  count_robot = Hash.new(0)
  # /favicon.icoを探しに来た回数を入れるハッシュ
  count_fav = Hash.new(0)

  header_out("エラーログ") #ヘッダ表示
  logfile = open(file)
  while logline = logfile.gets
    line = Accesslog.new(logline)
    #アクセスされたファイルによって処理を分ける
    req_file = line.requestURI
    ig_error = Regexp.new("^" + IGNORE_ERROR)
    case req_file
      when "/robots.txt"
        count_robot[line.user_agent] += 1
        next
      when "/favicon.ico"
        count_fav[line.user_agent] += 1
        next
      when ig_error #無視ファイルは何もしない
        next
    end
    status = line.status
    if /^[4|5]/ =~ status #ステータスコード400台と500台だけ処理
      #必要行lineをerror[status]に入れていく.
      #errorはハッシュで,{Key => Array}.
      unless error.key?(status)
        error[status] = Array.new
      end
      #ステータスエラーの行を保持
      error[status] << line
    end
  end
  #得られた行を並べ替えて表示
  error.sort.each{|status, value|
    print "<h3> " + status + " " + STATUS[status] +"</h3> \n"
    print "<ol> \n"
    value.each{|line|
      print "<li> <dl class=\"log\"> \n"
      print "<dt> Access URI</dt> <dd> #{line.requestURI}</dd> \n"
      print "<dt> Datetime</dt> <dd> #{line.year}年#{line.month}月#{line.day}日"
      print "#{line.hour}時#{line.minute}分#{line.second}秒</dd> \n"
      print "<dt> IP Address</dt> <dd> #{line.ip}</dd> \n"
      print "<dt> Referer</dt> <dd> "
      case line.referer
        when "-"
          print "(ダイレクトアクセス)</dd> \n"
        else
          print "<a href=\"#{line.referer}\"> #{line.referer_unencode}</a> </dd> \n"
      end
      print "<dt> User Agent</dt> <dd> #{line.user_agent}</dd> \n"
      print "</dl> <hr> \n"
    }
    print "</ol> \n"
  }
  #ロボットのアクセス回数を表示
  print "<h3> robots.txtへのアクセス</h3> \n"
  print "<ul> \n"
  count_robot.each{|crawler,count|
    print "<li> #{count}回:#{crawler}</li> \n"
  }
  print "</ul> \n"
  #お気に入りアイコンへのアクセス回数を表示
  print "<h3> favicon.icoへのアクセス</h3> \n"
  print "<ul> \n"
  count_fav.each{|ua,count|
    print "<li> #{count}回:#{ua}</li> \n"
  }
  print "</ul> \n"

  footer_out() #フッタ表示
end

それから,生ログ表示部を作ったときに,「UTF-8を直せない」と言っていたのだが,uconvというものを知ったので,使ってみた.

RAAのuconvのところから,uconv-0.4.12.tar.gzをダウンロードし,展開した上で,すべてサーバー上の同じディレクトリにアップロードする.

それから,サーバーにシェルログインして,uconvのファイルを入れたディレクトリに移動.

ruby extconf.rb

と打つと,Makefileができたよ~というメッセージが出るので,おもむろに

make

と打つと,めでたくuconv.soというファイルができあがった.

このファイルを,cgiスクリプトを置いているディレクトリに放り込み,require "uconv"!

でもって,文字コード変換をやっているreferer_unencodeを次のように書き換えた.

def referer_unencode #リファラーを返す(アンエンコード済)
  ref = CGI.unescape(@all[10])
  case NKF.guess(ref)
    when 0
      chr_in = "-J"
    when 1
      chr_in = "-S"
    when 2
      chr_in = "-E"
    when 3
      begin
        return Uconv.u8toeuc(ref) + NKF.guess(ref).to_s
      rescue
          return NKF.nkf("-e", ref)
      end
  end
  return NKF.nkf("-e" + chr_in, ref)
end

出力結果(検索文字列を含む物以外は,ばっさり削除)

......ギース様,大人気?――じゃなくて.

かなり変換できるようになったなぁ.(まんぞく,まんぞく)

コメントを投稿

| PC/Web > Ruby |

2004年10月21日

ノーベル賞の知名度

I君
(新聞を読みながら)芝浦工大の学長ってノーベル賞取ってるんですね.知りませんでしたよ.
Sousui
名前は知ってたの?
I君
ええ,名前はよく見るなあと思ってたんですけど.
Sousui
芝浦工大の学長が江崎玲於奈だと知らないのはしょうがないかもしれないけど,江崎玲於奈がノーベル賞取ってるの知らないのはダメでしょ.
Yさん
僕は,その人自体を知らない.……利根川さんなら知ってるけど.
Sousui
じゃ,中身は当然知らないですよね……
I君
Sousuiさんは知ってるんですか?
Sousui
量子トンネル効果だったっけ?
I君
さすがですね.これからSousuiさんに無茶言えません.
Mさん
今まで言ってたんですか?
I君
(あわてて)いえ,今までも言ってませんけど.
Yさん
その人,いつノーベル賞取ったの?
I君
(新聞を見ながら)1973年です.
Yさん
うわ,生まれた年だよ.
I君
僕は生まれてません.
Sousui
私も.
Yさん
生まれる前のことなんてよく知ってるね.
Sousui
だって,アインシュタインがノーベル賞取ったことは知ってるでしょう?
Yさん
アインシュタインがノーベル賞取ったのを知らない.
Sousui
まじっすか?じゃ,日本で初めてノーベル賞取った人も――
Yさん
知らない.知ってる?
I君
湯川さん.
Yさん
すごいぢゃない,I君.
Sousui
何したかは知ってるの?
I君
電気を通すプラスチックでしたっけ.
Sousui
馬鹿か,お前は
I君
それは最近でしたっけ.

ノーベル賞を取った日本人は12人いるそうだ.さあ,みんなでおもいだしてみよう.

コメントを投稿

| 雑記 > よく分からない会話集 |

2004年10月22日

川崎さん

詩人の川崎洋さんが亡くなった.

私がこの方を知ったのは,読売新聞のこどもの詩の欄で,はっきりと意識したのは,toschが「この人のコメントがおもしろい」と言ったからである.なるほど,そう言われてみればその通りだ.

勝手に45ぐらいだと思いこんでいたのだが,70を超えていたと初めて知った.それを知って,送られてくる無邪気な詩を読みながら目を細めている好々爺の姿が思われる.

ご冥福をお祈りします.

コメントを投稿

| コメント (2) | 雑記 |

Apacheアクセスログと私(サイト内遷移表示のバグ取り)

今日はサイト内遷移表示のバグ取り.

こないだ書いたコード"をよくよく見てみると,

trace.sort.each{|ip, value|
(略)

と書いてるくせに,中でもらっている変数がlineになっていた.これがおかしい元凶であるような気がする.

それで,書き換えてみた.書き換えの際,また繰り返すのがこの部分で,計算も繰り返しでする部分があって,1回目だけ通るのがここで,等と考えているうちにまた訳が分からなくなる.

それと,ハッシュのハッシュを配列のハッシュにしたので,その部分も書き換え.それと,無視するファイルも文末一致で除く物と,文中どこであれ除く物とに増やしたので,書き換えている.

#ページ内遷移表示関数
#IPアドレス順に並び替えて,requestしたファイルを表示する.
def trace_view(file)
  header_out("ページ内遷移")

  logfile = open(file)
  ignore = Regexp.new("#{IGNORE_FILE_END}$|#{IGNORE_FILE}")
  #必要な行をとりあえずハッシュに保持
  trace = Hash.new
  while logline = logfile.gets
    line = Accesslog.new(logline)
    #無視するファイルは処理しない
    unless ignore =~ line.requestURI
      #必要行lineをtrace[ip]に入れていく.
      #traceはハッシュで,{Key => Array}.
      unless trace.key?(line.ip)
        trace[line.ip] = Array.new
      end
      #行を保持
      trace[line.ip] << line
    end
  end
  #得られた行を表示
  trace.each{|ip, value|
    print "<h3> " + ip + "</h3> \n"
    value.each_with_index{|line, i|
      if i == 0
        print "<h4> #{line.user_agent}</h4> \n"
        print "<ol> \n"
      end
      t_last = Time.mktime(line.year, line.month, line.day, line.hour, line.minute, line.second)
      unless i == 0
        period = conv_sec(t_last - $t_prev)
        print "<br> \n↓<br> \n↓ #{period}<br> \n↓</li> \n"
      end
      $t_prev = t_last #t_prevに前の時間を保持
      print "<li> "
      print "#{line.requestURI}(#{line.month}月#{line.day}日"
      print "#{line.hour}時#{line.minute}分#{line.second}秒)"
    }
    print "</li> \n"
    print "</ol> \n"
  }

  footer_out() #フッタ表示
end

conv_secは,引数にもらった数を秒数として,○時間○分○秒という文字列を返すメソッド.

# 秒数を引数にもらって,(秒,分,時)という配列を返す.
# 秒数によって,配列の長さは変わる.
TIME_CONV = [ 60, 60 ]
#助数詞
TIME_AN = [ "秒", "分", "時間" ]
def conv_sec(num)
  t = Array.new
  fmt_time = ""
  t[0] = num.to_i
  TIME_CONV.each{|s|
    if t[-1] < s
      break
    else
      t << t[-1] / s
      t[-2] = t[-2] % s
    end
  }
  t.each_with_index{|an, i|
    fmt_time = an.to_s + TIME_AN[i] + fmt_time
  }
  return fmt_time
end

かえって分かりにくくなったかなあ.もし,日とか月とかに拡張するときも配列定数に書き加えるだけでいいかなあと思ったんだけど.

ちなみに,表示結果はこんな具合.うまくいっているような気はする.

今度はロボットのアクセスを分けてみよっと.

コメントを投稿

| PC/Web > Ruby |

2004年10月23日

風に揺られて

着ようと思った服が見つからず,頭をひねる.

なんせ,ワンルームマンションだ.置き場所だってそうはない.

……

……

……

もしかして.

おそるおそる覗いたベランダにあんぎゃ~,あんた,あの台風の暴風雨の中,そこで揺れてたんですか~

ちょっと助けを求めてくれれば取り込んだ物を,とあり得ないことなど考えながら,何日目かの救助にあたったのであった.

コメントを投稿

| 雑記 |

2004年10月24日

Apacheアクセスログと私(クローラーのアクセスを分ける)

ロボットのアクセスを分けることにする.特に,ページ内遷移は,人のアクセスだったら「どのぐらいの時間を掛けてるのかな~」と思うけど,クローラーなら一瞬でどんどん読み込んでいっちゃうんだろうから滞在時間なんていらない.

実のところ,だんだん慣れてきたので,コードを書くのはそれほど大変じゃなかった.大変だったのは,どのユーザーエージェントがロボットで,そのロボットはどういう検索エンジンのロボットかを調べることだった.調べている最中にメールアドレス収集ロボットのUAをいくつか知ったので,.htaccessではねておいた.

ま,そいつはともかく,調べた結果を,「ユーザーエージェント名」,「その説明」のタブ区切りテキストにした.このファイルの名前をrobotsinfo.txtにして,定数ROBOT_TXTに読み込んでおく.

それから,ロボット情報読み込みのためのモジュールを作っておく.

#クローラー情報関連読み込み関数
module Crawler
  #クローラー情報メソッド:返り値はハッシュで,{ roboto_ua => comment }
  def robot_info
    r = Hash.new
    robotfile = open(ROBOT_TXT)
    while roboline = robotfile.gets
      robo = roboline.chomp.split(/\t/)
      r[robo[0]] = robo[1]
    end
    robotfile.close
    return r
  end
  module_function :robot_info

  #クローラーのUserAgent名を返すメソッド:返り値は正規表現
  def robot_name
    robot_ua = ""
    robotfile = open(ROBOT_TXT)
    while roboline = robotfile.gets
      robo = roboline.chomp.split(/\t/)
      robot_ua = robot_ua + robo[0] + "|"
    end
    robotfile.close
    return Regexp.new(robot_ua.chop)
  end
  module_function :robot_name
end

いまいち,何をクラスにして,何をメソッドにして,何をモジュールにしたらいいのか分かってないんだよなぁ……

ともかく,ロボットの情報を書いたファイルを読み込んで,変数に入れていくメソッドを作ってみた.(robot_infoは,今回はまだ使わない)

似たようなことしてるんだけど,これって1つにできないのかなぁ.

ま,それは置いといて,あとは簡単で,呼び出し側に robot_re = Crawler::robot_nameと書いておいて,無視ファイルを決めているunless文にunless ignore =~ line.requestURI || robot_re =~ line.user_agentと書き入れる.

これでおしまい.今回は簡単だったな.

コメントを投稿

| PC/Web > Ruby |

Rubyデスクトップリファレンス

紙媒体のリファレンスが欲しいと思って買ったんだけど,簡潔すぎて使いこなせてません.

なんせ,サンプルがない.

Rubyをバリバリ使っている人が,ちょっと思い出したいときに使うもんなんでしょうね,きっと.

Rubyデスクトップリファレンス (単行本)

コメントを投稿

| PC/Web > Ruby |

2004年10月25日

地震の被害

新潟地震の被害なんですが,うちは東京だというのに,置き時計が転げ落ちて電池が吹っ飛び,霧吹きが倒れて水浸しになりました.

おかしい.たぶん,震度1ぐらいだよなあ.

コメントを投稿

| 雑記 |

謎のアクセスログ

こないだからアクセスログを整形することばかりに力を注いでいるんですが,気になるログがある.それは,「\x83W\x83\x87\x83W\x83\x87\x82\xcc\x8a\xef\x96\xad\x82\xc8\x96`\x8c\xaf」とかいう訳の分からない検索文字列をrefererに持つ物である.何か気味が悪い.しかし,調べても他のサーバーのアクセスログしか出てこなくて,何であるかは分からない.

誰か情報プリーズ.

コメントを投稿

| PC/Web |

2004年10月26日

地震の被害(その2)

実は,富山に帰る切符を取った日に地震が起き,取った切符の路線が思いっきり不通になってしまいました.越後湯沢まで行けてもなあ…….その先のほくほく線の復旧は1週間程度を予定しているようですが,帰る日に間に合うかどうか微妙なところだったので,米原経由に切り替えました.

このとき,JRのおねーさんに訊いていて思ったのですが,もし,地震の後に買っていたら手数料無しの払い戻しはなかったのかしらん.

そして,7000円ほど高かった.時間もかかるんだろう.

コメントを投稿

| 雑記 |

またしても

I君が「富山はどうだったんですか」と訊くので,「知らないよ,東京にいるのに知るわけないじゃないか」と言ったら,Yさんが「また,こんなこと言ってるよ」とのたまわった.

しかしだね,言わせて欲しい.

私は地震の起きた日,実家に電話を掛けている.

はい,○○です.
もしもし.
おお,なんだ.
11月3日に帰るから.
そっで,いつまでおるんだ.
日曜日の予定.
3日いつ来るんだ.
お昼頃.
んー,分ったぞ.

これで何をどう心配しろと言うんだ

と,Yさんに文句を言ったら,「親子断絶?」と訊かれた.いや,断絶してたら帰えんねって.

コメントを投稿

| コメント (2) | 雑記 |

2004年10月27日

弱震程度じゃ分りません

Sousui
東京も揺れてたんですね,地震.
Yさん
ちょっとね.
Sousui
こないだから咳が止まんなくて,自分が揺れてるんだか地面が揺れてんだかさっぱり分りません.
I君
僕も,二日酔いかなあ,と.
Sousui
あんな夕方に,いきなり二日酔いかい.
コメントを投稿

| 雑記 > よく分からない会話集 |

咳が止まらない

17日あたりからずっと咳が止まらない.電話に出ている最中に咳が出るのには参っていたものの,他の症状がないので,放っておいたのだが,係の人が嫌そうな顔をするので観念して医者に行ってきた.

医師
1週間以上咳が止まらない,と.のどは痛い?
Sousui
いいえ.
医師
ちょっとのど見せてくれる?あ~,真っ赤だね~.痛くないの?
Sousui
まったく.

夕方から,なんだかのどが痛いような気もしないでもなくなってきたんだけど,医者が行ったからかもしれない.

やっぱり咳がときどき押さえがたくなるだけで,普段は肺を膨らませにくい(息が吸いにくい)気がするだけだ.

寝てりゃ直るんだろう.しぱらく大人しくしていよう.

コメントを投稿

| コメント (2) | 雑記 |

2004年10月29日

Apacheアクセスログと私(クローラーを捕まえてみる)

それでは,本日はロボットの挙動を表示する部分をば.

どんな風に表示するかをまず考える.サイト内遷移の表示をベースに,滞在時間はいらんなとか,同じ検索エンジンのクローラーがいっぱい来るかもしれないから,それはひとまとめにしたいよな,と考え,


ロボットの説明

ユーザーエージェント名/IPアドレス

……

……

アクセスしたファイルのリスト

……

……

というのの繰り返しにしようと考える.そこで,作っておいたrobot_infoも利用して,以下のコードを書いた.


#サイト内遷移表示関数(ロボット用)

def trace_robot(file)

  header_out("クローラー/オートパイロット-サイト内遷移")



  robot_info = Crawler::robot_info #ロボット情報のハッシュ



  ignore = Regexp.new("#{IGNORE_FILE_END}$|#{IGNORE_FILE}")



  logfile = open(file)

  #必要な行をとりあえずハッシュに保持

  trace = Hash.new

  while logline = logfile.gets

    line = Accesslog.new(logline)

    #無視するファイルは処理しない

    unless ignore =~ line.requestURI

      robot_info.each_key{|ua|

        reg_robot = Regexp.new(ua) #クローラー情報にあるUAを正規表現にする.

        if reg_robot =~ line.user_agent

          #必要行をtrace[ua]に入れていく.

          #traceはハッシュで,{Key => Array}.

          unless trace.key?(ua)

            trace[ua] = Array.new

          end

          #行を保持

          trace[ua] << line

        end

      }

    end

  end

  logfile.close



  #得られた行を表示

  trace.each{|ua, value|

    print "<h3>#{robot_info[ua]}</h3>\n" #最初にロボットの説明を見出しにする.



    #ユーザーエージェントとIPを表示する.

    print "<h4>ユーザーエージェント【IPアドレス】</h4>\n"

    print "<ol>\n"

    #重複するUA/IPを削るための操作

    ua_ip = value.collect{|rline| "#{rline.user_agent}【#{rline.ip}】"}

    ua_ip.uniq.sort.each{|rua| print "<li>#{rua}</li>\n"}

    print "</ol>\n"

   

    print "<hr>\n" #区切り



    #アクセスされたファイルを表示

    print "<h4>リクエストファイル</h4>\n"

    print "<ol>\n"

    value.each_with_index{|line, i|

      print "<li>#{line.requestURI}(#{line.month}月#{line.day}日"

      print "#{line.hour}時#{line.minute}分)</li>\n"

    }

    print "</ol>\n"

    print "</div>\n"

  }



  footer_out() #フッタ表示

end

最初,出力してみたら,見にくかったので,今回,CSSもちょっといじっている.出力サンプルいや,Googleクローラーのすごいこと,すごいこと.

しまった,気づいちゃいたんだけど,IPアドレスのままの物とDNSを引いてリモートホストに変換された物が入り交じってるけど,重複する物ってあるよな.

どうやったらIPを変換できるかなぁ.

コメントを投稿

| PC/Web > Ruby |

プログラミングRuby―達人プログラマーガイド

勝手に「ウサギ本」と呼んでいる.

評判がよいので,読んでみたいなぁと思っているところに転がり込んできた図書券5000円.そりゃ,買いますわ,あんさん.

文書に漂うジョークの具合が何とも翻訳本くさく,微笑んでしまった.昔から翻訳物に慣れ親しんでいる身としては,嫌いじゃない.

内容は,ちょっぴり高度で,プログラミング未経験という人には向かないんだろうけど,丁寧なので,「かじりました~」ぐらいの人(=私ぐらいの人)ならついて行けるんじゃないだろうか.

現在,一生懸命勉強中.

ちょっと失敗したと思ったのは,買ってしまってから,Ruby1.8対応の2nd Editionが近日中に出版されると知ったこと.もしかしたら,そっちも買っちゃうかもなあ.

あ,言うまでもないことだが,これは,英語版.翻訳されるかどうか知らない.あと,作者のサイトから,PDF版も買えるようだ.(英語の取引になるけど)

ちなみに,1st Editionでかつ英語でかつ抄で良ければ,Ruby Centralで読める.

プログラミングRuby―達人プログラマーガイド (単行本)

コメントを投稿

| PC/Web > Ruby |

2004年10月31日

Apacheアクセスログと私(IP→リモートホスト変換)

IPをリモートホストに変換するべく,前に作ったAccesslogクラスのipメソッドを書き換えた.

def ip #リモートホスト名を返す
  ip = @all[0] #IPアドレス/リモートホスト
  begin
    #数字.数字.数字.数字という文字列だったら
    if /^\d+\.\d+\.\d+\.\d+$/ =~ ip
      ip = Resolv.getname(ip).to_s
    end
  rescue
  end
  return ip
end

あ,これを使うにあたってresolv.rbをrequireしてますよ.

なぜか,エラーになることがあるので,rescueして――結局,何でエラーになるのか分らないので,何もしていない.......へたれだ.

ipじゃなくてremote hostだよな,完全に名前に偽りありだ.

2004年11月4日追記

正規表現で回数指定の繰り返しを使えるのを知ったので,条件設定を /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ =~ ip にしてみた.

それから,エラーの対処なんだけど,とりあえず,いったんエラーになったIPは処理しないようにしてみた.

begin
  if /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ =~ ip #数字.数字.数字.数字という文字列だったら
  #エラーになったことのあるipでなければDNSをひく

    ip = Resolv.getname(ip).to_s unless @@error_ip.include?(ip)
  end
  rescue Resolv::ResolvError, Resolv::ResolvTimeout
    @@error_ip << ip #DNSエラーになるipは以後,処理しない
  end

他にも,Resolvでタイムアウトになるものの処理も高速化させたいのに,timeoutやらresolv-なんとか(忘れた)など使っていろいろやってみたけど,上手く捕まえられない.

あ,なるとちゃん(@@error_ipのこと)は,外でArray.newしてます.

コメントを投稿

| コメント (1) | PC/Web > Ruby |

Powered by Movable Type