| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- 生成单文件HTML可视化页面
- """
- import json
- import os
- def generate_single_html():
- """生成包含所有资源的单文件HTML"""
- # 读取各个文件
- with open('index.html', 'r', encoding='utf-8') as f:
- html_content = f.read()
- with open('css/style.css', 'r', encoding='utf-8') as f:
- css_content = f.read()
- with open('js/carousel.js', 'r', encoding='utf-8') as f:
- carousel_js = f.read()
- with open('js/card.js', 'r', encoding='utf-8') as f:
- card_js = f.read()
- with open('js/tree.js', 'r', encoding='utf-8') as f:
- tree_js = f.read()
- with open('js/main.js', 'r', encoding='utf-8') as f:
- main_js = f.read()
- with open('data/data.json', 'r', encoding='utf-8') as f:
- data = json.load(f)
- # 修改main.js中的数据加载逻辑
- main_js_modified = main_js.replace(
- 'const response = await fetch(\'data/data.json\');',
- '// 使用内联数据'
- ).replace(
- '''if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- this.data = await response.json();''',
- 'this.data = window.__INLINE_DATA__;'
- )
- # 构建完整的HTML(使用与index.html完全一致的结构)
- single_html = f'''<!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>小红书搜索结果可视化</title>
- <style>
- {css_content}
- </style>
- </head>
- <body>
- <!-- 顶部标题栏 -->
- <header class="header">
- <div class="header-content">
- <h1 class="header-title">🔍 小红书搜索结果可视化</h1>
- <div class="header-stats">
- <span class="stat-item">
- <span class="stat-label">结果项:</span>
- <span class="stat-value" id="stat-results">0</span>
- </span>
- <span class="stat-item">
- <span class="stat-label">特征数:</span>
- <span class="stat-value" id="stat-features">0</span>
- </span>
- <span class="stat-item">
- <span class="stat-label">帖子数:</span>
- <span class="stat-value" id="stat-notes">0</span>
- </span>
- </div>
- </div>
- <!-- 搜索和筛选栏 -->
- <div class="toolbar">
- <div class="search-box">
- <input type="text"
- id="search-input"
- class="search-input"
- placeholder="搜索特征名称或关键词...">
- <button class="search-btn" id="search-btn">🔍</button>
- </div>
- <div class="filter-box">
- <select id="filter-status" class="filter-select">
- <option value="all">全部状态</option>
- <option value="success">搜索成功</option>
- <option value="failed">搜索失败</option>
- <option value="pending">待搜索</option>
- </select>
- <select id="sort-by" class="filter-select">
- <option value="default">默认排序</option>
- <option value="note_count">按帖子数</option>
- <option value="weight">按权重</option>
- </select>
- <button class="theme-toggle" id="theme-toggle" title="切换主题">🌙</button>
- </div>
- </div>
- </header>
- <!-- 主内容区域 -->
- <main class="main-container">
- <!-- 左侧树形列表 -->
- <aside class="sidebar">
- <div class="sidebar-header">
- <h2 class="sidebar-title">特征树形结构</h2>
- <button class="collapse-all-btn" id="collapse-all">全部折叠</button>
- </div>
- <div class="tree-container" id="tree-container">
- <div class="loading">加载中...</div>
- </div>
- </aside>
- <!-- 右侧详情面板 -->
- <section class="content-panel">
- <div class="panel-header">
- <h2 class="panel-title" id="panel-title">搜索结果详情</h2>
- <div class="panel-info" id="panel-info"></div>
- </div>
- <div class="cards-container" id="cards-container">
- <div class="empty-state">
- <div class="empty-icon">📋</div>
- <p class="empty-text">请从左侧选择一个特征查看搜索结果</p>
- </div>
- </div>
- </section>
- </main>
- <!-- 图片查看器模态框 -->
- <div class="modal" id="image-modal">
- <div class="modal-overlay" id="modal-overlay"></div>
- <div class="modal-content">
- <button class="modal-close" id="modal-close">×</button>
- <button class="modal-prev" id="modal-prev">‹</button>
- <button class="modal-next" id="modal-next">›</button>
- <img class="modal-image" id="modal-image" src="" alt="">
- <div class="modal-caption" id="modal-caption"></div>
- </div>
- </div>
- <script>
- // 内联数据
- window.__INLINE_DATA__ = {json.dumps(data, ensure_ascii=False, indent=2)};
- // Carousel组件
- {carousel_js}
- // Card组件
- {card_js}
- // Tree组件
- {tree_js}
- // Main应用
- {main_js_modified}
- </script>
- </body>
- </html>'''
- # 写入文件 - 使用新文件名不覆盖原有文件
- import datetime
- timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
- output_file = f'xiaohongshu_visualization_{timestamp}.html'
- with open(output_file, 'w', encoding='utf-8') as f:
- f.write(single_html)
- # 获取文件大小
- file_size = os.path.getsize(output_file) / (1024 * 1024)
- print(f"✅ 已生成单文件HTML: {output_file}")
- print(f"📦 文件大小: {file_size:.1f} MB")
- print(f"🚀 可以直接拖拽到浏览器打开")
- return output_file
- if __name__ == '__main__':
- generate_single_html()
|