こんにちは。ナミレリです。みなさん、MacでPythonは使っていますか?
アクセスログのIPアドレスから国をサクッと調べたいときってありますよね。前回は無料のGeoLite2を使ってPythonでIPアドレスから国を確認する記事を書きました。GeoLite2を使いたい方はぜひ下の記事も参照ください。
今回はGeoLite2を使わずにpandasを使ってIPアドレスから国を確認してみます。やっていて気づきましたが、割と頻繁に地域インターネットレジストリ(RIR)から公開されているIPアドレスデータに変更があります。GeoLite2で国を確認するとフランス、RIRの最新データで確認するとデンマーク、なんてこともありましたし、サブネット(サブネットマスク)もGeoLite2とRIRの最新データで差分がありました。GeoLite2は無料で利用できるデータなので更新頻度が低いということだと思います。
という状況の気づきもあり、今回はpandasを使ってRIRのデータでIPアドレスから国を確認することをやってみます。

この記事はこんな人にオススメ
- コマンドラインでIPアドレスから国を確認したい
- 複数のIPアドレスから一気に国を確認したい
- しかも無料で確認したい
- Pythonのpandasを使って勉強のためにも自分で作ってみたい
- M2 MacBook Air 13.6 インチ
- macOS Ventura 13.0.1
- pyenv 2.3.8
- miniforge3-4.10.3-10(Python 3.9.15)
- pandas 1.5.2

目次
IPアドレス割り振りの仕組みを理解する
前回の記事でも書いていますが少しおさらいすると、世界のIPアドレスはICANNによってい管理されています。このICANNがIPアドレスを世界に5つある地域インターネットレジストリ(Regional Internet Registry:RIR)に割り振り、このRIR(下図参照)がさらに各国に割り振り管理されています。
地域 | 名称 | 略 |
---|---|---|
北アメリカ | American Registry for Internet Numbers | ARIN |
ヨーロッパ、 中東 、中央アジア | RIPE Network Coordination Centre | RIPE NCC |
アジア・太平洋地域 | Asia-Pacific Network Information Centre | APNIC |
南アメリカ とカリブ海地域 | Latin American and Caribbean Internet Address Registry | LACNIC |
アフリカ | African Network Information Centre | AfriNIC |
RIRが公開しているIPアドレス割り振りデータ
RIRが各国に割り振りしたIPアドレスをサイトに公開しています。アジア・太平洋地域の各国にIPアドレスを割り振るAPNICのサーバから、世界に5つあるRIRの各データがダウンロードできます。
地域 | 略 | FTP(最新IPアドレスデータ) |
---|---|---|
北アメリカ | ARIN | https://ftp.apnic.net/stats/arin/delegated-arin-extended-latest |
ヨーロッパ、 中東 、中央アジア | RIPE NCC | https://ftp.apnic.net/stats/ripe-ncc/delegated-ripencc-latest |
アジア・太平洋地域 | APNIC | https://ftp.apnic.net/stats/apnic/delegated-apnic-latest |
南アメリカ とカリブ海地域 | LACNIC | https://ftp.apnic.net/stats/lacnic/delegated-lacnic-latest |
アフリカ | AfriNIC | https://ftp.apnic.net/stats/afrinic/delegated-afrinic-latest |
IPアドレスデータのファイルのフォーマット
ファイルのフォーマットは|で区切られたCSVで以下の通りです。
registry|cc|type|start|value|date|status
grep ipv4 delegated-apnic-latest | tail -10
apnic|KR|ipv4|223.255.208.0|4096|20100802|allocated
apnic|ID|ipv4|223.255.224.0|2048|20100809|allocated
apnic|AU|ipv4|223.255.232.0|1024|20100812|allocated
apnic|CN|ipv4|223.255.236.0|1024|20110311|allocated
apnic|HK|ipv4|223.255.240.0|1024|20100803|allocated
apnic|IN|ipv4|223.255.244.0|1024|20100804|allocated
apnic|HK|ipv4|223.255.248.0|1024|20151105|allocated
apnic|CN|ipv4|223.255.252.0|512|20110414|allocated
apnic|SG|ipv4|223.255.254.0|256|20110408|assigned
apnic|AU|ipv4|223.255.255.0|256|20110811|assigned
項目 | 例 | 意味 |
---|---|---|
registry | apnic | 地域インターネットレジストリ(RIR) |
cc | JP | ISO 3166の国コード |
type | ipv4 | ipv4, ipv6, asnのどれかが入ります |
start | 223.252.112.0 | 開始のIPアドレス(ネットワークアドレス) |
value | 4096 | IPアドレスの個数 |
date | 20100727 | 割り当てた年月日(YYYMMDD形式) |
status | allocated | allocated, assignedのどちらかのステータス |
extensions | A918B936 | extendedフォーマットのみ |
ここまでは前回のおさらいですがpandasに読み込む際にデータとして知っておくべきことなのでぜひ下の記事もご覧ください。
pandasを使ってIPアドレスから国を確認する
事前準備
今回の作業ディレクトリは/Users/you/ipとし、RIRのデータをcurlでダウンロードします。
pwd
/Users/you/ip
curl \
-O https://ftp.apnic.net/stats/arin/delegated-arin-extended-latest \
-O https://ftp.apnic.net/stats/ripe-ncc/delegated-ripencc-latest \
-O https://ftp.apnic.net/stats/apnic/delegated-apnic-latest \
-O https://ftp.apnic.net/stats/lacnic/delegated-lacnic-latest \
-O https://ftp.apnic.net/stats/afrinic/delegated-afrinic-latest
ls -lh
total 52608
-rw-r--r-- 1 u staff 388K 12 11 11:59 delegated-afrinic-latest
-rw-r--r-- 1 u staff 3.5M 12 11 11:59 delegated-apnic-latest
-rw-r--r-- 1 u staff 11M 12 11 11:59 delegated-arin-extended-latest
-rw-r--r-- 1 u staff 2.0M 12 11 11:59 delegated-lacnic-latest
-rw-r--r-- 1 u staff 7.2M 12 11 11:59 delegated-ripencc-latest
IPアドレスから国を確認するプログラム
pandas、pathlib、ipaddressのライブラリを使い以下のように書いてみました。ipaddressライブラリを使うと簡単にIPアドレスの演算ができて便利です。
import pandas as pd
from pathlib import Path
from ipaddress import IPv4Address
import sys
# 地域インターネットレジストリ(RIR)が公開しているIPアドレスデータのディレクトリ
p = Path('/Users/you/ip')
# 'delegated-'から始まるファイル名
file_name = 'delegated-*'
# 複数のIPアドレスデータのファイルPATHを取得
csv_files = p.glob(file_name)
# カラム名の指定
column_name = ('registry',
'cc',
'type',
'start',
'value',
'date',
'status')
# 空のリストを作成
data_list = []
def main():
for file in csv_files:
# 区切り文字"|"を指定し、7列目(extensions)は読まない
df = pd.read_csv(file, names=column_name,
sep='|',usecols=lambda x: x not in ['7'],
dtype = {'registry':'object',
'cc':'object',
'type':'object',
'start':'object',
'value':'object',
'date':'object',
'status':'object',
}
)
data_list.append(df)
# dfを結合する
df = pd.concat(data_list)
# valueがsummaryの行は削除
df = df[df['value'] != "summary"]
# type列がipv4のレコードのみ抽出
df = df[df["type"] == "ipv4"]
#statusが"assigned"の行は削除
df = df[df['status'] != "assigned"]
# 欠損データがある行は削除
df = df.dropna(how='any')
# IPの個数とサブネットの辞書
netmasks = {16777216 : 8, 8388608 : 9,
4194304 : 10, 2097152 : 11,
1048576 : 12, 524288 : 13,
262144 : 14, 131072 : 15,
65536 : 16, 32768 : 17,
16384 : 18, 8192 : 19,
4096 : 20, 2048 : 21,
1024 : 22, 512 : 23,
256 : 24, 128 : 25,
64 : 26, 32 : 27,
16 : 28, 8 : 29,
4 : 30, 2 : 31,
1 : 32
}
# startのIPアドレスをIPv4Addressオブジェクトにしてdf['newIP']へ
df['newIP'] = df['start'].apply(IPv4Address)
# valueをint型にしてdf['value_int']へ
df['value_int'] = df['value'].astype('int')
# value_intからネットマスクにする
#### df['mask'] = df['value_int'].apply(netmasks.get)でもいいかも
df['mask'] = df['value_int'].map(netmasks)
# maskの".0"を除去
df['mask'] = df['mask'].astype('object')
df['mask'] = df['mask'].apply(str).str.replace('\.0', '', regex=True)
# newIPと個数から終点のIPアドレスを計算
df['endIP'] = df['newIP'] + df['value_int'] - 1
# startとmaskからネットワークアドレスを作成
df['network'] = df['start'].str.cat(df['mask'], sep='/')
# 引数の複数のIPアドレスをipsに
ips = sys.argv[1:]
for ipaddr in ips:
# 引数のIPアドレスをIPv4Addressオブジェクトに
ipaddr = IPv4Address(ipaddr)
# IPv4Addressオブジェクトに対する演算
result = df[(df['newIP'] <= ipaddr) & (ipaddr <= df['endIP'])]
# 結果の出力
print(
ipaddr, "->" ,
result['cc'].to_string(index=False)
+ "," +
result['network'].to_string(index=False)
)
if __name__ == '__main__':
main()
実行してみる
上記プログラムをここではip_cc.pyという名前にし実行します。使い方は引数にIPアドレスを指定します。下のように国名とネットワークを表示します。
公開されているgoogleのDNSのIPアドレスを指定してみます。
python ./ip_cc.py 8.8.8.8
8.8.8.8 -> US,8.0.0.0/9
公開されているgoogle botのIPアドレスを複数指定してみます。
python ./ip_cc.py 8.8.8.8 66.249.79.96 66.249.64.192
8.8.8.8 -> US,8.0.0.0/9
66.249.79.96 -> US,66.249.64.0/19
66.249.64.192 -> US,66.249.64.0/19
GeoLite2と結果を比較
前回の記事で記載したGeoLite2の出力結果と比較してみます。コードはこんな感じです。
import geoip2.database
import sys
db_path = '/path/to/GeoLite2-Country.mmdb'
ips = sys.argv[1:]
with geoip2.database.Reader(db_path) as reader:
for ip in ips:
response = reader.country(ip)
print(ip, end=",")
print(response.country.iso_code, end=",")
print(response.country.name, end=",")
print(response.traits.network)
まずは、GeoLite2でgoogleのDNSのIPアドレスを調べてみます。
python geoLite2_country_argv.py 8.8.8.8 8.8.4.4
8.8.8.8,US,United States,8.8.0.0/15
8.8.4.4,US,United States,8.8.0.0/15
国はUSでネットワークは8.8.0.0/15と出力されました。
次にこの記事のコードで調べてみます。
python ./ip_cc.py 8.8.8.8 8.8.4.4
8.8.8.8 -> US,8.0.0.0/9
8.8.4.4 -> US,8.0.0.0/9
国はUSでネットワークは8.0.0.0/9と出力されました。
ん〜、どっちが正しいのかRIRのファイルで直接しらべてみました。
grep 'ipv4|8.0.0.0' delegated-*
delegated-arin-extended-latest:arin|US|ipv4|8.0.0.0|8388608|19921201|allocated|e5e3b9c13678dfc483fb1f819d70883c
上のように確かにRIRのデータには8.0.0.0から8,388,608個(/9)のIPアドレスであることがわかります。GeoLite2が古いデータのようです。
少し調べていたらip2ccというコマンドを発見。これは知らなかった。ただ2013年のデータベースらしいので相当古いようです。
ip2cc 8.8.8.8
IP::Country modules (v2.28)
Copyright (c) 2002-13 Nigel Wetters Gourlay
Database updated Wed May 15 15:29:48 2013
Address: 8.8.8.8
Country: US (United States)
最後に
最後まで読んでいただきありがとうございます。今回の【Python】IPアドレスから国を確認する(pandas編)はいかがでしたでしょうか。RIRのデータでpandasを使ってIPアドレスから国を確認してみました。アクセスログからIPアドレスをgrepしてxargsで今回のプログラムに引数で渡すと便利に使えそうです。

\無料相談もできます/
・現役エンジニアから学べるオンラインに特化したプログラミングスクール。
・講師は全員、通過率10%の選考に合格した現役エンジニア。
・確かなスキルをもとにマンツーマンサポート。
・900社、30,000名を超える教育実績
※受講料最大70%支給
・Pythonを使ってデータ分析の手法を習得。
・1人では続かない方のためのパーソナルメンターがつく学習プログラム。
・統計学の基礎やPythonで実際に分析する方法まで習得することができます。
・統計学を基礎から学びたい方
・データサイエンティストとして活躍したい方
・Pythonのライブラリを使用して実装を行いたい方
・時間と場所にとらわれない働き方をしたい方
・区間推定、仮説検定による母集団の検証:乱数データを用いて古典的統計解析手法を習得
・住宅価格の予測:統計モデリングの基礎を習得
・サッカーの勝敗予測:ポアソン回帰により一般化線形モデルの基礎を習得
・オリジナルのデータ解析:公開されているデータセットを使ってデータ解析
・Python
・Numpy
・Pandas
・scikit-learn
\無料相談もできます/
MacやLinux、Pythonなど技術系のkindle本も豊富にあります。詳しくはこちらから。
Amazonの電子書籍読み放題サービス「Kindle Unlimited」でプライム会員を対象に、最初の3か月間を無料体験できるキャンペーンを実施中。マンガ、小説、ビジネス書、雑誌など500万冊から、好きな本を何冊でも読めるキャンペーンです。
初めてkindle unlimited 読み放題をご利用の方は30日間の無料で体験できます。
期間終了後は月額980円で、いつでもキャンセルできます。
200万冊以上が読み放題。お好きな端末で利用可能です。
