用python为网站画一张用户分布地图

我的个人博客网站coolpython.net上线已经有将近两年的时间了,一直都想画一张用户分布的地图,今天终于完成了,效果图如下
python 地图
本文记录下地图的制作过程

1. 第一步,提取用户ip

我的网站是用python编写的,使用uwsgi部署,会产生一个名为uwsgi.log的日志文件,记录的内容如下

[pid: 4758|app: 0|req: 62019/129930] 113.110.227.224 () {42 vars in 930 bytes} [Mon Jun  7 16:21:15 2021] GET /static/public/pic/favicon.ico => generated 771 bytes in 1 msecs via sendfile() (HTTP/1.1 200) 8 headers in 306 bytes (0 switches on core 0)
[pid: 4758|app: 0|req: 62020/129931] 223.80.104.104 () {42 vars in 1018 bytes} [Mon Jun  7 16:21:20 2021] GET /python_senior/concurrent/multithreading_lock.html => generated 10024 bytes in 4 msecs (HTTP/1.1 200) 4 headers in 129 bytes (1 switches on core 0)
[pid: 4758|app: 0|req: 62021/129932] 223.80.104.104 () {44 vars in 1097 bytes} [Mon Jun  7 16:21:24 2021] GET /python_primary/python_primary_tutorial.html => generated 10245 bytes in 3 msecs (HTTP/1.1 200) 4 headers in 129 bytes (1 switches on core 0)

使用awk 可以很容易提取出用户的ip地址

cat uwsgi.log | grep "\[pid:" | awk '!a[$5]++{print $5}' > ip.txt

2. 获取ip地址的地理坐标

这一步,我使用geoip2,安装方式如下

pip install geoip2

除了需要安装这个库外,还需要下载地图数据,无奈官网上招不到注册的入口,我只好在csdn上花了很多积分下载了一份,免费分享给你

链接:https://pan.baidu.com/s/188Hkgl9p2JRZ_JN9apW8KQ 
提取码:2gwi 

这个库的使用非常方便

import geoip2.database
client = geoip2.database.Reader('./GeoLite2-City.mmdb')
response = client.city('178.128.196.128')
print(response.country.iso_code)    # 国际标准码中的位置
print(response.location.latitude)   # 维度
print(response.location.longitude)   # 经度
print(response.location.time_zone)   # 时区
print(response.city.name)  # 城市 Saint Paul
print(response)   # 更多参考 ↓

3. 绘制地图

绘制地图,需要使用到matplotlib和mpl_toolkits.basemap, 后者需要使用conda安装

conda install basemap

全部代码如下

import matplotlib
# Anti-Grain Geometry (AGG) backend so PyGeoIpMap can be used 'headless'
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import geoip2.database

client = geoip2.database.Reader('./GeoLite2-City.mmdb')

def generate_map(output, lats=[], lons=[]):
    m = Basemap(projection='cyl', resolution='l')
    m.bluemarble()
    x, y = m(lons, lats)
    m.scatter(x, y, s=1, color='#ff0000', marker='o', alpha=0.3)
    plt.savefig(output, dpi=300, bbox_inches='tight')


def read_ip():
    ip_lst = []
    with open('ip.txt')as f:
        for line in f:
            ip_lst.append(line.strip())

    return ip_lst


def geoip_lat_lon(ip_lst):
    lats, lons = [], []
    for ip in ip_lst:
        try:
            response = client.city(ip)
        except:
            continue
        lats.append(response.location.latitude)
        lons.append(response.location.longitude)

    return lats, lons


def run():
    ip_lst = read_ip()
    lats, lons = geoip_lat_lon(ip_lst)
    generate_map('web.png', lats, lons)


run()

观察地图,有一点让我感到惊讶,访问我网站的用户中,有很多是在国外的,难不成都是留学生。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案