本文目录导读:

- 方案一:Nginx 日志 + 一行 Shell 命令(最轻量)
- 方案二:Python 脚本(简单易用,可扩展)
- 方案三:Node.js 脚本(适合实时Web服务)
- 方案四:专业方式 - 嵌入代码(推荐用于生产环境)
- 如何选择?
- 注意事项
可以,统计URL访问量是Web开发中的常见需求,下面提供几种实用且能自动运行的脚本方案,从简单到复杂,你可以根据技术栈和场景选择。
Nginx 日志 + 一行 Shell 命令(最轻量)
如果你的网站使用 Nginx 作为反向代理,它的访问日志文件本身就记录了所有请求的URL,用下面的脚本可以自动统计实时或历史的访问量。
-
命令脚本:统计所有URL的访问次数,按从高到低排序。
# 统计 access.log 中,第7列(请求的URL路径,不含域名)的出现次数 awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20 -
自动刷新脚本:保存为
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) | 延迟低、不占磁盘、可弹性扩展 |
注意事项
- 权限问题:读取
/var/log/nginx/access.log通常需要sudo或让用户加入adm组。 - 日志轮转:生产环境日志会按天切割,如果使用方案一/二,需要关注日志文件名(如
access.log.1)。 - 性能影响:解析100MB以上的日志文件时,Python/Node脚本会消耗一定CPU,建议用
tail -0f跟随最新日志(流式处理)代替重新读全量文件。 - 去重:如果统计UV(独立访客),需要在统计时加入IP或Cookie作为标识。
如果需要我针对某个方案(比如Python脚本的详细解读或Node.js的实时推送到WebSocket),可以告诉我。