文章目錄
- 一.準備作業
- 二.思路
- 1.整體思路
- 2.爬蟲思路
- 3.爬蟲實作
- 三.效果展示
- 1.資料庫
- 2.IP地址分類分析-餅圖
- 3.IP地址分布可視化-地圖
- 4.IP地址分布分析-餅圖
- 5.IP地址分布可視化-條形圖
- 6.IP地址運營商占比分析-餅圖
- 7.IP地址運營商占比可視化-條形圖
- 四.源代碼
- 1.get_ip_infos.py(IP地址資訊爬蟲)
- 2.analysis_ip_infos.py(IP地址資料可視化分析)
- 五.總結
本次先使用Python撰寫爬蟲,將爬取的資料存入資料庫最后使用pyecharts進行圖表的繪制,可視化地展示58677個IP地址,包括IP地址分類,IP地址歸屬地分布,IP地址運營商分布,
一.準備作業
整體操作是基于Python,我的環境:
- Python3.8
- JetBrains PyCharm 2018.2.2 x64
- pyecharts 1.9.0
二.思路
1.整體思路

2.爬蟲思路

這里說一句,資料抽取完了其實直接存入資料庫即可,我這里是先存入txt文本檔案,再讀取文本檔案寫入了excel中,最后手動匯入了MySQL資料庫,有些多此一舉了,
3.爬蟲實作
1.查找介面
在百度上搜索IP,百度會給我們提供一個IP138的查詢介面

在輸入框輸入IP,打開F12開發者工具,點擊查詢按鈕,

發現點完查詢按鈕后,瀏覽器向服務器發送了一個GET請求,服務器回傳了一串jQuery字串,其中data[0]中的location欄位為我們需要的IP地址歸屬地、運營商資訊使用空格分隔,請求介面為:
https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=8.8.8.8&co=&resource_id=5809&t=1636340450159&ie=utf8&oe=gbk&cb=op_aladdin_callback&format=json&tn=baidu&cb=jQuery1102030225422148935555_1636339389380&_=1636339389385
2.分析介面
對介面引數進行分析,具體操作步驟是:每次洗掉一組引數,然后放到瀏覽器去訪問,看服務器能否回傳需要的資料,
路徑:https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php
引數:
query: 8.8.8.8 (要查詢的IP地址,必傳)
co: (不知什么引數,可以不傳)
resource_id: 5809 (資源ID,必傳)
t: 1636341598109 (時間戳,可以不傳)
ie: utf8 (輸入編碼,可以不傳)
oe: gbk (輸出編碼,可以不傳)
cb: op_aladdin_callback (好像是回呼引數,可以不傳)
format: json (回傳值格式,可以不傳)
tn: baidu (提交搜索請求來源,可以不傳)
cb: jQuery1102030225422148935555_1636339389380 (回傳值型別,可以不傳)
_: 1636339389386 (也是時間戳,可以不傳)
3.確定介面
經過第二步的操作,得到一個可用的介面,回傳值型別為json字串:
https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=8.8.8.8&co=&resource_id=5809
放到瀏覽器訪問,能夠得到下圖中的結果:

(工具JSON-handle)
三.效果展示
1.資料庫
1.1資料表
資料表存盤了IP、IP歸屬地、IP運營商資訊,

1.2資料量
一共存盤了58677個IP地址資訊(去重后),

2.IP地址分類分析-餅圖

這里將所有IP地址進行劃分,分出來ABCDE類地址,劃分規則如下圖,可以看到A類地址占很大比例,

3.IP地址分布可視化-地圖

將IP地址歸屬地資訊可視化地標注在地圖上(對歸屬地在國外的IP不做分析展示),山東的IP地址較多,共有12805個,其次是廣東、香港,
4.IP地址分布分析-餅圖
什么,剛才的地圖你沒看出來廣東、香港占比大?請看這張圖,

5.IP地址分布可視化-條形圖

條形統計圖可以清楚地表明各種數量的多少,
6.IP地址運營商占比分析-餅圖

統計所有IP地址歸屬的運營商,通過上面的餅圖,能看到教育網占比最大,其次是電信、阿里云,
7.IP地址運營商占比可視化-條形圖

條形統計圖是用條形的長短來代表數量的大小,本文用于分析、展示IP運營商數量,
四.源代碼
1.get_ip_infos.py(IP地址資訊爬蟲)
#coding:utf-8
import requests
import json
import time
import re
import xlwt
"""
resource_id 引數很重要
"""
class IP_ana:
def read_txt(self,txt_file)->list:
"""
讀取檔案中的IP地址,去掉末尾的換行符
:param txt_file:
:return:
"""
with open(txt_file,'r',encoding="utf-8")as f:
data=[ip.strip() for ip in f.readlines()]
return data
def fmt_ip(self,ip)->str:
"""
對IP地址進行格式化,去掉其中的埠號
:param ip: 待處理的IP地址
:return: IPv4格式的IP地址
"""
regx="(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])"
if ":" in ip:
aim_ip=ip.split(":")[0]
else:
aim_ip=ip
if re.match(regx,aim_ip):
return aim_ip
else:
return False
def do_request(self,ip)->str:
"""
對介面進行訪問
:param ip: url必須引數
:return: 網頁源代碼
"""
try:
full_url=f"https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={ip}&co=&resource_id=5809"
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
}
r=requests.get(full_url,headers=headers)
if r.status_code==200:
html=r.text.encode('utf-8').decode('unicode_escape')
# print(html)
return html
except:
return False
def get_ip_attribute(self,html)->dict:
"""
獲取IP歸屬地
:param html:
:return:
"""
try:
item={}
_json=json.loads(html)
data=_json.get("data")
item['location'],item['ISP']=data[0].get("location").split(" ")
return item
except:
return False
def save_result(self,data)->None:
"""
存盤爬取結果
:param data:
:return:
"""
with open(aim_txt,'a',encoding='utf-8')as f:
f.write(data+'\n')
def write_to_excel(self,all_data)->None:
"""
寫入excel
:param all_data:
:return:
"""
workbook = xlwt.Workbook()
worksheet = workbook.add_sheet('sheet', cell_overwrite_ok=True)
headers = ['IP', '歸屬地', 'ISP', ]
worksheet.write(0, 0, headers[0])
worksheet.write(0, 1, headers[1])
worksheet.write(0, 2, headers[2])
for index, data in enumerate(all_data):
worksheet.write(index + 1, 0, data[0])
worksheet.write(index + 1, 1, data[1])
worksheet.write(index + 1, 2, data[2])
workbook.save(excel_path)
if __name__ == '__main__':
a=IP_ana()
all_ips=a.read_txt("test_ip.txt")
aim_txt="./2021-11-2_test_result.txt"
excel_path = "./combine_result.xls"
for ip in all_ips:
ip_fmt=a.fmt_ip(ip)
if ip_fmt:
ip_infos=a.do_request(ip_fmt)
if ip_infos:
item=a.get_ip_attribute(ip_infos)
if item:
data=ip_fmt+":\t"+item['location']+"\t"+item["ISP"]
print(data)
a.save_result(data)
else:
print(ip_fmt + ":\t" + "決議失敗!")
else:
print((ip_fmt + ":\t" + "獲取資訊失敗!"))
else:
print((ip + ":\t" + "不是標準IPv4格式!"))
#讀取txt,寫入excel
ip_data=a.read_txt(aim_txt)
excel_data_list=[]
for ip_data_ in ip_data:
ip_data_list=[ip_data_.strip().split("\t")]
excel_data_list.append(ip_data_list)
a.write_to_excel(excel_data_list)
2.analysis_ip_infos.py(IP地址資料可視化分析)
import pymysql
from pyecharts.charts import Map, Bar
from pyecharts.charts import Pie
from pyecharts import options as opts
from pyecharts.globals import ThemeType
"""
地圖:
餅圖:
地圖:
"""
def get_data_from_mysql():
"""
從資料庫獲取資料
:return:
"""
try:
conn=pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='root',
db='ip_count',
charset='utf8'
)
cursor=conn.cursor()
sql="select * from ip_count"
cursor.execute(sql)
data=cursor.fetchall()
return data
except pymysql.Error:
print("資料庫操作出現錯誤!")
finally:
cursor.close()
conn.close()
def sort_ip(data):
sort_result={}
sort_result["A類"]=0
sort_result["B類"]=0
sort_result["C類"]=0
sort_result["D類"]=0
sort_result["E類"]=0
for ip in data:
fisrt_num=ip.split('.')[0]
if 0<=int(fisrt_num)<=127:
sort_result["A類"]+=1
elif 128<=int(fisrt_num)<=191:
sort_result["B類"]+=1
elif 192<=int(fisrt_num)<=223:
sort_result["C類"]+=1
elif 224<=int(fisrt_num)<=239:
sort_result["D類"]+=1
elif 240<=int(fisrt_num)<=247:
sort_result["E類"]+=1
else:
print(ip)
return sort_result
def sort_provinces(data):
"""
對省份資訊進行分類排序
:param data:
:return:
"""
sort_result_item={}
Province_34 = ['北京', '上海', '海南', '貴州', '湖北', '重慶', '江蘇', '安徽', '澳門特別行政區', '四川', '江西', '浙江', '青海', '河南',
'天津', '臺灣', '湖南', '陜西', '黑龍江', '廣東', '香港', '河北', '遼寧', '福建', '廣西', '西藏', '內蒙古', '新疆', '云南',
'甘肅', '寧夏', '山西', '山東', '吉林']
provinces=[line[1] for line in data]
for line in provinces:
if line !=None:
for p in Province_34:
if p in line:
if p in sort_result_item.keys():
sort_result_item[p]+=1
else:
sort_result_item[p]=0
sort_result=sorted(sort_result_item.items(),key=lambda x:x[1],reverse=True)
return sort_result
def sort_ISP_data(data):
"""
對ISP資訊進行分類統計排序
:param data:
:return:
"""
data=[line[2] for line in data if line[2]!=None]
item={}
for isp in data:
if isp in item.keys():
item[isp]+=1
else:
item[isp] = 0
item_sorted=sorted(item.items(),key=lambda x:x[1],reverse=True)
return item_sorted
def draw_map(data):
"""
將分類好的省份資訊繪制成地圖
:param data:
:return:
"""
area1=[d[0] for d in data]
area2=[d[1] for d in data]
aim_num=max(area2)
num_max_pos = len(str(aim_num)) - 2
mid_num = divmod(aim_num, int("1" + "0" * num_max_pos))
res_num = str(mid_num[0] + 1) + "0" * (num_max_pos)
map =\
Map(init_opts=opts.InitOpts(width="1000px", height="600px"))\
.add("",[list(z) for z in zip(area1, area2)], 'china')\
.set_global_opts(title_opts=opts.TitleOpts(title="IP地址分布可視化-地圖")
,visualmap_opts = opts.VisualMapOpts(max_=res_num, split_number=8, is_piecewise=True,precision=0))
map.render("./IP地址分布可視化-地圖.html")
def draw_line(data,type_):
"""
將ISP和省份資訊繪制成條形圖
:param data:
:param type_:
:return:
"""
bar = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT)) #使用主題
.add_xaxis([data[0] for data in data])
.add_yaxis("占比",[data[1] for data in data])
.set_global_opts(
title_opts=opts.TitleOpts(title=f"IP地址{type_}可視化-條形圖.html"),
datazoom_opts=opts.DataZoomOpts(),
)
)
bar.render(f"IP地址{type_}可視化-條形圖.html")
def draw_pie(data,type_):
"""
將ISP和省份資訊繪制成餅圖
:param data:
:return:
"""
c = (
Pie()
.add(f"IP地址{type_}可視化", data,color = "green",rosetype = "radius")
.set_colors(["lightblue", "orange", "yellow", "blue", "pink", "green", "purple", "black"])
.set_global_opts(title_opts=opts.TitleOpts(title=f"IP地址{type_}可視化-餅圖"),legend_opts=opts.LegendOpts(
orient="vertical", #圖例垂直放置
pos_top="15%",# 圖例位置調整
pos_left="2%"),
)
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b} : {c} ({d}%)"))
.render(f"IP地址{type_}分析-餅圖.html")
)
if __name__ == '__main__':
data=get_data_from_mysql()
ip_data=[line[0] for line in data]
sort_ip_type_data=[(k,v) for k,v in sort_ip(ip_data).items()]
draw_pie(sort_ip_type_data,"分類")
ip_sort_res=sort_provinces(data)
draw_map(ip_sort_res)
draw_pie(ip_sort_res[:8],"分布")
draw_line(ip_sort_res[:8],"分布")
isp_sort_res=sort_ISP_data(data)
draw_pie(isp_sort_res[:8],"運營商占比")
draw_line(isp_sort_res[:8],"運營商占比")
五.總結
本次使用Python的pyecharts繪制了餅圖、條形圖、地圖,可視化地將IP地址歸屬地分布、運營商分布展示出來,代碼量不大,pyecharts中都給封裝好了,呼叫其中的介面函式就能夠輕易實作,希望大家也動手做起來,如果喜歡這些Echarts圖可以到藍奏云下載,思路、代碼方面有什么不足歡迎各位大佬指正、批評!覺得還可以的能點個贊嘛,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/353339.html
標籤:其他
上一篇:大規模路由綜合實驗
下一篇:萬字+圖片決議計算機網路運輸層
