ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

基于爬虫数据实现前端网页制作(学到很多!)

2021-06-26 17:01:13  阅读:214  来源: 互联网

标签:学到 function 网页 option res 爬虫 var scope data


目录

前言

上效果!

用户注册、登录网页

检索球队信息

图表制作:

柱状图展示的是各队伍的胜率信息:

饼状图展示的是各队伍的比赛场数

折线图展示的是各队伍的平均得分

管理员操作的实现

结语


前言

        几个月前,笔者发表了一篇爬虫的文章,爬取虎扑的NBA赛事信息(传送门)。但这么多数据只能自己看,当然略显无趣,所以现在笔者在这里基于node.js制作了一个前端网站。该网站实现了用户的注册、登录操作,用户可以登录网站检索想看到的球队的比赛信息,还可以查看各队伍的胜率图、比赛场次图、场均得分图;同时网站还实现了管理员身份,管理员的注册信息从本地数据库插入(想当管理员?得先过了我这关!),管理员可以查看所有用户的注册信息,还可以查看用户的操作日志,还可以停用用户账号。下面就来看一下制作网页的过程吧!

上效果!

<iframe allowfullscreen="true" data-mediaembed="bilibili" id="33PT5F8r-1624693808231" src="https://player.bilibili.com/player.html?aid=376283173"></iframe>

NBA爬虫数据前端网页展示

用户注册、登录网页

        首先,我们要准备好页面的背景图,还要写好要用的css样式。

*{
    margin: 0;
    padding: 0;
}
body
{
    background-image: url(./pictures/background.jpg);
    background-size: cover;
    background-position:top;
    font-family: sans-serif;
    
}
.form .login-page
{
    width: 360px;
    padding: 10% 0 0;
    margin: auto;
}
.form
{
    position: relative;
    top: 150px;
    z-index: 1;
    background: rgb(205, 186, 226);
    max-width: 360px;
    margin: 0 auto 100px;
    padding: 45px;
    text-align: center;
}
.form input
{
    outline: none;
    background: #f2f2f2;
    width: 100%;
    border: 0;
    margin: 0 0 15px;
    padding: 15px;
    box-sizing: border-box;
    font-size: 14px;
}
.form button
{
    text-transform: uppercase;
    outline: 0;
    background: orange;
    width: 100%;
    border: none;
    padding: 15px;
    color: #fff;
    font-size: 14px;
    cursor: pointer;
    transition: .5s;
}
.form button:hover,.form button:active
{
    background: green;
    border: none;
}
.form .message a
{
    color: rgb(240, 17, 17);
    text-decoration: none;
}
.register-form
{
    display: none;
}

 这些是准备工作,然后就可以开始写我们的html网页前端代码了。

前端代码要实现两个模块,登录和注册。

<!--Register-->
<form class="register-form" method="POST" id="register-form" role="form">
    <div class="form-group">
        <input type="text" ng-model="add_username" tabindex="1" class="form-control" placeholder="User Name">
    </div>
    <div class="form-group">
        <input type="password" ng-model="add_password" tabindex="2" class="form-control" placeholder="Password">
    </div>
    <div class="form-group">
        <input type="password" ng-model="confirm_password" tabindex="2" class="form-control" placeholder="Confirm Your Password">
    </div>
    <div class="form-group">
        <div class="row">
            <div class="col-sm-6 col-sm-offset-3">
                <button type="button" id="register-submit" tabindex="4" class="form-control" ng-click="doAdd()">Register</button>
            </div>
        </div>
    </div>
    <p class="massage">Already Registered ? <a href="#">Login</a></p>
</form>

<!--Login-->
<form class="login-form" method="POST" id="login-form" role="form">
    <div class="form-group">
        <input type="text" ng-model="username" tabindex="1" class="form-control" placeholder="User Name" name="username">
    </div>
    <div class="form-group">
        <input type="password" ng-model="password" tabindex="2" placeholder="Password" name="password">
    </div>
    <div class="form-group">
        <div class="row">
            <div class="col-sm-6 col-sm-offset-3">
                <button type="button" id="login-submit" tabindex="4" class="form-control" ng-click="check_pwd()">Login</button>
            </div>
        </div>
    </div>
    <p class="massage">Not Registered ? <a href="#">Register</a></p>
        <p class="massage alert alert-warning" ng-if="msg && msg!='ok'">
        <a href="#" class="close" data-dismiss="alert">&times;</a>
        <strong>警告!</strong>{{msg}}
    </p>
</form>

然后我们需要在同一个页面进行登录和注册的切换,因此用到了这一段代码(前提要引入jQuery模块):

$('.massage a').click(function() {
    $('form').animate({height:"toggle", opacity:"toggle"}, "slow");
});

不说了,咱们直接上效果图:

由于万能的css,两个界面切换地很流畅,鼠标悬停在按钮上会有高亮。然后通过angular和express实现前后端的连接,将用户的注册信息写入mysql数据库中,也可以从数据库验证用户的密码。

检索球队信息

        成功登录后,我们会进入competition.html页面。

点击检索,会出现如下画面。

这里做了一个html元素的隐藏和显示。代码如下:

<div ng-show="isShow" style="width: 1300px;position:relative; top:70px;left: 80px">
<!--    查询页面-->
    <div ng-include="'search.html'"></div>
</div>

用show属性的false和true来控制标签的显示与否。

后端可以捕获用户输入的球队名称,然后传到mysql检索。

// 查询数据(根据主客场队伍检索)
    $scope.search = function () {
        var team = $scope.team;
        var oppo = $scope.oppo;

        // 用户可能一个队伍名都不输入,默认查找全部数据
        var myurl = `/competitions/search?t1=${team}&op=${oppo}`;

        $http.get(myurl).then(
            function (res) {
                if(res.data.message=='data'){
                    $scope.isisshowresult = true; //显示表格查询结果
                    $scope.initPageSort(res.data.result)
                }else {
                    window.location.href=res.data.result;
                }


            },function (err) {
                $scope.msg = err.data;
            });
    };

//另一个文件↓

router.get('/search', function(request, response) {
    console.log(request.session['username']);
    //sql字符串和参数
    if (request.session['username']===undefined) {
        response.json({message:'url',result:'/index.html'});
    }else {
        var param = request.query;
        compDAO.search(param,function (err, result, fields) {
            response.json({message:'data',result:result});
        })
    }
});

//另一个文件↓

search :function(searchparam, callback) {
        // 组合查询条件
        var sql = 'select team,ground,scores,record,oppo,ground_op,'+
        'opScores,opRecord,time,timeCost,location,'+
        'numsOfAd,shoot,three_point,penalty,frontcourt,'+
        'backcourt,backboard,assist,foul,steal,mistake,cover from myfetches ';

        if(searchparam["t1"]!="undefined"){
            sql +=(`where team like '%${searchparam["t1"]}%'`);
            if(searchparam["op"]!="undefined"){
                sql +=(`AND oppo like '%${searchparam["op"]}%' `);
            };
        }
        else if(searchparam["op"]!="undefined"){
            sql +=(`where oppo like '%${searchparam["t1"]}%' `);
        };

        sql+=';';
        pool.getConnection(function(err, conn) {
            if (err) {
                callback(err, null, null);
            } else {
                conn.query(sql, function(qerr, vals, fields) {
                    conn.release(); //释放连接
                    callback(qerr, vals, fields); //事件驱动回调
                });
            }
        });
    }

检索支持双队伍检索,即固定主场队伍和客场队伍(有相对顺序关系)。因此在mysql检索语句中要加一系列条件判断语句,组合成mysql命令行的检索指令。

最后的效果图如下,结果实现了分页处理,而且还可以根据比赛时间排序(阿杜,你没有输!):

图表制作:

        点击图片,会下拉三个图表选项,分别是柱状图、饼状图、折线图。图表全部依赖ECharts制作。

柱状图展示的是各队伍的胜率信息:

胜率信息由爬取的record是字符串类型,所以要用parInt函数对record战绩信息的字符字串操作,得到胜场和败场,从而计算出胜率。

    $scope.histogram = function () {
        $scope.isShow = false;
        $http.get("/competitions/histogram")
            .then(
                function (res) {
                    if(res.data.message=='url'){
                        window.location.href=res.data.result;
                    }else {
                        let xdata = [], ydata = [], newdata;
                        res.data.result.forEach(function (element) {
                            // "record":"XX胜利XX失败"
                            if(element["record"].length > 4 && xdata.indexOf(element["team"]) == -1)
                            {
                                var win = parseInt(element["record"].substr(0, 2));//将字符串数据转化为数字,计算胜率
                                var lose = parseInt(element["record"].substr(3, 2));
                                var rate = win / (win + lose);
                                ydata.push(rate);
                                xdata.push(element["team"]);
                            }
                        });
                        newdata = {"xdata": xdata, "ydata": ydata};

                        var myChart = echarts.init(document.getElementById('main1'));

                        // 指定图表的配置项和数据
                        var option = {
                            title: {
                                text: 'NBA各队伍胜率'
                            },
                            tooltip: {},
                            legend: {
                                data: ['队伍']
                            },
                            xAxis: {
                                data: newdata["xdata"],
                                axisLabel: {
                                    show: true,
                                    interval:0
                                }
                            },

                            yAxis: {},
                            series: [{
                                name: '胜率',
                                type: 'bar',
                                data: newdata["ydata"],
                                barGap: '80%',
                                barWidth: '50%'
                            }]
                        };
                        // 使用刚指定的配置项和数据显示图表。
                        myChart.setOption(option);
                    }
                },
                function (err) {
                    $scope.msg = err.data;
                });

    };

饼状图展示的是各队伍的比赛场数

比赛的场次可以直接用mysql中的内置aggregate function COUNT() 得到。

"select team as x,count(team) as y from myfetches group by team;"

然后再将得到的数据作为pie图的数据就好了。

    $scope.pie = function () {
        $scope.isShow = false;
        $http.get("/competitions/pie").then(
            function (res) {
                if(res.data.message=='url'){
                    window.location.href=res.data.result;
                }else {
                    let newdata = [];
                    res.data.result.forEach(function (element) {
                        newdata.push({name: element["x"], value: element["y"]});
                    });

                    var myChart = echarts.init(document.getElementById('main1'));
                    var app = {};
                    option = null;
                    // 指定图表的配置项和数据
                    var option = {
                        title: {
                            text: '各队伍比赛场数',
                            x: 'center'
                        },
                        tooltip: {
                            trigger: 'item',
                            formatter: "{a} <br/>{b} : {c} ({d}%)"
                        },
                        legend: {
                            orient: 'vertical',
                            left: 'left',
                            // data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
                        },
                        series: [
                            {
                                name: '访问来源',
                                type: 'pie',
                                radius: '55%',
                                center: ['50%', '60%'],
                                data: newdata,
                                itemStyle: {
                                    emphasis: {
                                        shadowBlur: 10,
                                        shadowOffsetX: 0,
                                        shadowColor: 'rgba(0, 0, 0, 0.5)'
                                    }
                                }
                            }
                        ]
                    };
                    // myChart.setOption(option);
                    app.currentIndex = -1;

                    setInterval(function () {
                        var dataLen = option.series[0].data.length;
                        // 取消之前高亮的图形
                        myChart.dispatchAction({
                            type: 'downplay',
                            seriesIndex: 0,
                            dataIndex: app.currentIndex
                        });
                        app.currentIndex = (app.currentIndex + 1) % dataLen;
                        // 高亮当前图形
                        myChart.dispatchAction({
                            type: 'highlight',
                            seriesIndex: 0,
                            dataIndex: app.currentIndex
                        });
                        // 显示 tooltip
                        myChart.dispatchAction({
                            type: 'showTip',
                            seriesIndex: 0,
                            dataIndex: app.currentIndex
                        });
                    }, 1000);
                    if (option && typeof option === "object") {
                        myChart.setOption(option, true);
                    }
                    ;
                }
            });
    };

折线图展示的是各队伍的平均得分

        效果如下:

与饼状图同理,平均得分也可以由AVG()函数得到。

"select team as x,avg(scores) as y from myfetches group by team;"

得到数据后,便将数据加入ECharts组件即可展示折线图。

    $scope.line = function () {
        $scope.isShow = false;
        $http.get("/competitions/line").then(
            function (res) {
                if(res.data.message=='url'){
                    window.location.href=res.data.result;
                }else {
                    var myChart = echarts.init(document.getElementById("main1"));
                    let teams = [];
                    let avgScores = [];
                    res.data.result.forEach(function(element) {
                        teams.push(element["x"]);
                        avgScores.push(element["y"]);
                    });
                    option = {
                        title: {
                            text: '各队伍平均得分'
                        },
                        xAxis: {
                            type: 'category',
                            data: teams,
                        },
                        yAxis: {
                            type: 'value'
                        },
                        series: [{
                            data: avgScores,
                            type: 'line',
                            itemStyle: {normal: {label: {show: true}}}
                        }],

                    };

                    if (option && typeof option === "object") {
                        myChart.setOption(option, true);
                    }
                }

            });
    };

每次展示图表之前,都先初始化前端的main1标签,避免多张图重叠,然后再展示当前的图片。

管理员操作的实现

我们希望管理员有以下权限:查看所有用户的注册信息以及用户的操作日志,还有停用用户账号。

管理员的注册当然不能写在网页前端,不然人人都可以有管理他人账号的权力了。因此管理员的账号必须由后台直接在mysql中插入。

管理页面的前端和用户登录的前端类似。

当然需要在app文件中加入一个新的路由地址,一系列数据库操作也要和user的操作分离开来(这得创建好多新文件,头秃了......)。

管理员成功登录后,会出现如下界面。

页面的查看选项卡有两个选项,用户注册信息与操作日志浏览、停用用户。因为前者只是实现mysql数据的展示,而后者需要管理员输入,并对数据库信息进行修改,因此我将二者分开。

进入用户注册信息与操作日志浏览选项卡,会出现如下画面。

管理员可以点击两个按钮选择要浏览的信息。

(用户注册信息)

(用户操作日志)

这里的前端实现也与前面的competition类似,显示一个页面时隐藏其他页面。数据展示也实现了分页处理和按时间顺序排序的操作。

点击停用用户按钮,会出现如下画面。

管理员输入要停用的用户名,点击确定按钮,即可删除要删除的用户。

停用成功后,会alert一个弹窗,告诉管理员停用成功。

我们再查看用户注册信息,发现已经没有'mr_king'的注册信息了。

再到登陆界面用mr_king的账号密码登录,也无法登录。

前端页面显示用户不存在。

结语

        这次前端网页制作的过程我无疑是收获满满的:学会了很多mysql的命令、更加熟练地使用路由实现前后端交互、html的设计也愈发熟练。希望这个网页能为我的Web编程课提交一份满意的答卷。

标签:学到,function,网页,option,res,爬虫,var,scope,data
来源: https://blog.csdn.net/weixin_52104555/article/details/118249242

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有