当前位置:首页>python>Python 零基础100天—Day32 综合练习

Python 零基础100天—Day32 综合练习

  • 2026-06-27 22:49:52
Python 零基础100天—Day32 综合练习

🐍 综合练习 — 批量文件重命名 + 日志分析

🕐 预计用时:3-4 小时 | 🎯 目标:用 Day26-31 所学知识完成两个实战项目


📖 今日目录

  1. 项目一:批量文件重命名工具
  2. 需求分析与设计
  3. 基础版:按序号重命名
  4. 进阶版:正则替换重命名
  5. 高级版:按日期/EXIF 信息重命名
  6. 完整版:带预览和撤销的 CLI 工具
  7. 项目二:日志文件分析器
  8. 日志格式与解析
  9. 统计与分析功能
  10. 生成分析报告
  11. 今日小结

1. 项目一:批量文件重命名工具

场景:你下载了一堆文件,名字乱七八糟(IMG_001.jpg、photo(2).png、新建文件夹(3).txt……),想统一重命名。

需求分析

功能
说明
用到的知识
按序号重命名
file_001, file_002, ...
os.listdir, os.rename
正则替换
把文件名中的空格换成下划线
re 模块
添加前缀/后缀
在文件名前加日期
字符串操作
修改扩展名
.jpeg → .jpg
os.path.splitext
预览模式
先看效果再执行
dry_run 设计
撤销功能
后悔了能还原
JSON 记录历史

2. 基础版:按序号重命名

import osfrom pathlib import Pathdef rename_sequential(directory, prefix="file", ext_filter=None, start=1):    """按序号批量重命名    Args:        directory: 目标目录        prefix: 文件名前缀        ext_filter: 只处理指定扩展名(如 ".jpg")        start: 起始序号    """    target = Path(directory)    if not target.is_dir():        print(f"❌ 目录不存在: {directory}")        return    # 获取所有文件(不包括目录)    files = sorted([        f for f in target.iterdir()        if f.is_file()    ])    # 如果指定了扩展名过滤    if ext_filter:        files = [f for f in files if f.suffix.lower() == ext_filter.lower()]    if not files:        print("⚠️ 没有找到匹配的文件")        return    print(f"📂 目录: {target}")    print(f"📄 找到 {len(files)} 个文件")    print()    # 重命名    padding = len(str(len(files) + start - 1))  # 序号位数    renamed = []    for i, filepath in enumerate(files, start=start):        new_name = f"{prefix}_{str(i).zfill(padding)}{filepath.suffix}"        new_path = filepath.parent / new_name        # 避免覆盖已有文件        if new_path.exists():            print(f"⚠️ 跳过 {filepath.name} → {new_name}(目标已存在)")            continue        filepath.rename(new_path)        renamed.append((str(filepath), str(new_path)))        print(f"✅ {filepath.name} → {new_name}")    print(f"\n完成: 重命名 {len(renamed)} 个文件")    return renamed
# 使用示例:创建测试文件from pathlib import Pathimport os# 创建测试目录和文件test_dir = Path("test_rename")test_dir.mkdir(exist_ok=True)for name in ["photo 1.jpg", "IMG_002.jpg", "picture(3).jpg", "新建文件.jpg"]:    (test_dir / name).touch()# 按序号重命名rename_sequential(test_dir, prefix="photo", ext_filter=".jpg")# 结果:# ✅ IMG_002.jpg → photo_1.jpg# ✅ photo 1.jpg → photo_2.jpg# ✅ picture(3).jpg → photo_3.jpg# ✅ 新建文件.jpg → photo_4.jpg

3. 进阶版:正则替换重命名

import osimport refrom pathlib import Pathdef rename_regex(directory, pattern, replacement, ext_filter=None, dry_run=True):    """用正则表达式批量重命名    Args:        directory: 目标目录        pattern: 正则表达式模式        replacement: 替换文本        ext_filter: 只处理指定扩展名        dry_run: True=只预览不执行    """    target = Path(directory)    files = sorted([f for f in target.iterdir() if f.is_file()])    if ext_filter:        files = [f for f in files if f.suffix.lower() == ext_filter.lower()]    print(f"{'🔍 预览模式' if dry_run else '⚡ 执行模式'}")    print(f"规则: '{pattern}' → '{replacement}'")    print("-" * 50)    renamed = []    for filepath in files:        stem = filepath.stem        new_stem = re.sub(pattern, replacement, stem)        if new_stem == stem:            continue  # 没变化,跳过        new_name = new_stem + filepath.suffix        new_path = filepath.parent / new_name        if not dry_run:            if new_path.exists():                print(f"⚠️ 跳过 {filepath.name}(目标已存在)")                continue            filepath.rename(new_path)        renamed.append((filepath.name, new_name))        print(f"{'🔍' if dry_run else '✅'} {filepath.name} → {new_name}")    action = "将被" if dry_run else "已"    print(f"\n{action}重命名: {len(renamed)} 个文件")    return renamed
# 使用示例# 1. 空格换成下划线rename_regex("test_rename", r"\s+", "_")# 2. 去掉括号及内容rename_regex("test_rename", r"\(.*?\)", "")# 3. 统一日期格式:2024.01.15 → 2024-01-15rename_regex("test_rename", r"(\d{4})\.(\d{2})\.(\d{2})", r"\1-\2-\3")# 4. 去掉中文字符rename_regex("test_rename", r"[\u4e00-\u9fff]+", "")# 5. 全部转小写(需要自定义函数)def rename_lowercase(directory, ext_filter=None, dry_run=True):    """文件名全部转小写"""    target = Path(directory)    files = sorted([f for f in target.iterdir() if f.is_file()])    if ext_filter:        files = [f for f in files if f.suffix.lower() == ext_filter.lower()]    renamed = []    for filepath in files:        new_name = filepath.name.lower()        if new_name != filepath.name:            new_path = filepath.parent / new_name            if not dry_run:                filepath.rename(new_path)            renamed.append((filepath.name, new_name))            print(f"{'🔍' if dry_run else '✅'} {filepath.name} → {new_name}")    return renamed

⚠️ dry_run 模式很重要!批量重命名是不可逆操作,一定要先预览(dry_run=True),确认无误后再执行(dry_run=False)。


4. 高级版:按日期重命名

import osimport timefrom datetime import datetimefrom pathlib import Pathdef rename_by_date(directory, date_format="%Y%m%d_%H%M%S", ext_filter=None, dry_run=True):    """按文件修改日期重命名    Args:        directory: 目标目录        date_format: 日期格式        ext_filter: 只处理指定扩展名        dry_run: True=只预览不执行    """    target = Path(directory)    files = sorted([f for f in target.iterdir() if f.is_file()])    if ext_filter:        files = [f for f in files if f.suffix.lower() == ext_filter.lower()]    # 检查重名(同一秒可能有多个文件)    name_count = {}    print(f"{'🔍 预览模式' if dry_run else '⚡ 执行模式'}")    print("-" * 50)    renamed = []    for filepath in files:        # 获取修改时间        mtime = filepath.stat().st_mtime        dt = datetime.fromtimestamp(mtime)        # 生成新文件名        base_name = dt.strftime(date_format)        # 处理重名:加后缀 _1, _2, ...        if base_name in name_count:            name_count[base_name] += 1            base_name = f"{base_name}_{name_count[base_name]}"        else:            name_count[base_name] = 0        new_name = f"{base_name}{filepath.suffix}"        new_path = filepath.parent / new_name        if not dry_run:            filepath.rename(new_path)        renamed.append((filepath.name, new_name))        print(f"{'🔍' if dry_run else '✅'} {filepath.name} → {new_name}")    print(f"\n{'将被' if dry_run else '已'}重命名: {len(renamed)} 个文件")    return renamed
# 使用示例rename_by_date("test_rename", date_format="%Y-%m-%d_%H%M%S", dry_run=True)# 结果:# 🔍 IMG_002.jpg → 2024-01-15_143025.jpg# 🔍 photo 1.jpg → 2024-01-15_143026.jpg# 🔍 picture(3).jpg → 2024-01-15_143027.jpg# 🔍 新建文件.jpg → 2024-01-15_143028.jpg

5. 完整版:带预览和撤销的 CLI 工具

import osimport reimport jsonimport argparsefrom pathlib import Pathfrom datetime import datetimeclass BatchRenamer:    """批量重命名工具(支持撤销)"""    def __init__(self, directory):        self.directory = Path(directory)        self.history_file = self.directory / ".rename_history.json"        self.history = self._load_history()    def _load_history(self):        """加载历史记录"""        if self.history_file.exists():            return json.loads(self.history_file.read_text())        return []    def _save_history(self, rename_list):        """保存重命名历史(用于撤销)"""        entry = {            "timestamp": datetime.now().isoformat(),            "changes": rename_list        }        self.history.append(entry)        self.history_file.write_text(json.dumps(self.history, ensure_ascii=False, indent=2))    def list_files(self, ext_filter=None):        """列出目录中的文件"""        files = sorted([f for f in self.directory.iterdir() if f.is_file()])        if ext_filter:            files = [f for f in files if f.suffix.lower() == ext_filter.lower()]        return files    def preview(self, rename_func, **kwargs):        """预览重命名结果"""        files = self.list_files(kwargs.get("ext_filter"))        changes = []        for filepath in files:            new_name = rename_func(filepath.name, **kwargs)            if new_name and new_name != filepath.name:                changes.append((filepath.name, new_name))        if not changes:            print("⚠️ 没有需要重命名的文件")            return []        print(f"🔍 预览({len(changes)} 个文件将被重命名):")        print("-" * 60)        for old, new in changes:            print(f"  {old}")            print(f"    → {new}")        print("-" * 60)        return changes    def execute(self, changes):        """执行重命名"""        if not changes:            return        rename_list = []        for old_name, new_name in changes:            old_path = self.directory / old_name            new_path = self.directory / new_name            if new_path.exists():                print(f"⚠️ 跳过 {old_name}(目标已存在)")                continue            old_path.rename(new_path)            rename_list.append({"old": old_name, "new": new_name})            print(f"✅ {old_name} → {new_name}")        # 保存历史        if rename_list:            self._save_history(rename_list)            print(f"\n完成: 重命名 {len(rename_list)} 个文件(已保存历史,可撤销)")    def undo(self):        """撤销上一次重命名"""        if not self.history:            print("⚠️ 没有可撤销的操作")            return        last = self.history.pop()        changes = last["changes"]        print(f"⏪ 撤销 {last['timestamp']} 的操作:")        for item in changes:            old_path = self.directory / item["new"]            new_path = self.directory / item["old"]            if old_path.exists():                old_path.rename(new_path)                print(f"  ✅ {item['new']} → {item['old']}")            else:                print(f"  ⚠️ {item['new']} 不存在,跳过")        # 更新历史文件        self.history_file.write_text(json.dumps(self.history, ensure_ascii=False, indent=2))# ---- 重命名策略函数 ----def sequential_name(old_name, prefix="file", index=0, **kwargs):    """按序号重命名"""    ext = os.path.splitext(old_name)[1]    return f"{prefix}_{index:03d}{ext}"def replace_pattern(old_name, pattern="", replacement="", **kwargs):    """正则替换"""    return re.sub(pattern, replacement, old_name)def add_prefix(old_name, prefix="", **kwargs):    """添加前缀"""    return f"{prefix}{old_name}"def add_suffix(old_name, suffix="", **kwargs):    """添加后缀"""    name, ext = os.path.splitext(old_name)    return f"{name}{suffix}{ext}"def lowercase_name(old_name, **kwargs):    """转小写"""    return old_name.lower()# ---- 使用示例 ----# 创建测试test_dir = Path("test_rename")test_dir.mkdir(exist_ok=True)for name in ["Photo A.jpg", "IMG_001.jpg", "Picture (2).jpg", "新建文件.jpg"]:    (test_dir / name).touch()renamer = BatchRenamer("test_rename")# 方式1: 预览 + 确认执行changes = renamer.preview(replace_pattern, pattern=r"\s+", replacement="_")if changes:    renamer.execute(changes)# 方式2: 撤销renamer.undo()# 方式3: 序号重命名changes = renamer.preview(lambda name, **kw: f"photo_{kw['index']:03d}{os.path.splitext(name)[1]}", index=1)# 注意:上面的 lambda 每次 index 都是 1,实际需要用闭包或类方法

💡 撤销功能的设计思路:1. 每次重命名前,把 (旧名→新名) 记录到 JSON 文件2. 撤销时读取最后一次记录,反向重命名3. 这是"操作日志"模式——数据库、游戏存档都用这个思路


6. 项目二:日志文件分析器

场景:服务器每天产出大量日志文件,需要分析错误频率、请求量、响应时间等指标。

日志格式

# 典型的 Web 服务器日志格式(Apache/Nginx 风格)# 192.168.1.1 - - [15/Jan/2024:10:30:15 +0800] "GET /api/users HTTP/1.1" 200 1234# 192.168.1.2 - - [15/Jan/2024:10:30:16 +0800] "POST /api/login HTTP/1.1" 401 567# 192.168.1.1 - - [15/Jan/2024:10:30:17 +0800] "GET /api/orders HTTP/1.1" 500 0# 我们用简化的格式(方便演示)# [2024-01-15 10:30:15] [INFO] GET /api/users 200 12ms# [2024-01-15 10:30:16] [WARN] POST /api/login 401 5ms# [2024-01-15 10:30:17] [ERROR] GET /api/orders 500 150ms - DatabaseError: Connection refused

生成测试日志

import randomfrom datetime import datetime, timedeltadef generate_test_log(filename, num_lines=500):    """生成测试日志文件"""    levels = ["INFO", "INFO", "INFO", "INFO", "WARN", "ERROR"]  # INFO 概率更高    methods = ["GET", "POST", "PUT", "DELETE"]    paths = ["/api/users", "/api/login", "/api/orders", "/api/products", "/api/cart", "/api/pay"]    status_codes = [200, 200, 200, 201, 301, 400, 401, 403, 404, 500]    errors = [        "DatabaseError: Connection refused",        "TimeoutError: Request timeout",        "ValueError: Invalid parameter",        "KeyError: 'user_id'",        "PermissionError: Access denied"    ]    base_time = datetime(2024, 1, 15, 0, 0, 0)    lines = []    for i in range(num_lines):        # 随机时间(按顺序递增)        base_time += timedelta(seconds=random.randint(1, 30))        level = random.choice(levels)        method = random.choice(methods)        path = random.choice(paths)        status = random.choice(status_codes)        response_time = random.randint(1, 500)        line = f"[{base_time.strftime('%Y-%m-%d %H:%M:%S')}] [{level}] {method} {path} {status} {response_time}ms"        if level == "ERROR":            line += f" - {random.choice(errors)}"        lines.append(line)    with open(filename, "w", encoding="utf-8") as f:        f.write("\n".join(lines))    print(f"✅ 生成 {num_lines} 行日志 → {filename}")generate_test_log("app.log", 500)

7. 日志解析与统计

import refrom collections import Counter, defaultdictfrom datetime import datetimedef parse_log_line(line):    """解析一行日志"""    # 格式: [2024-01-15 10:30:15] [INFO] GET /api/users 200 12ms - ErrorMsg    pattern = r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(\w+)\] (\w+) ([^\s]+) (\d+) (\d+)ms(?: - (.+))?"    match = re.match(pattern, line)    if not match:        return None    return {        "timestamp": datetime.strptime(match.group(1), "%Y-%m-%d %H:%M:%S"),        "level": match.group(2),        "method": match.group(3),        "path": match.group(4),        "status": int(match.group(5)),        "response_time": int(match.group(6)),        "error": match.group(7) if match.group(7) else None    }def analyze_log(filepath):    """分析日志文件"""    logs = []    parse_errors = 0    with open(filepath, "r", encoding="utf-8") as f:        for line in f:            line = line.strip()            if not line:                continue            entry = parse_log_line(line)            if entry:                logs.append(entry)            else:                parse_errors += 1    if not logs:        print("⚠️ 没有解析到有效日志")        return    # ---- 统计 ----    # 1. 日志级别统计    level_counter = Counter(log["level"] for log in logs)    # 2. 状态码统计    status_counter = Counter(log["status"] for log in logs)    # 3. 请求路径统计    path_counter = Counter(log["path"] for log in logs)    # 4. HTTP 方法统计    method_counter = Counter(log["method"] for log in logs)    # 5. 响应时间统计    response_times = [log["response_time"] for log in logs]    avg_response = sum(response_times) / len(response_times)    max_response = max(response_times)    min_response = min(response_times)    # 6. 每小时请求量    hourly = Counter(log["timestamp"].hour for log in logs)    # 7. 错误日志详情    errors = [log for log in logs if log["level"] == "ERROR"]    error_types = Counter(log["error"] for log in errors if log["error"])    # ---- 输出报告 ----    print("=" * 60)    print(f"📊 日志分析报告: {filepath}")    print("=" * 60)    print(f"\n📝 基本信息:")    print(f"   总行数: {len(logs)}")    print(f"   解析失败: {parse_errors} 行")    print(f"   时间范围: {logs[0]['timestamp']} ~ {logs[-1]['timestamp']}")    print(f"\n📊 日志级别:")    for level, count in level_counter.most_common():        pct = count / len(logs) * 100        bar = "█" * int(pct / 2)        print(f"   {level:8s} {count:4d} ({pct:5.1f}%) {bar}")    print(f"\n📡 HTTP 方法:")    for method, count in method_counter.most_common():        print(f"   {method:8s} {count:4d}")    print(f"\n🔢 状态码分布:")    for status, count in status_counter.most_common():        emoji = "✅" if status < 400 else "⚠️" if status < 500 else "❌"        print(f"   {emoji} {status} {count:4d}")    print(f"\n🛤️ 热门路径 TOP 5:")    for path, count in path_counter.most_common(5):        print(f"   {path:30s} {count:4d} 次")    print(f"\n⏱️ 响应时间:")    print(f"   平均: {avg_response:.1f}ms")    print(f"   最快: {min_response}ms")    print(f"   最慢: {max_response}ms")    # 响应时间分布    fast = sum(1 for t in response_times if t < 100)    medium = sum(1 for t in response_times if 100 <= t < 300)    slow = sum(1 for t in response_times if t >= 300)    print(f"   <100ms: {fast} | 100-300ms: {medium} | >300ms: {slow}")    print(f"\n🕐 每小时请求量:")    for hour in sorted(hourly.keys()):        count = hourly[hour]        bar = "█" * (count // 2)        print(f"   {hour:02d}:00  {count:3d} {bar}")    if errors:        print(f"\n❌ 错误详情 (共 {len(errors)} 条):")        for error_type, count in error_types.most_common(5):            print(f"   {error_type}: {count} 次")    print("\n" + "=" * 60)    return {        "total": len(logs),        "levels": dict(level_counter),        "statuses": dict(status_counter),        "paths": dict(path_counter),        "avg_response_time": avg_response,        "errors": len(errors)    }# 使用result = analyze_log("app.log")

8. 生成分析报告(CSV + HTML)

import csvfrom pathlib import Pathdef export_report_csv(log_filepath, output_csv="log_report.csv"):    """导出分析报告为 CSV"""    logs = []    with open(log_filepath, "r", encoding="utf-8") as f:        for line in f:            entry = parse_log_line(line.strip())            if entry:                logs.append(entry)    # 按小时统计    from collections import defaultdict    hourly_stats = defaultdict(lambda: {"requests": 0, "errors": 0, "total_time": 0})    for log in logs:        hour = log["timestamp"].strftime("%Y-%m-%d %H:00")        hourly_stats[hour]["requests"] += 1        hourly_stats[hour]["total_time"] += log["response_time"]        if log["level"] == "ERROR":            hourly_stats[hour]["errors"] += 1    # 写入 CSV    with open(output_csv, "w", encoding="utf-8", newline="") as f:        writer = csv.writer(f)        writer.writerow(["时间段", "请求数", "错误数", "平均响应时间(ms)"])        for hour in sorted(hourly_stats.keys()):            stats = hourly_stats[hour]            avg_time = stats["total_time"] / stats["requests"] if stats["requests"] > 0 else 0            writer.writerow([hour, stats["requests"], stats["errors"], f"{avg_time:.1f}"])    print(f"✅ 报告已导出: {output_csv}")export_report_csv("app.log")
def export_report_html(log_filepath, output_html="log_report.html"):    """导出分析报告为 HTML(公众号兼容格式)"""    from collections import Counter, defaultdict    logs = []    with open(log_filepath, "r", encoding="utf-8") as f:        for line in f:            entry = parse_log_line(line.strip())            if entry:                logs.append(entry)    # 统计数据    level_counter = Counter(log["level"] for log in logs)    status_counter = Counter(log["status"] for log in logs)    path_counter = Counter(log["path"] for log in logs)    response_times = [log["response_time"] for log in logs]    errors = [log for log in logs if log["level"] == "ERROR"]    error_types = Counter(log["error"] for log in errors if log["error"])    # 生成 HTML    html = f"""<!DOCTYPE html><html><head><meta charset="utf-8"><title>日志分析报告</title><style>body {{ font-family: sans-serif; max-width: 780px; margin: 0 auto; padding: 20px; }}h1 {{ text-align: center; color: #1a1a1a; }}table {{ width: 100%; border-collapse: collapse; margin: 16px 0; }}th {{ background: #07c160; color: white; padding: 10px; text-align: left; }}td {{ padding: 8px 12px; border: 1px solid #e0e0e0; }}tr:nth-child(even) {{ background: #f9f9f9; }}</style></head><body><h1>📊 日志分析报告</h1><p>总日志: {len(logs)} 条 | 时间范围: {logs[0]['timestamp']} ~ {logs[-1]['timestamp']}</p><h2>日志级别分布</h2><table><tr><th>级别</th><th>数量</th><th>占比</th></tr>"""    for level, count in level_counter.most_common():        pct = count / len(logs) * 100        html += f"\n<tr><td>{level}</td><td>{count}</td><td>{pct:.1f}%</td></tr>"    html += """</table><h2>状态码分布</h2><table><tr><th>状态码</th><th>数量</th></tr>"""    for status, count in status_counter.most_common():        html += f"\n<tr><td>{status}</td><td>{count}</td></tr>"    html += """</table><h2>热门路径 TOP 5</h2><table><tr><th>路径</th><th>请求次数</th></tr>"""    for path, count in path_counter.most_common(5):        html += f"\n<tr><td>{path}</td><td>{count}</td></tr>"    html += f"""</table><h2>响应时间</h2><table><tr><th>指标</th><th>值</th></tr><tr><td>平均</td><td>{sum(response_times)/len(response_times):.1f}ms</td></tr><tr><td>最快</td><td>{min(response_times)}ms</td></tr><tr><td>最慢</td><td>{max(response_times)}ms</td></tr></table>"""    if error_types:        html += "\n<h2>错误类型 TOP 5</h2>\n<table>\n<tr><th>错误</th><th>次数</th></tr>"        for error, count in error_types.most_common(5):            html += f"\n<tr><td>{error}</td><td>{count}</td></tr>"        html += "\n</table>"    html += "\n</body></html>"    Path(output_html).write_text(html, encoding="utf-8")    print(f"✅ HTML 报告已导出: {output_html}")export_report_html("app.log")

9. 进阶:实时日志监控

import timeimport refrom datetime import datetimedef tail_log(filepath, callback, interval=1):    """实时监控日志文件(类似 tail -f)    Args:        filepath: 日志文件路径        callback: 每行的处理函数        interval: 检查间隔(秒)    """    print(f"👁️ 开始监控: {filepath}")    print("按 Ctrl+C 停止\n")    with open(filepath, "r", encoding="utf-8") as f:        # 跳到文件末尾        f.seek(0, 2)        try:            while True:                line = f.readline()                if line:                    line = line.strip()                    if line:                        entry = parse_log_line(line)                        if entry:                            callback(entry)                else:                    time.sleep(interval)        except KeyboardInterrupt:            print("\n⏹️ 监控已停止")def alert_handler(entry):    """告警处理函数"""    if entry["level"] == "ERROR":        print(f"🚨 [{entry['timestamp']}] ERROR: {entry['path']} - {entry['error']}")    elif entry["response_time"] > 300:        print(f"🐢 [{entry['timestamp']}] 慢请求: {entry['path']} ({entry['response_time']}ms)")    elif entry["status"] >= 500:        print(f"💥 [{entry['timestamp']}] 服务器错误: {entry['status']} {entry['path']}")# 实时监控(取消注释运行)# tail_log("app.log", alert_handler)

💡 tail -f 原理:持续读取文件的新内容。f.seek(0, 2) 把指针移到末尾,然后不断 readline() 检查新行。这是日志监控的经典模式。


10. 今日小结

项目一:批量文件重命名工具

功能
核心代码
知识点
序号重命名
f"{prefix}_{i:03d}{ext}"
字符串格式化
正则替换
re.sub(pattern, repl, name)
正则表达式
按日期重命名
datetime.fromtimestamp(mtime)
datetime + os.stat
预览模式
dry_run=True
安全设计
撤销功能
JSON 记录历史
文件读写 + JSON

项目二:日志文件分析器

功能
核心代码
知识点
解析日志行
re.match(pattern, line)
正则分组
级别统计
Counter(log["level"])
collections.Counter
路径热度
path_counter.most_common(5)
Counter 排序
响应时间分析
sum(times)/len(times)
列表聚合
每小时统计
Counter(timestamp.hour)
datetime 属性
导出 CSV
csv.writer
csv 模块
导出 HTML
Path.write_text()
pathlib
实时监控
f.seek(0,2) + readline()
文件 tail

综合运用的知识(Day26-31)

  • ✅ Day26-27 正则表达式 → 解析日志格式、文件名替换
  • ✅ Day28 JSON → 保存重命名历史(撤销功能)
  • ✅ Day29 CSV → 导出分析报告
  • ✅ Day30 datetime → 按日期重命名、时间统计
  • ✅ Day31 os/pathlib → 文件遍历、路径操作、读写文件

🎯 扩展练习:1. 给重命名工具添加"递归模式"——连子目录的文件一起处理2. 给日志分析器添加"异常检测"——找出响应时间突增的时间段3. 写一个"日志清洗器"——把敏感信息(IP、手机号)替换成 ***4. 把两个工具打包成命令行程序(用 argparse)


📚 Day32 完成!第二阶段数据处理基础已全部结束 ✅明天进入 Day33:迭代器与生成器 — 惰性求值的魔法

轻松时刻:

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 05:07:58 HTTP/2.0 GET : https://f.mffb.com.cn/a/499008.html
  2. 运行时间 : 0.217630s [ 吞吐率:4.59req/s ] 内存消耗:4,636.24kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=5552f4eafe0673931774f7f4203d4ae7
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000854s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000773s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.008510s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000310s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000584s ]
  6. SELECT * FROM `set` [ RunTime:0.000198s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000608s ]
  8. SELECT * FROM `article` WHERE `id` = 499008 LIMIT 1 [ RunTime:0.001000s ]
  9. UPDATE `article` SET `lasttime` = 1783026478 WHERE `id` = 499008 [ RunTime:0.023172s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.000457s ]
  11. SELECT * FROM `article` WHERE `id` < 499008 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.009409s ]
  12. SELECT * FROM `article` WHERE `id` > 499008 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.004312s ]
  13. SELECT * FROM `article` WHERE `id` < 499008 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.002059s ]
  14. SELECT * FROM `article` WHERE `id` < 499008 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.009445s ]
  15. SELECT * FROM `article` WHERE `id` < 499008 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.002090s ]
0.221325s