« 大門夏祭り | メイン | GeoIPの続き »

2005年07月23日

|append.gif このエントリーを含むはてなブックマーク | delicious.gif | この記事をクリップ!

GeoIP + Shapelib + MapServerで国別の主題図

GeoIP(Python) + Shapelib(Python) + MapServerでApache logの国別の主題図を作ってみました.

nishioka.sakura.ne.jpにおける先月のApache logから国別の主題図
(自宅サーバなので、見えなかったらすんません)

Apache logから国別の主題図作り方のメモ


  1. http://www.diva-gis.org/data/DataServer.htmから世界地図をゲット

  2. apache logからIPアドレスのリストを作成してGeoIPで国別の集計をする

  3. ShapeLibを使って世界地図の属性に2で作成した集計情報を追加する

  4. MapServerで3.で作った世界地図を表示する

ShapelibとGeoIPはPythonのモジュールを利用しました。
僕の環境(FreeBSD)では、MapServerはPackageからGeoIPはPortsから取得して、そしてShapelibとpyShapelibはソースからコンパイルして利用しました。
コンパイルには特にオプションは設定していませんので割愛します。

2と3を行うPythonのコードをさらしておきます、

ip2dbf.py

#!/usr/local/bin/python import GeoIP import sys import string import math import  dbflib import re ar = sys.argv[1:] gi = GeoIP.new(GeoIP.GEOIP_MEMORY_CACHE) ip = {} p = re.compile('¥d+¥.¥d+¥.¥d+¥.¥d+')

try:
   basedbf = ar[1] 
except IndexError:
   basedbf = "cntry00.dbf"
try:
   savedbf = ar[2] 
except IndexError:
   savedbf = "new.dbf"

try:
   f = open(ar[0])
   for line in f.readlines(): 
      line = line[:-1]
      text = line.split(" ")
      host = text[0] 
      m = p.match(host)
      if m:
         name =  gi.country_name_by_addr(host)
      else:
         name =  gi.country_code_by_name(host)
      if ip.has_key(name):
         ip[name] = ip[name] + 1
      else:
         ip[name] =   1
   f.close()
except IOError:
   print "Can't find file:", x

max = len(ip)
ipv = ip.values()
ipv.sort()
lenip = {}
j = 0
for l in ipv:
   lenip[l] =    math.ceil((j * 5) / max) +1
   j = j + 1
   
newdbf = dbflib.create(savedbf)
#for k in ip.keys():
#   print k,'¥t',ip[k],'¥t',lenip[ip[k]]
try:
   dbf = dbflib.open(basedbf,"rb+")
   fieldcount  = dbf.field_count()
   for i in range(fieldcount):
      field = dbf.field_info(i)
      newdbf.add_field(field[1],field[0],field[2],field[3])
   newdbf.add_field("count",dbflib.FTInteger,6,0)
   newdbf.add_field("rank",dbflib.FTInteger,3,0)
   dbfcount = dbf.record_count()
   for i in range(dbfcount):
      line = dbf.read_record(i)
      na = line['ISO_2DIGIT']
      line['count'] = ip.get(na,0)
      line['rank'] = lenip.get(ip.get(na,0),0)
      newdbf.write_record(i,line)
#      print line , ' ', ip.get(na,0),' ',lenip.get(ip.get(na,0),0)
   f.close()
except IOError:
   print "Can't find file:", x

dbf.close()
newdbf.close()


使い方

python ip2dbf.py access_log input.dbf output.dbf

引数 1 : アクセスログファイル
引数 2 : 世界地図のdbfファイル
引数 3 : 新しいdbfファイル


python ip2dbf.py access_log cntry00.dbf tmp.dbf
cp cntry00.dbf cntry00.db.bk
mv tmp.dbf cntry00.dbf

1.で取得した 世界地図のshape fileの属性データ" cntry00.dbf"とアクセスログをもとに新しい属性データ"tmp.dbf"を作ります
1.で取得した 世界地図のshape fileの属性データ" cntry00.dbf"のバックアップを取ります
新しい属性データ"tmp.dbf"を世界地図のshape fileの属性データとして利用するために" cntry00.dbf"にリネームします


説明


  • このスクリプトは世界地図のDBFに主題図用のフィールドを追加します

  • shapeの構造は*.shp(図形ファイル),*.dbf(属性ファイル),*.sbx(図形索引ファイル)にで構成されています、このスクリプトはdbf(属性ファイル)のみを加工します。そのため、このスクリプトで作成したdbfファイルをShape fileとしてMapServerなどで利用するためには、スクリプトにて作成したdbfファイルを元のファイル名にリネームしてください

  • access_logは一レコード目にIPアドレスがあり、スペースで区切られている必要があります.

  • IPアドレスでもホスト名でもOKです。

  • 主題図用のフィールドとして、元のフィールドから"rank" と"count"をoutput.dbfを作成します

  • "rank"フィールドはアクセス数が多い順に5段階、"count"フィールドは今までアクセスの総計が入ります


  • pythonのスクリプトやらmapfileとかを詰め合わせたセット
    (世界地図も入れてますのでMapServerさえあれば動くと思います、再配布まずいかな?)

投稿者 nishioka : 2005年07月23日 22:01

TrackBack

このエントリーのトラックバックURL:
http://nishioka.sakura.ne.jp/mt/mt-tb.cgi/51

このリストは、次のエントリーを参照しています: GeoIP + Shapelib + MapServerで国別の主題図:

» 位置情報HACK4題 from ここギコ!
位置情報関係のHACK4題です。 まずはMapServer関係のHACKから、Nakamura-KU ADDICTさんとこで、自分のサイ [続きを読む]

トラックバック時刻: 2005年07月26日 05:19

Comment

コメントしてください




保存しますか?