为了账号安全,请及时绑定邮箱和手机立即绑定

使用Python抓取并展示Google Trends数据的教程

使用 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

文件2: 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 数据库中。通过检查今天的数据是否已保存来避免数据重复。
文件3: 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编程课

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消