試したい方はこちらから
https://geoip2-demo.onrender.com/
データベースの入手
データベースは無料で入手できますが、登録が必要です。
まずは以下からサインアップしてください。
登録には以下のフォームを埋める必要がありますが、適当でも大丈夫です。すぐに使えるようになりました。
- Full name
- Company
- Industry
- Country Intended use
- How you plan to use the geolocation data
- Email address Please provide a valid email address. This will become your username.
- Phone (optional)
- How do you plan to use the data?
メールアドレスにパスワード設定のメールが来るのでパスワードを設定します。
そしてデータベースをダウンロードします。
gradioで描画する
gradioとgeoip2をインストールします。
pip install gradio geoip2
IPアドレスのASを知るデータベースとどこにIPアドレスがあるかのデータベースは別れていますので別々に読み込みます。
subdivisionsはあったりなかったり、あっても日本語がなかったりします。なかったら英語を使うようにします。
import geoip2.database
import gradio as gr
asn_db = "./GeoLite2-ASN.mmdb"
city_db = "./GeoLite2-City.mmdb"
def get_asn(ip_address: str):
with geoip2.database.Reader(asn_db) as reader:
return reader.asn(ip_address)
def get_city(ip_address: str):
with geoip2.database.Reader(city_db) as reader:
return reader.city(ip_address)
def main(ip_address):
asn = get_asn(ip_address)
city = get_city(ip_address)
return {
"AS管理組織": asn.autonomous_system_organization,
"大陸": city.continent.names["ja"],
"国": city.country.names["ja"],
"緯度": city.location.latitude,
"経度": city.location.longitude,
"精度": city.location.accuracy_radius,
"登録国": city.registered_country.names["ja"],
"細分": list(map(lambda x: x.names["ja"] or x.names["en"], city.subdivisions)),
"IPアドレス": city.traits.ip_address,
}
gradioで描画します。
demo = gr.Interface(fn=main, inputs="text", outputs="json")
demo.launch(share=True)
これで好きなIPアドレスを入れて遊ぶことができます。
これを早速pythonanywhereで動かそうと思いましたが以下の問題が発生しました。
- gradioを直接動かしても反応がない
- gradioにはgunicornの後ろで動かす方法がない
- ならばfastapiの後ろで動かそうとしてもpythonanywhereではサポートしていない(https://www.pythonanywhere.com/forums/topic/32484/)
というわけで代替サービスを探したところrender.comにいきつきました。
ただこれもgradioを直接動かせないのでfastapiの後ろで動かします。
gradioのところをいかに書き直します。
from fastapi import FastAPI
app = FastAPI()
io = gr.Interface(fn=main, inputs="text", outputs="json")
app = gr.mount_gradio_app(app, io, path="/")
それでも以下のエラーが置きます。
"POST /run/predict HTTP/1.1" 422 Unprocessable Entity
{"detail":[{"type":"missing","loc":["body","event_id"],"msg":"Field required","input":{"data":["1.2.3.4"],"event_data":null,"fn_index":0,"session_hash":"w1mt4r43ag"},"url":"https://errors.pydantic.dev/2.1.2/v/missing"}]}
pydanticのバージョン違いのようです。
requirements.txtに以下を追記します。
pydantic==1.10.11
最終的なコードは以下のとおりです。
.
├── GeoLite2-ASN.mmdb
├── GeoLite2-City.mmdb
├── main.py
└── requirements.txt
import geoip2.database
import gradio as gr
from fastapi import FastAPI
asn_db='./GeoLite2-ASN.mmdb'
city_db='./GeoLite2-City.mmdb'
def get_asn(ip_address:str):
with geoip2.database.Reader(asn_db) as reader:
return reader.asn(ip_address)
def get_city(ip_address:str):
with geoip2.database.Reader(city_db) as reader:
return reader.city(ip_address)
def main(ip_address):
asn=get_asn(ip_address)
city=get_city(ip_address)
return {
"AS管理組織":asn.autonomous_system_organization,
"大陸":city.continent.names['ja'],
"国":city.country.names['ja'],
"緯度":city.location.latitude,
"経度":city.location.longitude,
"精度":city.location.accuracy_radius,
"登録国":city.registered_country.names['ja'],
"細分":list(map(lambda x:x.names['ja'] or x.names['en'],city.subdivisions)),
"IPアドレス":city.traits.ip_address,
}
app = FastAPI()
io = gr.Interface(fn=main, inputs="text", outputs="json")
app = gr.mount_gradio_app(app, io, path="/")
pydantic==1.10.11
geoip2
gradio
fastapi
uvicorn
render.comの設定には名前を入力し、Start Commandには以下のコマンドを入れて、その他はデフォルトにしてください。
uvicorn main:app --host 0.0.0.0
デプロイするとgradioが使えるようになります。