使用 Python 利用 Google Trends 试试看
Google Trends 让我们可以一窥全世界人们感兴趣的话题。通过了解热门话题以及兴趣的变化,企业、内容创作者和营销人员可以获取宝贵的见解。使用 Python,我们可以自动化从 Google Trends 收集数据的过程,并将数据存储在本地的 SQLite 数据库中,并利用 Bootstrap 和 JS Charts 来可视化和深入分析这些数据。
这篇文章涵盖了搭建虚拟环境、收集每日的数据趋势、本地存储数据以及创建一个供浏览器使用的交互界面。
最终结果会是这样的:
使用 Python 获取的 Google 趋势数据
搭建您的Python环境在开始编写代码之前,我们先设置一个虚拟环境来管理包。这样可以确保项目有一个干净的环境,不会干扰系统范围内的Python包和/或版本。
适用于 Windows:
python -m venv google_trends_env
google_trends_env\Scripts\activate
这会创建一个名为google_trends_env的虚拟环境,然后激活它。
适用于 Linux 和 Mac:
python3 -m venv google_trends_env # 在Unix-like系统中运行的命令
source google_trends_env/bin/activate # 激活名为google_trends_env的虚拟环境
在环境被激活之后,安装所需的软件包。
pip install pytrends flask pandas
**pytrends**
:一个用于获取Google Trends数据的库。**flask**
:一个轻量级的Web框架,用来创建本地服务器展示数据。**pandas**
:用于数据操作。**sqlite3**
:内置的Python库,用于操作SQLite数据库。(无需通过pip安装sqlite3)
我们将创建三个主要的文件。
**createdb.py**
: 创建数据库的脚本,设置 SQLite 数据库以存储 Google 趋势数据。**app.py**
: 应用程序脚本,获取 Google 趋势数据并将其插入数据库。**flaskapp.py**
: 一个 Flask 程序,通过带有交互式图表的网页界面展示趋势数据。
完成之后,你的文件结构应该像这样:
google_trends_app/
├── google_trends_env/ # 依赖的虚拟环境
├── app.py # 获取 Google 趋势数据并将数据存入数据库中
├── createdb.py # 初始化 SQLite 数据库和表以存储趋势数据
├── flaskapp.py # 提供 web 接口并管理数据交互的 Flask 应用程序
├── trends.db
文件名:createdb.py
此脚本启动一个SQLite数据库,并创建一个用于存储日趋势数据的表。
# 导入sqlite3模块
import sqlite3
# 从datetime模块导入datetime
from datetime import datetime
# 连接到SQLite数据库
conn = sqlite3.connect("trends.db")
cursor = conn.cursor()
# 创建一个名为daily_trends的表,用于存储每日趋势数据
cursor.execute('''CREATE TABLE IF NOT EXISTS daily_trends (
id INTEGER PRIMARY KEY,
date DATE,
trend_name TEXT,
searches INTEGER,
source TEXT,
interest_over_time TEXT # 随时间变化的兴趣
)''')
# 提交事务
conn.commit()
# 关闭数据库连接
conn.close()
- 解释:此脚本会创建一个名为
trends.db
的数据库文件,并在其中建立一个名为daily_trends
的表。该表存储每个趋势的信息,包括日期、趋势名称、平均搜索兴趣、来源(例如 "Google Trends"),以及一段时间内兴趣值的 JSON 格式字符串。
要运行此脚本并创建数据库。
运行脚本 python createdb.py
app.py
这个脚本从Google Trends获取每日热门搜索词并存入数据库。
# app.py
from pytrends.request import TrendReq
import pandas as pd
from datetime import datetime
import sqlite3
import json
def fetch_daily_trends():
pytrends = TrendReq()
today = datetime.today().date()
conn = sqlite3.connect("trends.db")
cursor = conn.cursor()
# 检查今天的趋势数据是否已经存在于数据库中
cursor.execute("SELECT * FROM daily_trends WHERE date = ?", (today,))
if cursor.fetchone():
conn.close()
return False # 如果今天的数据已存在,就返回 False
# 获取并处理热门搜索数据(如代码所示)
trending_data = pytrends.trending_searches(pn='united_states')
trending_data.columns = ["trend_name"]
for index, row in trending_data.iterrows():
trend_name = row["trend_name"]
pytrends.build_payload([trend_name])
interest_over_time_df = pytrends.interest_over_time()
if not interest_over_time_df.empty:
interest_values = interest_over_time_df[trend_name].tolist()
interest_json = json.dumps(interest_values)
avg_search_interest = sum(interest_values) / len(interest_values)
cursor.execute(
'''INSERT INTO daily_trends (date, trend_name, searches, source, interest_over_time)
VALUES (?, ?, ?, ?, ?)''',
(today, trend_name, avg_search_interest, "Google Trends", interest_json)
)
conn.commit()
conn.close()
return True # 如果数据被成功获取并插入,则返回 True (真)
- 解释:此功能使用
pytrends
工具获取美国当天的热门趋势,记录每个趋势随时间的兴趣变化,并保存到trends.db
数据库中。通过检查今天的数据是否已保存来避免数据重复。
flaskapp.py
这个文件创建了一个Flask应用,可以用来互动地展示趋势数据分析。
from flask import Flask, render_template_string, jsonify
import sqlite3
from app import fetch_daily_trends
import warnings
from datetime import datetime, timedelta
warnings.filterwarnings("ignore", category=FutureWarning)
app = Flask(__name__)
@app.route("/")
def index():
conn = sqlite3.connect("trends.db")
cursor = conn.cursor()
cursor.execute("SELECT id, date, trend_name, searches, interest_over_time FROM daily_trends ORDER BY date DESC LIMIT 10")
trends = cursor.fetchall()
conn.close()
html = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Google Trends</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div class="container mt-5">
<h2 class="text-center mt-5">每日 Google 趋向</h2>
<button id="getTrends" class="btn btn-primary mb-4">获取每日趋向</button>
<div class="alert alert-success d-none" id="successMessage">数据导入成功!</div>
<div class="alert alert-info d-none" id="alreadyFetchedMessage">今日的趋势已经获取。</div>
<div class="alert alert-info d-none" id="loadingMessage">正在获取数据,请稍等...</div>
<div class="progress d-none" id="progressBar">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%;" id="progress" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<table class="table">
<thead>
<tr>
<th>日期</th>
<th>趋向</th>
<th>平均兴趣</th>
<th>随时间变化的兴趣</th>
</tr>
</thead>
<tbody>
{% for trend in trends %}
<tr>
<td>{{ trend[1] }}</td> <!-- 日期 -->
<td>{{ trend[2] }}</td> <!-- 趋向名称 -->
<td>{{ trend[3] }}</td> <!-- 平均搜索兴趣 -->
<td>
<select id="rangeSelect{{ trend[0] }}" onchange="updateChart{{ trend[0] }}()">
<option value="7">最近 7 天</option>
<option value="30">最近 30 天</option>
<option value="all">所有数据</option>
</select>
<canvas id="chart{{ trend[0] }}" style="width: 100%; height: 150px;"></canvas>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
const trends = {{ trends | tojson }};
console.log("收集到的趋势数据:", trends);
{% for trend in trends %}
let interestData{{ trend[0] }} = JSON.parse({{ trend[4] | tojson | safe }});
let ctx{{ trend[0] }} = document.getElementById("chart{{ trend[0] }}").getContext('2d');
// 创建初始图表,显示最近 7 天的走势
let chart{{ trend[0] }} = new Chart(ctx{{ trend[0] }}, {
type: 'line',
data: {
labels: generateLabels(7),
datasets: [{
label: "{{ trend[2] }} 随时间变化的兴趣(最近 7 天)",
data: interestData{{ trend[0] }}.slice(-7),
fill: false,
borderColor: 'green',
borderWidth: 1
}]
},
options: {
scales: {
x: { title: { display: true, text: "日期" } },
y: {
title: { display: true, text: "兴趣水平" },
beginAtZero: true
}
}
}
});
function updateChart{{ trend[0] }}() {
let selectedRange = document.getElementById("rangeSelect{{ trend[0] }}").value;
let newData, newLabels;
if (selectedRange === "7") {
newData = interestData{{ trend[0] }}.slice(-7);
newLabels = generateLabels(7);
} else if (selectedRange === "30") {
newData = interestData{{ trend[0] }}.slice(-30);
newLabels = generateLabels(30);
} else if (selectedRange === "all") {
newData = getWeeklyTotals(interestData{{ trend[0] }});
newLabels = Array.from({length: newData.length}, (_, i) => `第 ${i + 1} 周`);
}
chart{{ trend[0] }}.data.labels = newLabels;
chart{{ trend[0] }}.data.datasets[0].data = newData;
chart{{ trend[0] }}.data.datasets[0].label = "{{ trend[2] }} 随时间变化的兴趣 (" + (selectedRange === "all" ? "所有数据(按周)" : `最近 ${selectedRange} 天`) + ")";
chart{{ trend[0] }}.update();
}
{% endfor %}
document.getElementById("getTrends").onclick = function() {
document.getElementById("loadingMessage").classList.remove("d-none"); // 显示加载信息
document.getElementById("progressBar").classList.remove("d-none"); // 显示进度条
document.getElementById("progress").style.width = "0%"; // 重置进度条
fetch("/fetch_trends").then(response => response.json()).then(data => {
// 加载完成后隐藏加载信息
document.getElementById("loadingMessage").classList.add("d-none");
if (data.already_fetched) {
document.getElementById("alreadyFetchedMessage").classList.remove("d-none");
document.getElementById("successMessage").classList.add("d-none");
} else {
document.getElementById("successMessage").classList.remove("d-none");
document.getElementById("alreadyFetchedMessage").classList.add("d-none");
}
// 模拟进度更新
let progress = 0;
const interval = setInterval(() => {
progress += 10; // 更新进度
document.getElementById("progress").style.width = progress + "%"; // 更新进度条
if (progress >= 100) {
clearInterval(interval); // 完成后停止间隔
document.getElementById("progressBar").classList.add("d-none"); // 完成后隐藏进度条
location.reload(); // 重新加载以显示新数据
}
}, 500); // 每隔 500 毫秒更新一次
});
};
// 生成日期标签的函数
function generateLabels(dataLength) {
let labels = [];
for (let i = 0; i < dataLength; i++) {
let date = new Date();
date.setDate(date.getDate() - (dataLength - 1 - i));
labels.push(date.toISOString().slice(0, 10)); // 格式化为 YYYY-MM-DD
}
return labels;
}
// 计算每周总数的函数
function getWeeklyTotals(data) {
let weeklyTotals = [];
for (let i = 0; i < data.length; i += 7) {
let weekTotal = data.slice(i, i + 7).reduce((acc, val) => acc + val, 0);
weeklyTotals.push(weekTotal);
}
return weeklyTotals;
}
</script>
</body>
</html>
"""
return render_template_string(html, trends=trends)
@app.route("/fetch_trends")
def fetch_trends():
data_fetched = fetch_daily_trends()
return jsonify(success=True, already_fetched=not data_fetched)
if __name__ == "__main__":
app.run(debug=True)
解释
**index()**
:获取最新的趋势数据,并使用嵌入的HTML模板来渲染,该模板使用Chart.js
来显示兴趣随时间的变化情况。- 获取趋势数据按钮:点击这个按钮会触发数据获取。
每个趋势都有一个下拉列表,包含三个选项。
- 最近7天(默认) — 该选项从
interest_over_time
列表中拉取最近的7个数据点。 - 最近30天 — 该选项从
interest_over_time
列表中拉取最近30个数据点。 - 所有数据点(按周汇总) — 该选项通过计算每周总计来汇总整个数据集,提供一段时间内趋势流行的整体视图。
每次下拉选择改变时,它会触发一个特定于该图表的updateChart
函数。此函数。
- 确认所选的时间段。
- 根据选择更新图表上的数据点。
我们来看看“所有数据点”的数据聚合是如何工作的
当你选择“所有数据点”选项时,每个趋势的数据将被分组为每周的总计。下面是如何进行这种汇总的:
- 获取所有数据点:访问
interest_over_time
中的所有数据点。 - 按周汇总:每7天的数据点汇总为一个点。
- 显示每周总计:每个聚合点代表7天内的累积数据,从而呈现出更平滑的趋势。
通过按周分组数据,此视图减少了每天波动带来的噪音,提供了更宽广的视角来观察整体趋势。每个汇总周显示为图表中的一个独立点,标记为“第1周”、“第2周”等,使用户一目了然,更容易理解长时间趋势变化。
进度栏应用程序中的进度条在数据获取时为用户提供视觉反馈。当点击“获取每日趋势”按钮时,会显示进度条和加载消息,表示正在加载最新的谷歌趋势。
一旦数据获取完成,进度条将被隐藏。用户会收到数据成功导入的通知或相关状态更新信息。
运行 Flask 应用要在浏览器里看应用,请运行以下命令行:npm start
运行 Python 脚本 `python flaskapp.py`。这会启动一个 Flask 应用程序: `python flaskapp.py`。
打开网页浏览器,然后访问 http://127.0.0.1:5000
查看你历史的 Google Trends 数据可视化结果!图表会根据下拉菜单的选择动态更新,让你的分析体验更加个性化。
感谢您阅读这篇文章。希望这篇文章对您有所帮助和启发。如果您有任何疑问,或者有新的Python代码示例或未来教程主题的建议,请随时联系我。您的反馈和建议总是很宝贵,欢迎随时与我分享。
祝你编程愉快!
C. C. Python编程课
共同学习,写下你的评论
评论加载中...
作者其他优质文章