# 第四週 大數據分析實務&商業智慧與巨量資料分析
> ==**將先前爬出來的多篇類別新聞進行詞彙分析、建置輿情分析平台、從0開始建置Django網站**==[color=#EA0000]
###### tags: `大數據分析實務` `商業智慧與巨量資料分析` `碩士` `複習用` `高科大`
>:::spoiler 文章目錄
>[TOC]
>:::
{%hackmd @chiaoshin369/bigdata_url_temple %}
## 第四週內容
> **時間:2025/3/11(二)、2025/3/13(四)** [color=#ffe260]
### 說明
1. 從0開始用Django製作輿情分析網站
2. 回家作業使用word檔,並截圖說明,最後匯出pdf檔
3. 將 `news_topkey_with_category_via_token_pos` 匯入
4. 執行 <font color="#EA0000">**Get hot keywords and draw chart**</font>
5. 建置Django專案,瞭解其MVC網站內容架構
## 下載本週課程檔案
>[!Note]
>選取 w04 所有檔案 download。

如果 **無法使用** 或 **檔案連結已被老師變更**,請至 `Github倉庫` 下載
>[!Important]
>[bigdata/2025/class4/drive-download-20250314T090347Z-001.zip at main · chiaoshin/bigdata](https://github.com/chiaoshin/bigdata/blob/main/2025/class4/drive-download-20250314T090347Z-001.zip)
>
## 抓取熱門關鍵字,並繪製圖表
> Get hot keywords and draw chart
```python=1
import pandas as pd
df_data = pd.read_csv('blow_news_topkey_with_category_via_token_pos.csv',sep=',')
df_data.head(5) # 印出前4類(含全部類別)
df_data['top_keys'][0] # 抓第1類
eval(df_data['top_keys'][0]) #將原先字串格式轉為list
data={} # 字典 Dict
for idx, row in df_data.iterrows(): # 逐列處理
data[row['category']]= eval(row['top_keys'])
data # 印出全部字典
data['議題'] # 單獨抓 "議題" 類別資料
data['議題'][0:5] # 抓 "議題" 類別資料的前5筆
# 寫一個函式,處理成Django圖表可讀取格式
def get_category_topword(cate, topk=10):
wf_pairs = data[cate][0:topk]
words = [w for w, f in wf_pairs]
freqs = [f for w, f in wf_pairs]
chart_data = {
"category": cate,
"labels": words,
"values": freqs}
return chart_data, wf_pairs
# 印出議題中前5筆資料(keyword)
get_category_topword('議題',5)
```
:::info
從list、Array(陣列) 轉成 Dict(字典)格式。
變成 ==類別==、==關鍵字keyword==、==數量==的組合(key,value組合)。

並 轉成 ==Django圖表== 可讀取的 Json格式。

:::
### Django API
```python
# POST: csrf_exempt should be used
# 指定這一支程式忽略csrf驗證
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def api_get_cate_topword(request):
cate = request.POST.get('news_category')
#cate = request.POST['news_category'] # this command is also works.
topk = request.POST.get('topk')
topk = int(topk)
print(cate, topk)
chart_data, wf_pairs = get_category_topword(cate, topk)
response = {'chart_data': chart_data,
'wf_pairs': wf_pairs,
}
print(response)
return JsonResponse(response)
```
## 建置Django輿情分析平台
> 圖表使用 `Char.js` 繪製。
> 也可以使用其他,如:D3.js、Highcharts。[color=#ff2877]
利用Ajax將後端資料,渲染至前端。
### Step By Step(初始化6步)
1. 建置資料夾 `website_news_analysis_v1`
2. 進入命令提示字元、終端機(cmd)
3. 執行conda環境 `conda activate ai25`
4. 建置專案配置資料夾 `website_configs`
5. 新增Django頁面 `app_top_keyword`
6. 執行網站(啟動) `python manage.py runserver 8000`
>[!Important]
>請先完成上方6個步驟,確認沒問題後,再執行下方步驟。
:::success
==配置頁面、網站設定==
1. `settings.py` 貼上修正
2. `urls.py` (website_configs總目錄 / app_top_keyword 頁面目錄)
3. 建立頁面資料夾 `templates`,再新增一層資料夾 `app_top_keyword` 放置 `home.html`
4. `views.py` 貼上修正
5. 在原專案頁面 `app_top_keyword` 資料集下,新增資料夾 `dataset`,並將處理好的csv資料集 `blow_news_topkey_with_category_via_token_pos.csv`放置於此
6. 修改成 **MVC架構**,將 原先的 `home.html` 拆成 `base.html` 跟 MVC渲染的 `home.html` 結構,並統一放置於 專案 `templates` 資料夾。
:::
#### 建置資料夾

#### 右鍵 叫出 ==命令提示字元、終端機(cmd)==

:::danger
注意!!! 要進去資料夾,再叫出cmd,否則要先執行 `cd website_news_analysis_v1`,才會到達對的路徑(請留意為資料夾放置的路徑,不一定和圖片相同)。

:::
#### 執行conda環境
```powershell=1
conda activate ai25
```

#### 建立 名為 website_config 的 ==專案配置資料夾==
```powershell=1
django-admin startproject website_configs .
```
用來存放專案設定(配置)檔案的資料夾,名稱為 `website_configs`
通常,這類資料夾包含各種設定檔,如環境變數、伺服器配置、資料庫連線資訊等,讓專案能夠根據不同的需求進行調整。


#### 新增Django頁面
> Create an APP[color=#42cbed]
```powershell=1
django-admin startapp app_top_keyword
```
or
```powershell=1
python manage.py startapp app_top_keyword
```
新增一個 Django頁面,名為 `app_top_keyword`。


#### 執行網站(啟動)
```cmd=1
python manage.py runserver 8000
```
確定顯示火箭,Django環境與專案則建置成功。


#### ==初始資料夾結構== 瞭解
> `website_news_analysis_v1` 專案資料夾

> `website_configs` 專案總設定檔資料夾

> `app_top_keyword` 單一頁面(app)資料夾

>[!Tip]
>瞭解 MVC框架架構。
>基本控制: `manage.py`
>基本檔案: `views.py`、`urls.py`、`settings.py`
>其餘資料夾與MVC架構:
>dataset、templates、`base.html`、`home.html`
#### 執行 Hello world 頁面
> **==views.py==**[color=#42cbed]
```python=1
from django.shortcuts import render
from django.http import HttpResponse
def hello( request ):
return HttpResponse('Hello World!')
# or 二選一
def hello( request ):
return HttpResponse('<h2>Hello World!</h2>')
```
> **==urls.py==**[color=#42cbed]
```python=1
from django.contrib import admin
from django.urls import path
from app_hello import views
urlpatterns = [
path('admin/', admin.site.urls),
path('hello/', views.hello),
]
```
#### 執行並創建Django各類新聞熱門關鍵詞網站
> **Top Keywords Display and Charting**

##### 完整專案資料夾結構

##### 開始建立 STEP by STEP (HW回家作業)

將 `settings.py` 進行處理,修改 `ALLOWED_HOSTS`、`INSTALLED_APPS`、`TEMPLATES`。
> **==settings.py==**[color=#42cbed]
```python=1
from pathlib import Path
import os
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-1j=m)#r))l4hz(gqvc65$@v8my(#!fijflbl@#ii61gq+xzvy!'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# 修改1
ALLOWED_HOSTS = [] # or '*', 'localhost', '127.0.0.1',"your public ip"
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Application definition
# 修改2
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app_top_keyword',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'website_configs.urls'
# 修改3
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'website_configs.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
```
新建一個頁面的路徑(create app router)。
> **==`app_top_keyword` urls.py==**
```python=1
from django.urls import path
from app_top_keyword import views
# Declare a namespace for this APP
app_name = 'app_top_keyword'
urlpatterns = [
# For home
path('', views.home, name='home'),
# For Ajax (當csv資料集新增進去,Ajax呼叫,需要指引路徑)
# 留意指定 home.html的ajax url,至 views.py的api_get_cate_topword方法
path('api_get_cate_topword/', views.api_get_cate_topword),
]
```
建立一個網站的總路徑(總目錄),並引入前面 **各類新聞熱門關鍵詞(app)** 頁面 的 `urls`。
> **==`website_configs` urls.py==**[color=#42cbed]
```python=1
from xml.etree.ElementInclude import include
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
# path('admin/', admin.site.urls),
# top keywords
path('topword/', include('app_top_keyword.urls')),
]
```
利用 `views.py` 將前端畫面進行渲染。
並且在頁面 `app_top_keyword` 建立資料夾 `dataset`,放置先前已處理好的資料集
`blow_news_topkey_with_category_via_token_pos.csv`

:::danger
注意!!! 放入csv資料集後,請重新執行,並載入畫面。
`python manage.py runserver 8000`
:::
> **==views.py==**[color=#42cbed]
```python=1
from django.shortcuts import render
from django.http import JsonResponse
import pandas as pd
# render渲染網頁
def home(request):
return render(request, 'app_top_keyword/home.html')
# read df 讀取csv資料集
df_topkey = pd.read_csv('app_top_keyword/dataset/blow_news_topkey_with_category_via_token_pos.csv', sep=',')
# prepare data 預處理 - 清洗資料
data={}
for idx, row in df_topkey.iterrows():
data[row['category']] = eval(row['top_keys'])
# We don't use it anymore, so delete it to save memory.
del df_topkey
# POST: csrf_exempt should be used
# 指定這一支程式忽略csrf驗證
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def api_get_cate_topword(request):
cate = request.POST.get('news_category')
#cate = request.GET['news_category'] # this command also works.
topk = request.POST.get('topk')
topk = int(topk)
print(cate, topk)
chart_data, wf_pairs = get_category_topword(cate, topk)
response = {'chart_data': chart_data,
'wf_pairs': wf_pairs,
}
print(response)
return JsonResponse(response)
def get_category_topword(cate, topk=10):
wf_pairs = data[cate][0:topk]
words = [w for w, f in wf_pairs]
freqs = [f for w, f in wf_pairs]
chart_data = {
"category": cate,
"labels": words,
"values": freqs}
return chart_data, wf_pairs
print("app_top_keywords--類別熱門關鍵字載入成功!")
```
在 `app_top_keyword` 資料夾內,新增一個資料夾 `templates`,在 `templates` 資料夾下,繼續新增一個資料夾 `app_top_keyword`,並將 `home.html` 放進去。

>[!Tip]
>資料夾名稱,建議用 **複製**,不要用打的,容易因為一個空白,或者字不一樣,導致路徑錯誤。
再來複製 `home.html`,即可看到即時渲染畫面。
:::info
==Django Template Language (DTL)==
{% url 'app_top_keyword:home' %}
定義在 `website_configs` 裡 `urls.py` path(總目錄) 中的 name
類似於 `Jinja`
:::
> **==home.html==**[color=#42cbed]
```html=1
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<title>輿情分析平台</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<div class="row">
<!-- Navigation Bar -->
<div class="col-lg-12 mb-2">
<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #e3f2fd">
<div class="container-fluid">
<a class="navbar-brand" href="#">輿情大數據</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="#">政治人物聲量排行榜</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">政黨聲量排行榜</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'app_top_keyword:home' %}">熱門關鍵詞分析</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">昨日熱門關鍵字</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">熱門人物排行分析</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">NER熱門分析</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">你的關鍵詞熱門度分析</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">全文檢索與關聯新聞分析</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">你的關鍵詞情緒分析</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">今日新聞瀏覽與新聞推薦</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">新聞或文章情緒分類</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">新聞分類新聞分類</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">課程介紹網頁</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">會員獨享功能</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li>
<a class="dropdown-item" href="#">長時間(超過3個月)監控分析(收費標準)</a>
</li>
<li>
<a class="dropdown-item" href="#">自訂分析功能(收費標準)</a>
</li>
<li>
<a class="dropdown-item" href="#">更多資料庫分析(收費標準)</a>
</li>
<li>
<hr class="dropdown-divider" />
</li>
<li>
<a class="dropdown-item" href="#">為你訂製輿情分析任務(報價)</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
<!-- End of Navigation Bar -->
<!-- Main Content -->
<div class="col-lg-12">
<h1>各類新聞最熱門的關鍵詞</h1>
<p>熱門度分析:可以了解新聞關注那些重要的東東</p>
</div>
<!-- 新聞類別選單--- -->
<div class="col-lg-6 mb-2">
<div class="card">
<div class="card-header">
<h3 class="h6 text-uppercase mb-0">熱門關鍵字瀏覽與繪圖(資料週期:資料截止時間的前4周)</h3>
</div>
<div class="card-body">
<!-- 新聞類別選單 form group -->
<div class="mb-3 row">
<label class="col-sm-3 form-label">新聞類別</label>
<div class="col-md-9">
<select id="cate-selected" name="news_category" class="form-select">
<!-- <option>請選擇</option> -->
<option>全部</option>
<option>人物</option>
<option>議題</option>
<option>新聞</option>
<option>雜吹</option>
</select>
<div class="form-text">請選擇新聞類別</div>
</div>
</div>
<!-- form group -->
<!-- 熱門詞多少個?form group -->
<div class="mb-3 row">
<label class="col-md-3 form-label">多少個熱門詞?</label>
<div class="col-md-9">
<input id="topk-selected" name="topk" value="10" class="form-control" />
<div class="form-text">內定值為10</div>
</div>
</div>
<!-- form group -->
<!-- submit按鈕form group -->
<div class="mb-3 row">
<div class="col-md-9 ms-auto">
<button type="button" id="btn-ok" class="btn btn-primary">查詢</button>
</div>
</div>
<!-- form group -->
</div>
<!-- card body -->
</div>
<!-- column -->
</div>
<!-- 區塊結束 -->
<!-- 繪圖區塊--- -->
<div class="col-lg-6 mb-5">
<div class="card">
<div class="card-header">
<h3 class="h6 text-uppercase mb-0">熱門關鍵字繪圖</h3>
</div>
<div class="card-body">
<canvas id="mychart"></canvas>
</div>
</div>
</div>
<!-- 區塊結束 -->
<!-- 熱門關鍵字區塊--- -->
<div class="col-lg-6 mb-5">
<div class="card">
<div class="card-header">
<h3 class="h6 text-uppercase mb-0">熱門關鍵字</h3>
</div>
<div class="card-body">
<ul id="topkeys"></ul>
</div>
</div>
</div>
<!-- 區塊結束 -->
</div>
</div> <!-- container -->
<!-- Bootstrap 5 JS Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Additional Scripts -->
<!-- chartjs圖js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
<!-- 程式碼區 -->
<script>
// Show default top words bar chart when the page is loaded.
// Invoke callAjax() after the function is defined, unless callAjax() is defined with "hoisting"
callAjax()
//*新聞類別選單select被選中值有改變時,執行以下事件
//$('#cate-selected').on('change', callAjax() );
$('#cate-selected').on('change', function () {
callAjax()
}) //event function
//**按鈕事件
$('#btn-ok').on('click', function () {
callAjax()
}) //event function
// ** draw chart using Ajax 畫圖
// There are two ways to define a function:
// one is expression, and the other is definition with "hoisting"
// function with hoisting: function callAjax() {}
// normal function expression: let callAjax = function() {}
// Define callAjax function with hoisting
// callAjax()這樣定義可以在被定義前就被使用 跟我們在Java裡面的函數用法一樣!
//let callAjax = function() {
function callAjax() {
let cate = $('#cate-selected').val()
//console.log(cate);
// $ 可改成 jQuery
let topk = $('#topk-selected').val()
//console.log(topk);
$.ajax({
type: 'POST',
//url: "/topword/api_get_cate_topword/",
url: 'http://127.0.0.1:8000/topword/api_get_cate_topword/',
//url: "http://163.18.23.21:8000/topword/api_get_cate_topword/",
//url: "api_get_cate_topword/", //Not recommended!
data: {
news_category: cate,
topk: topk
},
success: function (received) {
//console.log(received);
let chart_data = received.chart_data
let wf_pairs = received.wf_pairs
console.log(wf_pairs)
showTopKeys(wf_pairs)
showChart(chart_data)
} //success function
}) //ajax
} //callAjax
//* 顯示關鍵詞資料函數
function showTopKeys(items) {
//先清除前一次的資料
$('#topkeys').empty()
//將內容加上li標籤附加起來,顯示在顯示區"topkeys"
for (let i = 0; i < items.length; i++) {
let item_li = '<li>' + items[i] + '</li>'
$('#topkeys').append(item_li)
}
} //function
//**繪圖函數showChart()
function showChart(chart_data) {
// 畫圖需要的數據資料
let values = chart_data.values
let labels = chart_data.labels
let category = chart_data.category
//第1個變數: 餵給chart的資料
let data = {
labels: labels,
datasets: [
{
label: category,
data: values,
backgroundColor: randomColors(values.length),
borderColor: randomColors(values.length),
borderWidth: 1
}
]
}
//第2個變數: chart的選項 指定y坐標軸從零開始顯示
let options = {
scales: {
y: {
beginAtZero: true
}
}
}
//取得在前面html區域欲顯示的圖代號
let canvas_mychrat = document.getElementById('mychart')
//**先清除前一個圖 再繪新圖
// 可以印出barchart物件是否存在
// console.log(window.barchart);
//先清除前一個圖 再繪新圖 if 有以下兩種寫法皆可
// if (window.barchart) //若存在則為true
// if (typeof (barchart) != "undefined"){
if (window.barchart) {
barchart.destroy()
}
//**繪圖(產生一個圖物件變數名稱為barchart)
// 必須全域變數--注意:前面不要有let, var, const等修飾詞
// 理由: 我們要讓它存在於網頁全域變數,
// 這樣我們才方便判斷是否有前一次的圖,如果存在有,要刪除之,否則,很多張圖會疊在一起
barchart = new Chart(canvas_mychrat, {
type: 'bar',
data: data,
options: options
})
//** 產生隨機顏色
function randomColors(num_colors) {
let colors = []
for (i = 0; i < num_colors; i++) {
let r = Math.floor(Math.random() * 255)
let g = Math.floor(Math.random() * 255)
let b = Math.floor(Math.random() * 255)
let rgb = `rgba(${r},${g},${b},0.5)` // (red, green, blue, alfa) alfa透明度
colors.push(rgb)
}
return colors
}
} //show chart function
// document就是這個網頁HTML所有的元素
// window就是這個網頁的全域變數global variables:有一大堆,我們自己定義的有callAjax, showChart, barchart等
// 把document, window印出來看看就能理解它們是甚麼
//console.log(document);
//console.log(window);
</script>
</body>
</html>
```
上方為所有檔案的呈現(html+css+js+api_dataset)。
但不可能每一頁都要撰寫重複的meun bar (header),所以要把它拆開來撰寫,同時把檔案結構分乾淨、清楚,才會符合框架的 **MVC架構**。
在 `website_news_analysis_v1` 資料夾內,新增一個資料夾 `templates`,並將 `base.html` 放進去。
>[!Tip]
>資料夾名稱,建議用 **複製**,不要用打的,容易因為一個空白,或者字不一樣,導致路徑錯誤。
>
>他是吃 `settings.py` 的 `TEMPLATES`
>`'DIRS': [os.path.join(BASE_DIR, 'templates')],` 去讀取
> **==base.html==**[color=#42cbed]
```html=1
<!DOCTYPE html>
{% load static %}
<html lang="zh-TW">
<head>
<title>
{% block title %}
輿情分析平台
{% endblock %}
</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" />
{% block extra_css %}
{% endblock %}
</head>
<body>
<div class="container">
<div class="row">
<!-- Navigation Bar -->
<div class="col-lg-12 mb-2 mt-2">
<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #e3f2fd">
<div class="container-fluid">
<a class="navbar-brand" href="/">輿情大數據</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<!-- 基礎熱門分析 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">熱門分析</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="{% url 'app_top_keyword:home' %}">熱門關鍵詞分析</a>
<a class="dropdown-item" href="#">熱門人物排行分析</a>
<a class="dropdown-item" href="#">命名實體熱門分析</a>
<a class="dropdown-item" href="#" style="color: green">昨日誰最大</a>
</div>
</div>
<!-- 進階自訂分析 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">進階查詢</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">自訂關鍵詞熱門度分析</a>
<a class="dropdown-item" href="#">自訂全文檢索與關聯分析</a>
<a class="dropdown-item" href="#">自訂關鍵詞之情緒分析</a>
</div>
</div>
<!-- 特色分析 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">特色分析</button>
<div class="dropdown-menu">
<a class="nav-link" href="#" style="color: green">時中聲量我最大</a>
<div class="dropdown-divider"></div>
<a class="nav-link" href="#" style="color: green">台北市長選舉聲量觀測站</a>
<div class="dropdown-divider"></div>
<a class="nav-link" href="#">政黨聲量排行榜</a>
<a class="nav-link" href="#">政治人物聲量排行榜</a>
<div class="dropdown-divider"></div>
<a class="nav-link" href="#" style="color: green">事件人物聲量相關分析</a>
</div>
</div>
<!-- 新聞推薦系統 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">新聞推薦系統</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Bert/Qwen新聞推薦-新聞查找相似新聞</a>
</div>
</div>
<!-- NLP應用 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">自然語言理解</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">語言模型Bert/Qwen情緒分類</a>
<a class="dropdown-item" href="#">語言模型Bert/Qwen新聞分類</a>
</div>
</div>
<!-- 使用資料庫 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">使用DB</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">熱門人物資料庫查詢</a>
<a class="dropdown-item" href="#">昨日新聞資料庫全文檢索</a>
</div>
</div>
<!-- 其他特色應用 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">特色應用</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">高雄市市長選舉人氣分析</a>
<a class="dropdown-item" href="#">珊珊市長人氣</a>
<a class="dropdown-item" href="#">阿邁市長人氣</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">疫情發燒監視</a>
<a class="dropdown-item" href="#">蘋果發燒站</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">人氣美食排行榜</a>
<a class="dropdown-item" href="#">財經議題排行榜</a>
<a class="dropdown-item" href="#">股市新聞監視站</a>
<a class="dropdown-item" href="#">科技新聞熱門議題分析</a>
<a class="dropdown-item" href="#">人力銀行職缺大熱門</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">批踢踢酸民大吐槽</a>
<a class="dropdown-item" href="#">批踢踢鄉民來八卦</a>
<a class="dropdown-item" href="#">滴卡大學生關心議題</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">新聞媒體政黨傾向調查分析</a>
<a class="dropdown-item" href="#">自訂競爭大PK</a>
</div>
</div>
<!-- 會員訂閱 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">付費訂閱</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">長時間(超過3個月)監測分析(收費表)</a>
<a class="dropdown-item" href="#">更多資料庫分析(收費表)</a>
<a class="dropdown-item" href="#">為你訂製輿情分析任務(報價)</a>
</div>
</div>
<!-- 關於 -->
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">關於</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">課程介紹網頁</a>
<a class="dropdown-item" href="#">如何使用輿情API</a>
</div>
</div>
</ul>
</div>
</div>
</nav>
</div>
<!-- End of Navigation Bar -->
<!-- Main Content -->
{% block content %}
{% endblock %}
</div>
</div>
<!-- Bootstrap 5 JS Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Additional Scripts -->
{% block extra_js %}
{% endblock %}
</body>
</html>
```
將舊的 `home.html` 刪除,並重新貼上,修正成 **MVC架構** 的html模板。
> **==home.html==**[color=#42cbed]
```python=1
{% extends 'base.html' %}
{% block title %}
輿情分析平台 - 熱門關鍵詞分析
{% endblock %}
{% block content %}
<div class="col-lg-12">
<h1>各類新聞最熱門的關鍵詞</h1>
<p>熱門度分析:可以了解新聞關注那些重要的東東</p>
</div>
<!-- 新聞類別選單 -->
<div class="col-lg-6 mb-2">
<div class="card">
<div class="card-header">
<h3 class="h6 text-uppercase mb-0">熱門關鍵字瀏覽與繪圖(資料週期:資料截止時間的前4周)</h3>
</div>
<div class="card-body">
<!-- 新聞類別選單 form group -->
<div class="mb-3 row">
<label class="col-sm-3 form-label">新聞類別</label>
<div class="col-md-9">
<select id="cate-selected" name="news_category" class="form-select">
<!-- <option>請選擇</option> -->
<option>全部</option>
<option>人物</option>
<option>議題</option>
<option>新聞</option>
<option>雜吹</option>
</select>
<div class="form-text">請選擇新聞類別</div>
</div>
</div>
<!-- form group -->
<!-- 熱門詞多少個?form group -->
<div class="mb-3 row">
<label class="col-md-3 form-label">多少個熱門詞?</label>
<div class="col-md-9">
<input id="topk-selected" name="topk" value="10" class="form-control" />
<div class="form-text">內定值為10</div>
</div>
</div>
<!-- form group -->
<!-- submit按鈕form group -->
<div class="mb-3 row">
<div class="col-md-9 ms-auto">
<button type="button" id="btn-ok" class="btn btn-primary">查詢</button>
</div>
</div>
<!-- form group -->
</div>
<!-- card body -->
</div>
<!-- column -->
</div>
<!-- 區塊結束 -->
<!-- 繪圖區塊--- -->
<div class="col-lg-6 mb-5">
<div class="card">
<div class="card-header">
<h3 class="h6 text-uppercase mb-0">熱門關鍵字繪圖</h3>
</div>
<div class="card-body">
<canvas id="mychart"></canvas>
</div>
</div>
</div>
<!-- 區塊結束 -->
<!-- 熱門關鍵字區塊--- -->
<div class="col-lg-6 mb-5">
<div class="card">
<div class="card-header">
<h3 class="h6 text-uppercase mb-0">熱門關鍵字</h3>
</div>
<div class="card-body">
<ul id="topkeys"></ul>
</div>
</div>
</div>
<!-- 區塊結束 -->
{% endblock %}
{% block extra_js %}
<!-- chartjs圖js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
<!-- 程式碼區 -->
<script>
// Show default top words bar chart when the page is loaded.
// Invoke callAjax() after the function is defined, unless callAjax() is defined with "hoisting"
callAjax()
//*新聞類別選單select被選中值有改變時,執行以下事件
//$('#cate-selected').on('change', callAjax() );
$('#cate-selected').on('change', function () {
callAjax()
}) //event function
//**按鈕事件
$('#btn-ok').on('click', function () {
callAjax()
}) //event function
// ** draw chart using Ajax 畫圖
// There are two ways to define a function:
// one is expression, and the other is definition with "hoisting"
// function with hoisting: function callAjax() {}
// normal function expression: let callAjax = function() {}
// Define callAjax function with hoisting
// callAjax()這樣定義可以在被定義前就被使用 跟我們在Java裡面的函數用法一樣!
//let callAjax = function() {
function callAjax() {
let cate = $('#cate-selected').val()
//console.log(cate);
let topk = $('#topk-selected').val()
//console.log(topk);
$.ajax({
type: 'POST',
//url: "/topword/api_get_cate_topword/",
url: 'http://127.0.0.1:8000/topword/api_get_cate_topword/',
//url: "http://163.18.23.21:8000/topword/api_get_cate_topword/",
//url: "api_get_cate_topword/", //Not recommended!
data: {
news_category: cate,
topk: topk
},
success: function (received) {
//console.log(received);
let chart_data = received.chart_data
let wf_pairs = received.wf_pairs
console.log(wf_pairs)
showTopKeys(wf_pairs)
showChart(chart_data)
} //success function
}) //ajax
} //callAjax
//* 顯示關鍵詞資料函數
function showTopKeys(items) {
//先清除前一次的資料
$('#topkeys').empty()
//將內容加上li標籤附加起來,顯示在顯示區"topkeys"
for (let i = 0; i < items.length; i++) {
let item_li = '<li>' + items[i] + '</li>'
$('#topkeys').append(item_li)
}
} //function
//**繪圖函數showChart()
function showChart(chart_data) {
// 畫圖需要的數據資料
let values = chart_data.values
let labels = chart_data.labels
let category = chart_data.category
//第1個變數: 餵給chart的資料
let data = {
labels: labels,
datasets: [
{
label: category,
data: values,
backgroundColor: randomColors(values.length),
borderColor: randomColors(values.length),
borderWidth: 1
}
]
}
//第2個變數: chart的選項 指定y坐標軸從零開始顯示
let options = {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}
]
}
}
//取得在前面html區域欲顯示的圖代號
let canvas_mychrat = document.getElementById('mychart')
//**先清除前一個圖 再繪新圖
// 可以印出barchart物件是否存在
// console.log(window.barchart);
//先清除前一個圖 再繪新圖 if 有以下兩種寫法皆可
// if (window.barchart) //若存在則為true
// if (typeof (barchart) != "undefined"){
if (window.barchart) {
barchart.destroy()
}
//**繪圖(產生一個圖物件變數名稱為barchart)
// 必須全域變數--注意:前面不要有let, var, const等修飾詞
// 理由: 我們要讓它存在於網頁全域變數,
// 這樣我們才方便判斷是否有前一次的圖,如果存在有,要刪除之,否則,很多張圖會疊在一起
barchart = new Chart(canvas_mychrat, {
type: 'bar',
data: data,
options: options
})
//** 產生隨機顏色
function randomColors(num_colors) {
let colors = []
for (i = 0; i < num_colors; i++) {
let r = Math.floor(Math.random() * 255)
let g = Math.floor(Math.random() * 255)
let b = Math.floor(Math.random() * 255)
let rgb = `rgba(${r},${g},${b},0.5)` // (red, green, blue, alfa) alfa透明度
colors.push(rgb)
}
return colors
}
} //show chart function
// document就是這個網頁HTML所有的元素
// window就是這個網頁的全域變數global variables:有一大堆,我們自己定義的有callAjax, showChart, barchart等
// 把document, window印出來看看就能理解它們是甚麼
//console.log(document);
//console.log(window);
</script>
{% endblock %}
```
##### 最後結果呈現





---
:::spoiler 最後更新日期
>==第一版==[time=2025 3 20 , 1:58 AM][color=#786ff7]
>第二版[time=2025 3 27 , 11:24 PM][color=#ce770c]
<!-- >第三版[time=2025 3 24 , 3:20 PM][color=#ce770c] -->
>**最後版[time=2025 3 27 , 11:24 PM]**[color=#EA0000]
:::