python3--数据可视化-破解IP查询接口 将6万个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地址归属地、运营商信息使用空格分隔,请求接口为:
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图可以到蓝奏云下载。思路、代码方面有什么不足欢迎各位大佬指正、批评!觉得还可以的能点个赞嘛。
目录 返回
首页