IPアドレス群からワールドヒートマップを作成してみた

2022.01.07

こんにちは、森田です。

アクセスログの多くには、アクセス元のIPアドレスを含んでいます。
そのIPアドレスを集計し、可視化する方法の1つとしてワールドヒートマップがあります。
本記事では、実際にIPアドレス群からPythonでデータの処理を行い、ワールドヒートマップを行って行きます。

検証環境

  • Python 3.8.5
  • pandas
  • numpy
  • geoip2 4.5.0
  • pycountry 20.7.3
  • folium 0.12.1

使用するデータ

データは下記のようなIPアドレス群を使用します。csvファイルでまとめてあるものとします。

使用ライブラリ

IPアドレスから国を推定するためgeoip2geoip2で取得できる国名コード変換用にpycountryを使用します。
また、基本的なデータ処理はPandasを用いて行い、ヒートマップはfoliumを使用します。
Pandaspycountryは、pipコマンドなどでインストールを行います。

pip install pandas pycountry

geoip2(GeoLite2)のインストール

まず、pipコマンドを用いてインストールを行います。

pip install geoip2

geoip2を使用するためには、ファイルのダウンロードなどが必要となります。
こちらよりGeoLite2 Cityのダウンロードを行います。
ダウンロードしたファイルは以下のように使用します。

import geoip2.database

ip = '11.109.10.11'
reader = geoip2.database.Reader('GeoLite2-City.mmdb')
res = reader.city(ip)
print(res.country)

出力結果

geoip2.records.Country(confidence=None, geoname_id=6252001, is_in_european_union=False, iso_code='US', _locales=['en'], names={'de': 'USA', 'en': 'United States', 'es': 'Estados Unidos', 'fr': 'États Unis', 'ja': 'アメリカ', 'pt-BR': 'EUA', 'ru': 'США', 'zh-CN': '美国'})

Foliumのインストール

Foliumは、Pythonの地理データ可視化ライブラリの1つです。
このライブラリは、Quickstartを見るだけなんとなく使えるほど簡単に使用できるのがとても魅力的です。
こちらの使用には、まずpipでインストールを行います。

pip install folium

その後、地図データの別途ダウンロードが必要ですので、下記コマンドでデータをダウンロードします。

git clone https://github.com/python-visualization/folium.git

ワールドマップの場合は、examples/data/world-countries.jsonのデータを使用します。

データ前処理

ライブラリ・必要ファイルが準備できたので、先ほどのIPアドレスCSVファイルを国ごとでグループ化していきます。
まず、geoip2で取得できる国名コードがfoliumに対応していないのでpycountryで変換するように関数化します。

import geoip2.database
import pycountry

def country_checker(ipaddress):
    try :
        reader = geoip2.database.Reader('GeoLite2-City.mmdb')
        response = reader.city(ipaddress)
        return pycountry.countries.get(alpha_2=response.country.iso_code).alpha_3
    except:
        return None

この関数をそれぞれのIPアドレスに適用させ、country列を新規で作成していきます。

df["country"] = df["IP"].apply(country_checker)

国ごとでグループ化するため、counts列を追加します。

df["counts"] = 1

では、国ごとでグループ化を行い、countsの合計値を算出します。

import numpy as np
df2 = df[["country", "counts"]].groupby('country').agg(np.sum)

出力結果

         counts
country        
AUS         273
BRA          37
FRA         110
GBR         116
IDN         151
ITA          76
JPN         119
SGP          67
USA         474

最後に、foliumで可視化させる場合、国コードを列データとして渡すので、indexから新規にiso_code列を作成しておきます。

df2['iso_code'] = df2.index

ワールドマップ作成

では、最後にfoliumで可視化を行います。

import folium

# world map import
m = folium.Map(location=[50, 0], zoom_start=1)
geojson = "./folium/examples/data/world-countries.json"

# visualization
folium.Choropleth(
geo_data=geojson,
name='choropleth',
data=df2, # Input DataFrame
columns=['iso_code', 'counts'], 
key_on='feature.id',
fill_color='OrRd',
fill_opacity=0.7,
line_opacity=1,
legend_name='IP Adress Access' 
).add_to(m)

m.save("world.html")

このようにして作成されたワールドマップは以下となります。

いい感じで上手く可視化されました!

まとめ

今回は、GeoLite2Foliumなどを用いて、IPアドレスごとのアクセスをヒートマップにしてみましたが、ドキュメントを少し読むだけで作れたのでとても簡単でした!
ぜひ、アクセスログをお持ちの方は、IPアドレスを抽出し、ワールドヒートマップを作ってみてはいかがでしょうか?

今回のコード・ファイル

参考

GeoLite2でサクッとできるIPアドレスの国判定
Folium 0.12.1 documentation Quickstart