根据词云寻找对应文章的Web开发

1、前言

最近接了点项目,需求是是先通过网络爬虫将网页上的文章给爬取下来,然后通过分析文章的关键词,最终可以在网页上显示总体的关键词的词云图,通过点击关键词就可以实现找到对应的文章列表,且能跳转到对应文章的Web页面。大概项目的思路我将在以下分享。注:所有数据均脱敏处理。

2、技术栈

前端:HTML、CSS、Javasript、BootStrap、Echarts-wordclould

后端:Python、Django

数据库:Mysql

3、项目代码

3.1、爬取网站

使用了requests进行请求网站,lxml进行对html分析。

首先使用代理头,以免识别是python无法爬取结果。

headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36'
    }

首先对网站源码进行分析,得到我们需要的网站都是放在如下的<a>标签中,那么接下里的任务就是将文章网址爬取下来。
在这里插入图片描述

将url与headers带入,先requests进行get请求得到html,再经过etree解析html就可以得到需要的文章网站,当然,这时的网址是相对路径,需要带上之前的url。

page_taxt = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_taxt)
page_list = tree.xpath('//*[@id="article"]/a/@href')

既然我们得到了所有文章链接,那么就可以获取每一片文章,在这里还调用了词频函数,当然这在后面就会呈现。

for page in page_list:
    # 获取每篇笔记
    page_url = url + page
    response = requests.get(url=page_url, headers=headers)
    response.encoding = 'utf-8'
    page_data = response.text
    tree = etree.HTML(page_data)
    # 获取笔记原文数据
    data_al = tree.xpath('//*[@id="article"]//text()')
    for h in data_al:
        data_all = data_all + h
    name = tree.xpath('//h1/@id')
    try:
        # 获取笔记原文地址
        # 部分文章找不到kw,因而使用try跳过
        origin_page_url = tree.xpath('//*[@id="article"]/ol/li[4]/a/@href')[0]
        kw_url = origin_page_url + '/keywords#keywords'
        # 获取文章关键字
        response_kw = requests.get(url=kw_url, headers=headers).text
        ex = '"kwd":\[(.*?)\]'
        kw = re.findall(ex, response_kw, re.S)
        # 转换关键字存储方式,转化为列表
        ex = '"(.*?)"'
        kw_li = re.findall(ex, str(kw), re.S)
        # 存入整体kw列表
        for li in kw_li:
            kw_list.append(li)
        # 处理单篇文章的kw
        data = {}
        data = rank(kw_li)
        name_1 = str(name[0])
        name_1 = name_1.replace("阅读笔记:", '')
        data_list = []
        for fluent_name, value in data.items():
            data = {'papername':name_1, 'url':page_url, 'name':fluent_name, 'value':value}
            data_list.append(data)
        # 通过csv存储
        df = pd.DataFrame(data_list,
                          # index=[0],
                          columns=['papername','url','name', 'value'])
        df.to_csv("test.csv", mode="a", index=False, header=False, encoding='gb18030')
        # 通过mysql存储
        # Paper.objects.create(papername = name[0], url=page_url, name=name, value=value) # 此处只有定时更新数据的时候,才能够取消注释,否则会一直在数据库内追加数据,造成数据混乱
        # print(df)
        print('成功获取: ', name[0], ' 笔记原文献keywords')
    except:
        # pass
        print('无法获取: ', name[0], ' 笔记原文献keywords')
    # time.sleep(2)
# rank为字频统计函数
data1 = rank(kw_list)
3.2、字频统计

将爬取的文章关键词进行统计,就可以得到字频。这里运用普通的循环便利即可实现。

def rank(data_list):
    # 词频统计函数,获取原列表,统计列表元素重复,返回web所需键值对
    data_result = {}
    data_last = []
    for k in data_list:
        if k not in data_result:
            data_result[k] = 1
        else:
            data_result[k] += 1
    return data_result
3.3、前端

在这里,我们已经将前端界面设计好了,需要的数据留有接口,让后端处理好传递到前端,然后前端点击词云得到的关键词,可以通过echarts的点击传递href到后端,当然用ajax,将前端数据同步到后端也是可以的。在这里传输词云数据,我是使用的ajax通信,比较方便,jquery绑定也可以。在此之前,我们要下载echarts、echarts-wordcloud、jquery,可以在官网或者github上下载,找到dist文件夹下的如下js文件,导入依赖即可,不过因为我最近没有梯子,所以下载别人分享的,貌似不能用。。。前端一直报错,最后才发现是echarts.js的问题。

{% load static %}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script src='https://cdn.bootcss.com/echarts/3.7.0/echarts.simple.js'></script>
        <script src='../static/js/echarts-wordcloud.min.js'></script>
        <script src='../static/js/echarts-wordcloud.js'></script>
        <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>


{#        <script src='../static/js/echarts.js'></script>#}
    </head>
    <body>

    <div id="main" style="width: 1500px;height: 700px; "></div>
        <script>
                var chart = echarts.init(document.getElementById('main'));
                var option = {
                tooltip: {},
                series: [ {
                    type: 'wordCloud',
                    gridSize: 2,
                    sizeRange: [12, 50],
                    rotationRange: [-90, 90],
                    shape: 'pentagon',
                    width: 600,
                    height: 400,
                    drawOutOfBound: true,
                    textStyle: {
                        normal: {
                            color: function () {
                                return 'rgb(' + [
                                    Math.round(Math.random() * 160),
                                    Math.round(Math.random() * 160),
                                    Math.round(Math.random() * 160)
                                ].join(',') + ')';
                            }
                        },
                        emphasis: {
                            shadowBlur: 10,
                            shadowColor: '#333'
                        }
                    },
                    data:[]
                } ]
            };
                chart.showLoading({text: '正在加载数据'});
                $.ajax({
                    url:'/word/data',
                    type: 'get',
                    datatype: 'JSON',
                    success(res){
                        //将后台返回的数据,更新到option中
                        if (res.status){
                            chart.hideLoading();
                            console.log("res.data"+res.data)
                            {#option.series.data = res.data#}
                            chart.setOption({
                                series:{
                                    data:res.data
                                }
                            }
                            )

                        }
                    }
                })
            chart.setOption(option);

            window.onresize = chart.resize;

            var ecConfig = echarts.config;
            chart.on('click', eConsole);

            function eConsole(param) {
                if(typeof param.seriesIndex != 'undefined') {
                    if(typeof param.name != 'none') {
                        switch(param.name) { //简单的switch,大家应该能够明白怎么设置
                        case param.name:
                            window.location.href = "/tiaozhuan/?name="+param.name;
                            {#$.ajax({#}
                            {#        url:'/tiaozhuan',#}
                            {#        type: 'get',#}
                            {#        datatype: 'JSON',#}
                            {#        data:{#}
                            {#            name:param.name#}
                            {#        },success:function (res) {#}
                            {#            console.log(res);#}
                            {#    }#}
                            {#})#}
                            {#window.open('/tiaozhuan/')#}
                            // window.open("https://jbk.39.net/bw/zhongliuke/", "_blank");//在新页面打开
                            break;
                        default:
                            break;
                    }
                    }

                }
            }
        </script>
    </body>
</html>

主界面已经设计好了,接下来就是跳转之后的界面,在这个界面里,我们需要有文章的链接,实现查找文章。在这里要导入bootstrap依赖,就可以设计页面了。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
    <style>
        .navbar{
            border-radius: 0;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-default">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <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="#"> </a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li><a href="#"> </a></li>


            </ul>
        </div>
    </div>
</nav>
<div>
    <div class="container">
        <div style="margin-bottom: 10px">
            <a class="btn btn-success" href="#">
                <span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span>
                查询关键词结果</a>
        </div>

        <div class="bs-example" data-example-id="table-within-panel">
    <div class="panel panel-default">
      <!-- Default panel contents -->
      <div class="panel-heading">
          <span class="glyphicon glyphicon-list" aria-hidden="true"></span>
          相关文章
      </div>
      <div class="panel-body">
      </div>
      <!-- Table -->
      <table class="table table-bordered">
        <thead>
          <tr>
            <th>文章</th>
          </tr>
        </thead>
        <tbody>
        {% for obj in data %}
          <tr>
          <td>
{#              {{ obj.paper }}#}
              <a href="{{ obj.url }}" >{{ obj.paper }}</a>
          </td>
{#                <th scope="row" >{{ obj }}</th>#}
          </tr>
        {% endfor %}
        </tbody>
      </table>
    </div>
  </div>
    </div>
</div>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>
3.4、后端

首先在终端环境中创建一个项目与app,在此之前需要配置django-admin的全局变量。不然不能创建项目。

sudo vim ~/.bashrc

之后source一下让配置立即生效就可以了

sudo source ~/.bashrc

因为我的django是安装在anaconda环境下的,所以将我自己ananconda创建的虚拟环境下的bin文件夹直接加入环境变量中就可以了。

现在就可以在终端中创建django项目了。

cd /home/chenyu/PythonFile
django-admin startproject Word

接下来创建一个app

manage.py startapp app01

这样我们的app就部署成功了,但是我们还需要将app激活,在seetings.py增加配置即可。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
]

django是基于MVC(Model、View、Control)的Web开发框架,那么我们先来配置路由。

from django.urls import path
from app01 import views

urlpatterns = [
    path('index/', views.index),
    path('word/data/', views.word_data),
    path('tiaozhuan/', views.tiaozhuan),
    path('test/', views.test),
]

路由对应的链接,可以跳转到我们的视图函数,接下来就要设计视图函数了。

首先设计一个主页,在这里可以实现词云功能。这里返回的html就是我们在前端中设计的第一个文件,返回一个render,将请求与html一起返回即可在浏览器中看到页面了。

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

在这里,我们设计了一个关于词云数据的,这些数据取自数据库,将我们之前存储到的关键词频率全部读取后以Json格式的response传入到前端。这与我们在前端第一个文件中留的ajax接口是一致的,data_list将传到ajax实现同步通信。

def word_data(request):
    data_list = Fluent.Object.all()
    li = []
    for obj in data_list:
        li.append({
            'name': obj.name,
            'value': obj.value
        })
    data_dict = {"status": True,
                 'data':li
                }
    return JsonResponse(data_dict)

当点击词云图的关键词之后,如果是get请求进来之后,则在数据库查到有多少篇文章对应这个关键词,然后将数据再返还给前端,且跳转到一个新的页面。

def tiaozhuan(request):
    if request.method =='GET':
        url = 'https://www.xxx'
        keywords = request.GET.get('name')
        info = Paper.Object.filter(name=keywords)
        data = []
        for obj in info:
            data.append({'papername':obj.papername, 'url':obj.url})
        return render(request, 'tiaozhuan.html', {'data':data})
3.5、数据库

首先在终端中打开mysql,输入mysql -u root -p后会提示输入密码,输入密码后进入mysql控制台。

mysql -u root -p

进入mysql中想要创建新的数据库的话则需要create,之后再建立表格,如下操作可以根据个人要求来选择使用。

CREATE DATABASE cy; # 这里数据库名称根据自己需求设定
use cy; # 使用该数据库
show tables; # 展示该数据库下的数据表
create table paper (
`id` varchar(8) NOT NULL AUTO_INCREMENT,
`papername` varchar(64) DEFAULT NULL,
`name` varchar(64) DEFAULT NULL,
`url` varchar(64) DEFAULT NULL,
`value` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
INSERT INTO (xxx) VALUES (xxx);# 如果想要在mysql直接插入数据,则可以使用该命令
select * from paper; # 可以查看全部数据

在django的setting配置中,将自己的数据库与项目绑定,则可以直接通过django来控制数据的生成与销毁。xxx代表自己设置的数据库信息,需要根据自己的数据库来填写。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'xxx',  # 数据库名字
        'USER': 'xxx', # 默认为root
        'PASSWORD': "xxx",
        'HOST': '127.0.0.1',  # 那台机器安装了MySQL
        'PORT': 3306, # 端口一般为3306,如果更改了端口可以在终端中查找
    }
}

接下来就是我们的Model,通过如下命令就可以生成数据表,如果通过该操作可以省略mysql中前两行后的指令,但是也可以相互配合着使用。

from django.db import models

class Paper(models.Model):
    papername = models.CharField(verbose_name="papername", max_length=64, default=True, null=True)
    url = models.CharField(verbose_name="url", max_length=64, default=True, null=True)
    name = models.CharField(verbose_name="name", max_length=64, default=True, null=True)
    value = models.IntegerField(verbose_name="value", default=True, null=True)

class Fluent(models.Model):
    name = models.CharField(verbose_name="name", max_length=64, default=True, null=True)
    value = models.IntegerField(verbose_name="value", default=True, null=True)

之后要进行数据迁移,将Model数据导入到项目中。

manage.py makemigrations
manage.py migrate

4、项目界面

当我们访问主页面的时候,就会得到词云图,字体越大代表出现的频率越高。我们在前端中设置了echarts的windows属性,那么各个关键词就不是普通文本了,可以实现点击传输数据,将点击的文本传输到后端,与数据库的中的数据进行查找比对。
在这里插入图片描述

通过点击关键词,就可以通过Web框架传入参数跳转到下一个页面。这个页面就是所有的文章列表,所有的信息均是超链接的形式,点击即可跳转到相应的官网的文章。
在这里插入图片描述

本图片已抹除重要信息,仅保留文章部分内容,至此已实现全部项目。
在这里插入图片描述
如果还有时间的话,可以再用Vue搭建框架,用Docker容器搭建环境进行上线。过一段时间可以再发布一个Vue从头搭建的项目。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Python词云中显示中文,可以按照以下方法进行操作: 1. 引用中的代码是使用WordCloud词云库生成词云图的基本代码。但是默认的字体文件DroidSansMono不支持中文显示,所以会出现中文乱码的情况。为了解决这个问题,可以采用以下两种方法之一。 方法一:更换字体文件 你可以选择一个支持中文的字体文件,并将其传递给WordCloud方法的font_path参数。例如,你可以将字体文件的路径设置为SimHei.ttf,然后将其传递给WordCloud方法: ```python wc = WordCloud(font_path='SimHei.ttf') ``` 这样就可以使用SimHei字体来显示中文了。 方法二:下载支持中文的字体文件 你可以从引用的链接中下载支持中文的字体文件,然后将其放到相应的文件夹中。接下来,你需要运行`python setup.py install`命令来安装字体文件,以确保词云库能够找到并使用该字体文件。 总结起来,要在Python词云中显示中文,你可以选择更换字体文件或者下载支持中文的字体文件并安装。这样就可以解决中文乱码的问题了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Python使用wordcloud词云库——中文乱码](https://blog.csdn.net/hahalan/article/details/121637058)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Python词云库wordcloud 显示中文 !!!](https://blog.csdn.net/qq_34777600/article/details/77455674)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值