实用脚本能自动统计URL访问量吗?

wen 实用脚本 1

本文目录导读:

实用脚本能自动统计URL访问量吗?

  1. 方案一:Nginx 日志 + 一行 Shell 命令(最轻量)
  2. 方案二:Python 脚本(简单易用,可扩展)
  3. 方案三:Node.js 脚本(适合实时Web服务)
  4. 方案四:专业方式 - 嵌入代码(推荐用于生产环境)
  5. 如何选择?
  6. 注意事项

可以,统计URL访问量是Web开发中的常见需求,下面提供几种实用且能自动运行的脚本方案,从简单到复杂,你可以根据技术栈和场景选择。

Nginx 日志 + 一行 Shell 命令(最轻量)

如果你的网站使用 Nginx 作为反向代理,它的访问日志文件本身就记录了所有请求的URL,用下面的脚本可以自动统计实时或历史的访问量。

  1. 命令脚本:统计所有URL的访问次数,按从高到低排序。

    # 统计 access.log 中,第7列(请求的URL路径,不含域名)的出现次数
    awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
  2. 自动刷新脚本:保存为 watch_url.sh,每5秒自动刷新一次。

    #!/bin/bash
    while true; do
        clear
        echo "===== 当前URL访问量 Top 10 (每5秒刷新) ====="
        awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
        sleep 5
    done

    运行:bash watch_url.sh

Python 脚本(简单易用,可扩展)

使用Python可以更灵活地处理数据,比如统计今天、过去1小时的数据,或者输出为JSON。

# url_stats.py
import re
from collections import Counter
from datetime import datetime, timedelta
LOG_FILE = "/var/log/nginx/access.log"
def count_urls(time_window_minutes=None):
    """
    统计URL访问量
    :param time_window_minutes: 可选,只统计最近N分钟内的访问
    """
    urls = []
    now = datetime.now()
    with open(LOG_FILE, "r") as f:
        for line in f:
            # 解析日志行,提取时间戳和URL路径
            # 常见Nginx日志格式:127.0.0.1 - - [10/Oct/2023:13:55:36 +0000] "GET /api/v1/users HTTP/1.1" 200 1234
            match = re.search(r'\[(\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2}).*?"(\w+)\s+(/\S*)', line)
            if not match:
                continue
            log_time_str = match.group(1)
            url = match.group(3)
            if time_window_minutes:
                log_time = datetime.strptime(log_time_str, "%d/%b/%Y:%H:%M:%S")
                if (now - log_time) > timedelta(minutes=time_window_minutes):
                    continue
            urls.append(url)
    return Counter(urls)
if __name__ == "__main__":
    # 统计最近30分钟的Top 10
    stats = count_urls(time_window_minutes=30)
    print("最近30分钟内 TOP 10 URL 访问量:")
    for url, count in stats.most_common(10):
        print(f"{count:>5}  {url}")

运行方式: python url_stats.py

Node.js 脚本(适合实时Web服务)

如果你希望统计结果可被前端直接请求,可以用Node.js。

// url_stats_server.js
const express = require('express');
const fs = require('fs');
const readline = require('readline');
const app = express();
const LOG_FILE = '/var/log/nginx/access.log';
const PORT = 3000;
// 存储统计结果
let urlCounts = {};
function parseLog() {
    console.log('更新统计...');
    const counts = {};
    const rl = readline.createInterface({
        input: fs.createReadStream(LOG_FILE),
        crlfDelay: Infinity
    });
    rl.on('line', (line) => {
        // 简单正则提取URL
        const match = line.match(/"(?:GET|POST|PUT|DELETE)\s+(\/\S*)/);
        if (match) {
            const url = match[1];
            counts[url] = (counts[url] || 0) + 1;
        }
    });
    rl.on('close', () => {
        urlCounts = counts;
        console.log(`统计完成,共 ${Object.keys(counts).length} 个URL`);
    });
}
// 每30秒重新解析一次日志
setInterval(parseLog, 30000);
parseLog(); // 首次启动时立即统计
app.get('/api/url-stats', (req, res) => {
    // 返回排序后的Top 20
    const sorted = Object.entries(urlCounts)
        .sort((a, b) => b[1] - a[1])
        .slice(0, 20)
        .map(([url, count]) => ({ url, count }));
    res.json(sorted);
});
app.listen(PORT, () => {
    console.log(`URL统计API运行在 http://localhost:${PORT}/api/url-stats`);
});

运行: node url_stats_server.js,然后访问 http://localhost:3000/api/url-stats 即可看到JSON格式的统计结果。

专业方式 - 嵌入代码(推荐用于生产环境)

生产环境几乎不使用解析日志的方式,而是在应用层直接埋点统计,因为:

  • 日志解析有延迟
  • 长连接(WebSocket)不写日志
  • 静态资源CDN不会返回日志

JavaScript 前端埋点示例:

// 在每个页面或API调用时,发送统计请求
function trackPageView() {
    fetch('/api/track?url=' + encodeURIComponent(window.location.pathname), {
        method: 'GET',
        // 使用1x1像素图片代替 fetch,避免跨域问题(更稳妥)
    });
}
// 用 img 标签发送(最兼容,且不阻塞页面)
new Image().src = '/track.gif?url=' + encodeURIComponent(window.location.pathname);

后端接收(Node.js + Redis示例):

// 服务端接收埋点并计数(挂载在 /track 路由)
app.get('/track', (req, res) => {
    const url = req.query.url || '/';
    redisClient.incr(`url_count:${url}`); // 在Redis中递增计数
    // 返回透明1x1像素图片
    res.writeHead(200, { 'Content-Type': 'image/gif' });
    res.end(Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64'));
});
// 获取统计
app.get('/api/stats', (req, res) => {
    redisClient.keys('url_count:*', (err, keys) => {
        const pipeline = redisClient.pipeline();
        keys.forEach(key => pipeline.get(key));
        pipeline.exec((err, results) => {
            const data = keys.map((key, i) => ({
                url: key.replace('url_count:', ''),
                count: parseInt(results[i][1] || 0)
            }));
            res.json(data.sort((a,b) => b.count - a.count).slice(0,20));
        });
    });
});

如何选择?

场景 推荐方案 理由
临时调试、快速查看 方案一(Shell) 无需安装、秒级执行
需要对历史数据做复杂分析 方案二(Python) 容易写条件过滤和时间窗口
需要实时Web接口供其他系统调用 方案三(Node.js) 自带HTTP服务器
生产环境、高并发 方案四(埋点+Redis) 延迟低、不占磁盘、可弹性扩展

注意事项

  1. 权限问题:读取 /var/log/nginx/access.log 通常需要 sudo 或让用户加入 adm 组。
  2. 日志轮转:生产环境日志会按天切割,如果使用方案一/二,需要关注日志文件名(如 access.log.1)。
  3. 性能影响:解析100MB以上的日志文件时,Python/Node脚本会消耗一定CPU,建议用 tail -0f 跟随最新日志(流式处理)代替重新读全量文件。
  4. 去重:如果统计UV(独立访客),需要在统计时加入IP或Cookie作为标识。

如果需要我针对某个方案(比如Python脚本的详细解读或Node.js的实时推送到WebSocket),可以告诉我。

抱歉,评论功能暂时关闭!