Amazon オーディブル2ヶ月無料キャンペーン中 5/9まで

【Python】IPアドレスから国を確認する(pandas編)

9 min

こんにちは。ナミレリです。みなさん、MacでPythonは使っていますか?

アクセスログのIPアドレスから国をサクッと調べたいときってありますよね。前回は無料のGeoLite2を使ってPythonでIPアドレスから国を確認する記事を書きました。GeoLite2を使いたい方はぜひ下の記事も参照ください。

今回はGeoLite2を使わずにpandasを使ってIPアドレスから国を確認してみます。やっていて気づきましたが、割と頻繁に地域インターネットレジストリ(RIR)から公開されているIPアドレスデータに変更があります。GeoLite2で国を確認するとフランス、RIRの最新データで確認するとデンマーク、なんてこともありましたし、サブネット(サブネットマスク)もGeoLite2とRIRの最新データで差分がありました。GeoLite2は無料で利用できるデータなので更新頻度が低いということだと思います。

という状況の気づきもあり、今回はpandasを使ってRIRのデータでIPアドレスから国を確認することをやってみます。

この記事はこんな人にオススメ

  • コマンドラインでIPアドレスから国を確認したい
  • 複数のIPアドレスから一気に国を確認したい
  • しかも無料で確認したい
  • Pythonのpandasを使って勉強のためにも自分で作ってみたい
この記事のMac環境
  • 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
Parallels 19 for Macの無料トライアル もありますので、ぜひダウンロードして試してみてください。M1/M2/M3のMac上で快適にMacやUbuntu、Windowsが動作します。
NEW Parallels Desktop 19 for Mac

Parallels Desktop 19 for Macは、M1/M2/M3のMac上で快適にMacやUbuntu、Windowsが動作します。

14日間の無料トライアルもありますので、ぜひダウンロードして試してみてください。

IPアドレス割り振りの仕組みを理解する

前回の記事でも書いていますが少しおさらいすると、世界のIPアドレスはICANNによってい管理されています。このICANNがIPアドレスを世界に5つある地域インターネットレジストリ(Regional Internet Registry:RIR)に割り振り、このRIR(下図参照)がさらに各国に割り振り管理されています。

地域名称
北アメリカAmerican Registry for Internet NumbersARIN
ヨーロッパ、 中東 、中央アジアRIPE Network Coordination CentreRIPE NCC
アジア・太平洋地域Asia-Pacific Network Information Centre APNIC
南アメリカ とカリブ海地域Latin American and Caribbean Internet Address Registry LACNIC
アフリカAfrican Network Information CentreAfriNIC
表:世界に5つある地域インターネットレジストリ
Amazonの読み放題・聴き放題

kindle unlimited 読み放題
200万冊以上が読み放題

Audible
12万以上の対象作品が聴き放題

Amazon オーディブル:2ヶ月無料キャンペーン中(5/9まで)→ 詳しくはこちら

RIRが公開しているIPアドレス割り振りデータ

RIRが各国に割り振りしたIPアドレスをサイトに公開しています。アジア・太平洋地域の各国にIPアドレスを割り振るAPNICのサーバから、世界に5つあるRIRの各データがダウンロードできます。

地域FTP(最新IPアドレスデータ)
北アメリカARINhttps://ftp.apnic.net/stats/arin/delegated-arin-extended-latest
ヨーロッパ、 中東 、中央アジアRIPE NCChttps://ftp.apnic.net/stats/ripe-ncc/delegated-ripencc-latest
アジア・太平洋地域APNIChttps://ftp.apnic.net/stats/apnic/delegated-apnic-latest
南アメリカ とカリブ海地域LACNIChttps://ftp.apnic.net/stats/lacnic/delegated-lacnic-latest
アフリカAfriNIChttps://ftp.apnic.net/stats/afrinic/delegated-afrinic-latest
表:世界に5つある地域インターネットレジストリの最新データ

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

項目意味
registryapnic地域インターネットレジストリ(RIR)
ccJPISO 3166の国コード
typeipv4ipv4, ipv6, asnのどれかが入ります
start223.252.112.0開始のIPアドレス(ネットワークアドレス)
value4096IPアドレスの個数
date20100727割り当てた年月日(YYYMMDD形式)
statusallocatedallocated, assignedのどちらかのステータス
extensionsA918B936extendedフォーマットのみ
表:世界に5つある地域インターネットレジストリの最新データ

ここまでは前回のおさらいですが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アドレスから国を確認するプログラム

pandaspathlibipaddressのライブラリを使い以下のように書いてみました。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

Amazonの読み放題・聴き放題

kindle unlimited 読み放題
200万冊以上が読み放題

Audible
12万以上の対象作品が聴き放題

Amazon オーディブル:2ヶ月無料キャンペーン中(5/9まで)→ 詳しくはこちら

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本も豊富にあります。詳しくはこちらから。

初めてkindle unlimited 読み放題をご利用の方は30日間の無料で体験できます。
期間終了後は月額980円で、いつでもキャンセルできます。
200万冊以上が読み放題。お好きな端末で利用可能です。

定番おすすめ記事

関連記事