面子工程之IP數據可視化

前言

我很在乎的一件事情是好看,嗯,好看.以及是否有趣.雖然不必定有用.html

下面是效果圖,因爲數據量有限,因此還不夠眼花繚亂.python

面子工程之IP數據可視化

面子工程之IP數據可視化

本文的主要內容是經過echarts,threejs將web日誌或者任何含有IP數據的文本文件可視化.簡單的來講,裝逼,能夠將這個動態圖放在大屏幕上.git

全部源碼及相關數據文件請訪問下面github倉庫
https://github.com/youerning/blog/tree/master/ip-visualizegithub

前提條件

  • 熟悉python及框架flask
  • 熟悉JavaScript

獲取數據

IP數據

數據獲取方式web

  • 日誌文件
  • elk三件套
  • 其餘

歸根結底數據最終來自日誌文件, 這裏主要指web日誌。ajax

這裏使用我本身網站的web日誌,格式以下.正則表達式

'116.24.64.239 - - [12/Mar/2018:18:58:40 +0800] "GET /example HTTP/2.0" 502 365\n'
...
'116.24.64.239 - - [12/Mar/2018:18:54:55 +0800] "GET / HTTP/2.0" 200 1603\n'

經過下面代碼將IP地址拿出來.數據庫

# 打開日誌文件
fp = open("website.log")

# 建立ip集合,因爲這裏只須要IP地址,因此用集合的特性去重
ip_set = set()

# 經過循環每次讀取日誌一行,若是日誌量大建議如下方式,日誌文件不大,能夠直接readlines,一次性所有讀取出來,
while True:
    line = fp.readline()
    if len(line.strip()) < 1:
        break
    ip = line.split()[0]
    ip_set.add(ip)

# 訪問用戶IP的個數
len(ip_set)

# 查看前20個IP
list(ip_set)[:20]
['111.206.36.133',
 '220.181.108.183',
 '40.77.178.63',
 '220.181.108.146',
 '119.147.207.152',
 '112.97.63.49',
 '66.249.64.16',
 '138.246.253.19',
 '123.125.67.164',
 '40.77.179.59',
 '66.249.69.170',
 '119.147.207.144',
 '66.249.79.108',
 '157.55.39.23',
 '123.125.71.80',
 '42.236.10.84',
 '123.125.71.79',
 '111.206.36.10',
 '106.11.152.155',
 '66.249.66.148']

不過爲了使用普遍這裏使用正則表達式.
import re
pat = "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
ipfind = re.compile(pat)

line = '116.24.64.239 - - [12/Mar/2018:18:54:55 +0800] "GET / HTTP/2.0" 200 1603\n'

ip = ipfind.findall(line)
if ip:
    ip = ip[0]
    print(ip)

下面是完整步驟
    # 建立ip列表
    ip_lis = list()

    # files of logs
    files = glob("logs/*")

    # complie regex
    pat = "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
    ipfind = re.compile(pat)

    # extract ip from  every file
    for logfile in files:
        with open(logfile) as fp:
            # 經過循環每次讀取日誌一行,若是日誌量大建議如下方式,日誌文件不大,能夠直接readlines,一次性所有讀取出來
            # 若是太大則用readline一行一行的讀

            lines = fp.readlines()
            for line in lines:
                if len(line.strip()) < 1:
                    continue
                ip = ipfind.findall(line)
                if ip:
                    ip = ip[0]
                    ip_lis.append(ip)

至此,咱們將訪問文件裏面的的IP拿出來了。json

值得注意的是: 若是你有搭建elk之類的日誌集羣,那麼獲取數據會更簡單更快,只是方式不一樣而已.這裏就不贅述了.flask

IP地址的地理信息

若是隻是拿到IP數據,在本文並無用,由於爲了在地圖上可視化每個IP的位置,咱們須要知道每一個IP地址的地理信息,即,經緯度,所在城市等。

這裏使用dev.maxmind.com提供的開源免費的geoip數據庫.

下載地址: https://dev.maxmind.com/geoip/geoip2/geolite2/

這裏不保證IP地址對應的位置信息絕對正確。爲了保證IP地址的準確性,能夠搜索在線的Geo服務。

爲了使用上面下載的數據庫,首先得下載相應的模塊.

pip install geoip2

經過下面代碼獲取指定IP的地理信息

# 導入相應模塊
import geoip2.database

# 記載下載的數據庫文件路徑,這裏是在代碼執行的工做目錄
reader = geoip2.database.Reader("GeoLite2-City.mmdb")

response = reader.city("61.141.65.76")

# 查看國家名
response.country.name
Out[115]: 'China'

# 查看城市名
response.city.name
Out[116]: 'Shenzhen'

response.city.names["zh-CN"]
Out[117]: '深圳市'

# 查看經緯度
response.location.latitude
Out[118]: 22.5333

response.location.longitude
Out[119]: 114.1333

上面只是用geoip2這個庫查看城市,國家, 經緯度,更多信息可本身探索.

處理數據

在處理數據以前,咱們要知道,咱們要處理成什麼數據格式,因爲畫圖是一件很費時費力的工做,這裏藉助的是這個echarts的demo,地址以下:
http://echarts.baidu.com/examples/editor.html?c=lines3d-flights&gl=1

該demo的數據源以下:
http://echarts.baidu.com/examples/data-gl/asset/data/flights.json

數據結構大體以下。

面子工程之IP數據可視化

可是這個格式實在是有點讓人誤導
經過閱讀demo的js代碼,你會發現,繪製飛線的數據格式爲:
[[[源緯度數據點, 源經度數據點], [目標維度數據點, 目標經度數據點]]..]

而threejs所需的數據格式號以下

var data = [
    [
    'seriesA', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
    ],
    [
    'seriesB', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
    ]
];

關於echarts官網demo的解讀能夠在下面地址查看.
https://github.com/youerning/blog/blob/master/ip-visualize/ipvis/prototype/lines3d-flights.html

代碼插入太多太佔篇幅。

數據處理以下

from functools import lru_cache

@lru_cache(maxsize=512)
def get_info(ip):
    """
    return info of ip

    Returns:
        city, country, sourceCoord, destCoord
    """
    try:
        resp = reader.city(ip)
        city = resp.city.name
        if not city:
            city = "unknow"
        country = resp.country.names["zh-CN"]
        if not country:
            country = "unknow"
    except Exception as e:
        print("the ip is bad: {}".format(ip))
        print("=" * 30)
        print(e)
        return False

    sourceCoord = [resp.location.longitude, resp.location.latitude]
    return city, country, sourceCoord, destCoord

# ip_Lis爲上面獲取的IP地址列表
ipinfo_lis = [get_info(ip) for ip in ip_lis]

可視化數據

在處理完數據以後就能夠經過一個接口暴露數據,這裏使用json數據格式.
而後經過ajax獲取數據.

數據實時更新

這裏只說思路

  • 日誌文件

    主要是經過python的文件對象的文件位置做爲數據是否有新內容寫入,若是有就讀入,加載數據到暴露的數據接口

  • elk stack
    這個就比較簡單了,定時查詢數據

demo使用教程

#安裝依賴
pip install flask, geoip2

# 下載源代碼

# 進入到ipvis目錄

# 將含有日誌文件放到logs目錄下
# 啓動
python app.py

# 訪問web
http://127.0.0.1/p1
http://127.0.0.1/p2

值得注意的是geoip自定義的數據庫查詢並非很是的快,因此當你訪問頁面的時候會感受比較慢,主要是ip數據的查詢耗時過久, 1.8w條數據大概查詢14秒左右

還有就是echarts這個庫可能有性能問題(至少是這個球形圖的時候,即時是官方網站的官方demo),由於當你打開http://127.0.0.1/p1的時候,可能cpu飆升到100%

不足之處

  • 不能實時加載數據
  • 數據量過大有性能問題
  • IP數據分類不夠細化
  • 圖表不夠健全

總結

一個僅僅於我而言有意思的小項目。不肯定大家有沒有更多的有意思的想法.

相關文章
相關標籤/搜索