最近在学习数据可视化知识,就拿了小时候玩的洛克王国练了练手,爬取每个精灵的各项属性数据,存入到数据库中,并用flask框架进行可视化出来。

1.首先分析一下整个页面,所有的精灵信息存储在一个ul标签中,并且每个精灵详细信息的url放在这个a标签里,所以第一步就是先提取每个精灵具体信息页面的url

    def parse(self,soup):
        for i in soup.find_all('ul', id="cwdz_list"):
            newurls = re.findall('<a href="/luoke/luokechongwu/(.*?).html">', str(i))
            return newurls

2.提取到每个精灵的详细url后,分析详细页面,这里每个精灵的各项基础属性值及最大属性值都放在了这个tbody里,然后我们通过bs4库和正则把我们需要的信息提取出来,这里代码写的比较臃肿,因为我水平还不够,嘿嘿

    def NewRespon(self,url):
        r1 = requests.get(url, headers=self.headers)
        r1.encoding = 'gb2312'
        soup = BeautifulSoup(r1.text, 'html.parser')
        for i in soup.find_all('div', 'netab cf'):
            list1 = []
            for j in i.find_all('tbody'):
                list1.append(list(j.children))
        if len(list1) <= 1:
            return
        item = list1[1]
        if len(item) <= 7:
            return
        info = re.findall('<td class="td1">([\u4e00-\u9fa5]+)</td>', str(item[3]))
        infoName = re.findall('<td>([\u4e00-\u9fa5]+)</td>', str(item[5]))
        if len(infoName) == 0:
            return
        infoAttrs = re.findall('<td>(\d+)</td>', str(item[5]))
        infoMax = re.findall('<td>(\d+)</td>', str(item[7]))
        if len(infoMax) == 0:
            return
        return infoName,infoAttrs,infoMax

 3.到这里,我们已经基本完成了爬虫的部分,下面把获取来的数据用键值对的方式存储起来,并转换称json格式,这里搞一下每个精灵的存储结构,之后用json库中的dumps方法存储为json文件

itemData = {
            'name': '',
            'leixing': '',
            'energy': {
                'min': '',
                'max': ''
            },
            'attack': {
                'min': '',
                'max': ''
            },
            'defense': {
                'min': '',
                'max': ''
            },
            'speed': {
                'min': '',
                'max': ''
            },
            'MagicAttack': {
                'min': '',
                'max': ''
            },
            'MagicDefense': {
                'min': '',
                'max': ''
            },
            'sum': {
                'min': '',
                'max': ''
            },
        }

 4.这个时候,我们就把我们的json文件里的信息存入到数据库中,先用json库中load方法把json文件转换成键值对形式,然后连接数据库并存入

with open('./items.json', 'r',encoding='utf-8') as f:
    a = json.load(f)
print('数据解析完成!')
mydb = pymysql.connect(
    host="localhost",
    user="root",
    passwd="root",
    database="xk" # 用这个表
)
mycursor = mydb.cursor()
print('数据库链接OK!')
mycursor.execute('create table GenieInfo (name VARCHAR(255), PRIMARY KEY(name),leixing VARCHAR(255),EnergyMin VARCHAR(255),EnergyMax VARCHAR(255),AttackMin VARCHAR(255),AttackMax VARCHAR(255),DefenseMin VARCHAR(255),DefenseMax VARCHAR(255),SpeedMin VARCHAR(255),SpeedMax VARCHAR(255),MagicAttackMin VARCHAR(255),MagicAttackMax VARCHAR(255),MagicDefenseMin VARCHAR(255),MagicDefenseMax VARCHAR(255),SumMin VARCHAR(255),SumMax VARCHAR(255));')
print('数据表建成功')
print('开始添加数据!')
for i in a:
    sql = "INSERT INTO GenieInfo (name,leixing,EnergyMin,EnergyMax,AttackMin,AttackMax,DefenseMin,DefenseMax,SpeedMin,SpeedMax,MagicAttackMin,MagicAttackMax,MagicDefenseMin,MagicDefenseMax,SumMin,SumMax) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
    val = (i['name'],i['leixing'],i['energy']['min'],i['energy']['max'],i['attack']['min'],i['attack']['max'],i['defense']['min'],i['defense']['max'],i['speed']['min'],i['speed']['max'],i['MagicAttack']['min'],i['MagicAttack']['max'],i['MagicDefense']['min'],i['MagicDefense']['max'],i['sum']['min'],i['sum']['max'])
    mycursor.execute(sql, val)
    mydb.commit()
print('数据保存成功!')

 

5.这个时候,我们的信息已经都放好了,那现在就开始搭建一个flask框架,因为flask本身并不支持连接数据库,所以我们使用了Flask-SQLAlchemy这个扩展包,SQLALCHEMY_DATABASE_URI变量中获取数据库的位置,然后实例化对象,有个要注意的是,这里数据表中必须要有主键,不然会报错

app.config['SQLALCHEMY_DATABASE_URI']=\
    'mysql://root:root@localhost/xk'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False
db = SQLAlchemy(app)

class gen(db.Model):
    __tablename__ = 'genieinfo'
    name = db.Column(db.String(64),primary_key=True)
    leixing = db.Column(db.String(64))
    EnergyMin = db.Column(db.String(64))
    EnergyMax = db.Column(db.String(64))
    AttackMin = db.Column(db.String(64))
    AttackMax = db.Column(db.String(64))
    DefenseMin = db.Column(db.String(64))
    DefenseMax = db.Column(db.String(64))
    SpeedMin = db.Column(db.String(64))
    SpeedMax = db.Column(db.String(64))
    MagicAttackMin = db.Column(db.String(64))
    MagicAttackMax = db.Column(db.String(64))
    MagicDefenseMin = db.Column(db.String(64))
    MagicDefenseMax = db.Column(db.String(64))
    SumMin = db.Column(db.String(64))
    SumMax = db.Column(db.String(64))

6.连接上数据库之后,不着急继续往下做,我们先建一个echarts的前端可视化出来,我的设想是做两个页面,一个是每个精灵的各项数据对比,一个是两个精灵的基础数据和满值数据对比,图形上我选择了基本的雷达图和折线柱状图,建立一个echarts首要的是 一个dom容器 然后配置项,实例化,具体每种可以去echarts官网查看样例,非常全,嘿嘿 ,这个是我的可视化的配置项代码

 <script>
        (function() {
            var MyChart = echarts.init(document.querySelector(".box"));
            var option = {
                title: {
                    text: '{{n1}}、{{n2}}的基础属性对比',
                    show: true
                },
                color:['green','red'],
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross',
                        crossStyle: {
                            color: 'red',
                            width: 2
                        }
                    }
                },
                legend: {

                },
                grid: {
                    left: '15%',
                    right: '15%',
                    bottom: '10%',
                    top: '10%',
                    containLabel: true
                },
                xAxis: {
                    type: 'category',
                    boundaryGap: false,
                    data: ['血量','攻击','防御', '速度','魔攻','魔抗']
                },
                yAxis: {
                    type: 'value',
                    name: ''
                },
                series: [{
                    name: '{{n1}}',
                    type: 'line',
                    data: {{min1 | safe}},
                    label: {
                        show: true
                    },
                    emphasis: {
                        focus: 'series'
                    },
                }, {
                    name: '{{n2}}',
                    type: 'line',
                    data: {{min2 | safe}},
                    label: {
                        show: true
                    },
                    emphasis: {
                        focus: 'series'
                    },
                }]
            };
            MyChart.setOption(option);
        })();
        (function(){
            var MyChart = echarts.init(document.querySelector(".box1"));
            var option = {
                 title: {
                    text: '{{n1}}、{{n2}}的满属性对比',
                    show:true
                 },
                 legend: {
                    data: ['{{n1}}', '{{n2}}']
                 },
                 color:['green','red'],
                 radar: {
                    indicator: [
                      { name: '血量', max: 500 },
                      { name: '攻击', max: 500 },
                      { name: '防御', max: 500 },
                      { name: '速度', max: 500 },
                      { name: '魔攻', max: 500 },
                      { name: '魔抗', max: 500 }
                    ]
                 },
                 series: [
                    {
                      name: '',
                      type: 'radar',
                      data: [
                        {
                          value: {{max1 | safe}},
                          name: '{{n1}}'
                        },
                        {
                          value: {{max2 | safe}},
                          name: '{{n2}}'
                        }
                      ]
                    }
                 ]
            };
            MyChart.setOption(option);
        })();
    </script>

7.我们把可视化的页面做好之后,就差最后一步,往里面填充数据,我直接把数据库里的信息往前端页面送就完事了,有一个要注意的是,数据库里的信息在传的时候,可能会有空格 这就会导致配置项中不能识别数据,解决办法在变量名后面加个safe {{ 变量名 | safe }}

@app.route('/<name>')
def search(name):
    x = gen.query.filter(gen.name==name).first()
    n1=x.name
    min1=[x.EnergyMin,x.AttackMin,x.DefenseMin,x.SpeedMin,x.MagicAttackMin,x.MagicDefenseMin]
    max1=[x.EnergyMax,x.AttackMax,x.DefenseMax,x.SpeedMax,x.MagicAttackMax,x.MagicDefenseMax]
    return render_template('lineBar.html',n=n1,min1=min1,max1=max1)

@app.route('/<name>/<name1>')
def compare(name,name1):
    x = gen.query.filter(gen.name == name).first()
    n1 = x.name
    max1 = [x.EnergyMax, x.AttackMax, x.DefenseMax, x.SpeedMax, x.MagicAttackMax, x.MagicDefenseMax]
    min1 = [x.EnergyMin, x.AttackMin, x.DefenseMin, x.SpeedMin, x.MagicAttackMin, x.MagicDefenseMin]

    y = gen.query.filter(gen.name == name1).first()
    n2 = y.name
    max2 = [y.EnergyMax, y.AttackMax, y.DefenseMax, y.SpeedMax, y.MagicAttackMax, y.MagicDefenseMax]
    min2 = [y.EnergyMin, y.AttackMin, y.DefenseMin, y.SpeedMin, y.MagicAttackMin, y.MagicDefenseMin]
    return render_template('pie.html',n1=n1,n2=n2,max1=max1,max2=max2,min1=min1,min2=min2)

8.完事具备,直接开始run,尝试了一下,非常ok,当传入一个精灵名称的时候就是这个精灵的各项属性各时期的对比,当传入两个精灵名字的时候就是两个精灵的各项属性对比,

 9. 完美撒花

 

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐