利用爬虫和Django+echarts建立自己的动画人气统计小站

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/s291547/article/details/77785265

开发环境:Django版本1.11.4,python版本3.6.0

Django后台的准备

新建项目

如何安装django就不多说了,安装好之后打开cmd,输入django-admin.py startproject Anime,新建Anime项目。如果报错尝试使用django.admin代替django.admin.py。如果想在某个指定的文件夹下建立项目,把django.admin.py放到指定的文件夹下,在命令行下进入该文件夹后再执行新建项目命令。

我是新建好项目后打开pycharm加载项目文件,之后命令行的操作通过pycharm下方的terminal完成。
这里写图片描述

我使用的pycharm是免费版本,阉割了python的web开发功能,网上教程能在pycharm内直接新建django项目的应该是付费的professional版本。(?)

新建app

进入Anime目录下,命令行输入python manage.py startapp Zawarudo,新建名为Zawarudo的app。为了让django工程运行的时候能识别新的app,修改Anime/setting.py,在INSTALLED_APP中新增’ Zawarudo’,完成新app的注册。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'Zawarudo'
]

建立模型

进入Anime/Zawarudo/models.py,新增Animation模型:

from django.db import models

# Create your models here.
class Animation(models.Model):
    name = models.CharField(max_length=64)
    uid = models.IntegerField()
    statics = models.TextField()

    def __str__(self):
        return self.name

其中name为动画的作品名,uid为该动画作品在s1中的专楼id,statistics为人气统计,具体格式与含义后边会解释。

在admin中注册模型,这样就能在admin管理界面内进行数据库内容的操作。

from django.contrib import admin
from.models import Animation
# Register your models here.
admin.site.register(Animation)

注册完后就能对其内容进行管理了。
这里写图片描述

建立模板

新建Graph.html文件,将一些布局什么的先塞进去,在statics文件夹下新建Zawarudo文件夹,将相关的css与js文件扔进里边。

注意开头加上{% load staticfiles %}将静态文件加载进来。此时head引用的文件已经包含了echarts.js,但我们还没用到。

{% load staticfiles %}
<!DOCTYPE html>
<html>

    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>2017年4月统计</title>
        <script type="text/javascript" src="{% static 'Zawarudo/js/jquery.min.js' %}"></script>
        <script type="text/javascript" src="{% static 'Zawarudo/js/echarts.js' %}"></script>
        <script type="text/javascript" src="{% static 'Zawarudo/js/bootstrap.js' %}"></script>

        <link type="text/css" rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">

    </head>

    <body>
        <nav class="navbar navbar-default navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
                    <a class="navbar-brand" href="#">Hidoshi的统计小站</a>
                </div>
                <div id="navbar" class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li>
                            <a href="/index/">主页</a>
                        </li>
                        <li class="active">
                            <a href="#about">统计</a>
                        </li>
                        <li>
                            <a href="#contact">说明</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>

        <div class="container" style="margin-top: 5em;">
            <div class="row">
                <div class="col-md-8">
                    <div align="center">
                        <div id="main" style="width: 1100px;height:600px"></div>
                    </div>

                </div>
            </div>
        </div>
    </body>
</html>

有时候启动服务后提示模板不存在,那可能需要确认一下setting.py文件里面TEMPLATES的路径’DIRS’: [XXXX]

建立视图

视图负责处理用户的请求,之后将处理的结果返回给用户。

from django.shortcuts import render
from .models import Animation

def index(request):
    return render(request, 'index.html')

def Graph(request):
    Animations = Animation.objects.all()
    ctx = {
        'Animations': Animations
    }
return render(request, 'Graph.html', ctx)

使用django的orm进行数据库查询,结果集为一个QuerySet对象,放入ctx字典中,渲染模板完成页面数据的加载。

完成url设置

在Anime/Zawarudo文件夹下新建urls.py文件,明确访问指定的url时需要请求的视图,将以下内容写入:

from django.conf.urls import url
from. import views as view

urlpatterns = [
    url(r'^$', view.index, name=index),
    url(r'^Graph/$', view.Graph, name='Graph'),
]

然后修改Anime/urls.py文件,修改成如下:

from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
    url(r'^Zawarudo/', include('Zawarudo.urls')),
    url(r'^admin/', admin.site.urls),
]

注意这是两个不同的urls文件。一个位于项目目录下,一个位于app目录下。其中项目目录下urls.py中使用include()方法引用其他的URLconf。django1.11文档中建议除了admin.site.urls以外的url patterns都通过include()管理。

进行数据库同步

先后运行python manage.py makemigrations和python manage.py migrate。这两句在通过django的orm方法修改数据库后经常要被调用以和数据库文件进行同步。

Python manage.py makemigrations:将对models的改动记录,但还未作用到数据库文件。
Python manage.py migrate:将改动作用到数据库文件。

此时在命令行界面运行python manage.py runserver就能启动服务了,访问
http://127.0.0.1:8000/Zawarudo/Graph/地址能看到网站大致的布局,当然现在还是空的。

完成后的工程目录情况如下:
这里写图片描述

数据的获取

以国内用户活跃程度较高的stage1st论坛为例,论坛的动漫板块在每个季度都会为日本的新番动画分别建立讨论的专楼,我们可以通过考察某部动画在其专楼的讨论热度来判断其人气程度(起码是在该论坛的人气)。

我们通过爬虫获取每个回帖的发帖时间,然后构造帖子数量随时间变化的图表,以此能观察其在不同时间段的讨论热度。

爬虫获取与数据入库

除了常规的requests和re库,此处还需要方便日期操作的datetime库与对轻量级数据库sqlite3进行操作的sqlite3库。小爬虫并不复杂,只是运行的时候还需要自行寻找专楼的地址。

import requests
import re
import datetime
import sqlite3

main_url = "http://bbs.saraba1st.com/2b/thread"
url_token = '1290033'
tail = "-1.html"
headers = {
    'Host':'bbs.saraba1st.com',
    'Referer':'http://bbs.saraba1st.com/2b/forum-6-1.html',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55',
}
timeList = []

#遍历帖子页数
for i in range(1, 54):
    url = main_url + "-" + url_token + "-" + str(i) + tail
    content = requests.get(url, headers=headers)
    pattern = re.compile(r'发表于 (.+?)</em>')
    currentTimeList = pattern.findall(content.text)
    timeList.extend(currentTimeList)

#print(len(timeList))

startDate = datetime.datetime.strptime('2017-04-01 00:00:00', '%Y-%m-%d %H:%M:%S')
delta = datetime.timedelta(days=7)

#将初始时间加入列表与字典中
date = startDate
dateCount = {}
dateCount[startDate] = 0
dateList = []
dateList.append(startDate)

#以一周作为时间间隔,将间隔的时间点计算出来以便与发帖时间做比较,找出发帖时间属于哪个时间间隔
for i in range(14):
    date = date + delta
    dateCount[date] = 0
    dateList.append(date)

#print(dateList)
#print(dateCount)

before = 0 #播放前的人气
after = 0 #播放后的人气

#计算播放中每个时间间隔的发帖数量,
for time in timeList:
    t = datetime.datetime.strptime(time, '%Y-%m-%d %H:%M')
    if t < dateList[0]:
        before = before + 1
    elif t > dateList[-1]:
        after = after + 1
    else:
        for i in range(14):
            if t >= dateList[i] and t < dateList[i + 1]:
                dateCount[dateList[i]] = dateCount[dateList[i]] + 1

statistics_list = []

del dateCount[dateList[-1]]

print("before"+" "+str(before))
statistics_list.append(before)

for date in dateCount:
    print(str(date)+" "+str(dateCount[date]))
    statistics_list.append(dateCount[date])

print("after"+" "+str(after))
statistics_list.append(after)

print(statistics_list)

#计算到某个时间间隔为止的总帖子数量
for i in range(1,16):
    statistics_list[i] = statistics_list[i-1]+statistics_list[i]

print(statistics_list)

#数据库操作
conn = sqlite3.connect('F:\django\Anime\db.sqlite3')
c = conn.cursor()
#print ("Opened database successfully")


c.execute("INSERT INTO Zawarudo_animation (name, uid, statistics) \
      VALUES ('末日时在做什么?', '"+ url_token + "', +'"  + str(statistics_list) + "')");

conn.commit()

#print ("Operation done successfully")
c.close()
conn.close()

选择当前为止累积帖子数量而非当前时间段发帖数量作为人气的衡量,主要是考虑生成的图表能更为总体的反应整部作品的人气。

随便挑选了四月的几部新番动画,爬虫效果如图:
这里写图片描述

这时候进django的admin管理页面也能看到增加了相应的记录。

利用echarts展示数据

数据的展示还是折线图好,先看看官方给的折线图示例:
这里写图片描述

嗯,挺好的,该有的都有了。注意到数据填充的格式和python列表的形式一样,所以我们在处理爬虫爬取的数据时是将list类型直接转为string入库的,这样传递数据的时候就不用过多处理了。

在我们上面写好的Graph.html中新增一段javascript代码,加在

<div align="center">
    <div id="main" style="width: 1100px;height:600px"></div>
</div>

之后:

<script type="text/javascript">
    var myChart = echarts.init(document.getElementById('main'));
    option = {
        tooltip: {
            trigger: 'axis'
        },
        legend: {
            data: [
            //获取作品名
            { %for Animation in Animations % }
                '{{ Animation.name }}',
                { % endfor % }
            ]
        },
        grid: {
            left: '3%',
            right: '4%',
            bottom: '3%',
            containLabel: true
        },
        toolbox: {
            feature: {
                saveAsImage: {}
            }
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            data: ['Before', '2017-04-01', '2017-04-08', '2017-04-15', '2017-04-22', '2017-04-29', '2017-05-06', '2017-05-13', '2017-05-20', '2017-05-27', '2017-06-03', '2017-06-10', '2017-06-17', '2017-06-24', '2017-07-01', 'After']
        },
        yAxis: {
            type: 'value'
        },
        series: [
            //获取作品名与作品的人气统计数据,填入name与data中
            { %for Animation in Animations % } 
            {
                name: '{{ Animation.name }}',
                type: 'line',
                smooth: true,
                data: {
                    {
                        Animation.statistics
                    }
                }
            },
            { % endfor % }
        ]
    };
    myChart.setOption(option);
</script>

横坐标以时间间隔为单位。在series参数的设定中,由于我们不需要堆叠效果故将stack属性去掉,为了获得平滑的曲线我们将smooth属性设为true.

结果与总结

最后没有意外的话效果如图:
这里写图片描述

数据分析什么的就不多说了,总体的人气情况与印象中大致相同。

一些总结:这玩意其实还是个半成品…后期需要完善的话可以通过ajax来查询不同季度的动画人气数据,不过这样前端视图数据库都得重新设计,以后啥时候有心情了再把它完善一下找个服务器挂上去好了…

猜你喜欢

转载自blog.csdn.net/s291547/article/details/77785265
今日推荐