287 lines
16 KiB
HTML
287 lines
16 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>微信公众号文章爬虫系统</title>
|
||
<link rel="stylesheet" href="css/style.css">
|
||
</head>
|
||
<body>
|
||
<!-- 头部导航 -->
|
||
<header class="top-navbar" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px 0; box-shadow: 0 2px 10px rgba(0,0,0,0.1); position: sticky; top: 0; z-index: 100;">
|
||
<div class="navbar-content" style="max-width: 1200px; margin: 0 auto; padding: 0 20px; display: flex; align-items: center; justify-content: space-between;">
|
||
<a href="frontend.html" class="logo" style="font-size: 24px; font-weight: bold; text-decoration: none; color: white;">🔍 易搜高</a>
|
||
<nav class="nav-menu" style="display: flex; gap: 15px; align-items: center;">
|
||
<a href="frontend.html" class="nav-link" style="color: white; text-decoration: none; font-size: 14px; font-weight: 500; padding: 8px 16px; border-radius: 6px; transition: all 0.3s; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2);" onmouseover="this.style.background='rgba(255, 255, 255, 0.2)'" onmouseout="this.style.background='rgba(255, 255, 255, 0.1)'">首页</a>
|
||
<a href="#" class="nav-link" style="color: white; text-decoration: none; font-size: 14px; font-weight: 500; padding: 8px 16px; border-radius: 6px; transition: all 0.3s; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2);" onmouseover="this.style.background='rgba(255, 255, 255, 0.2)'" onmouseout="this.style.background='rgba(255, 255, 255, 0.1)'">监控中心</a>
|
||
<a href="#" class="nav-link" style="color: white; text-decoration: none; font-size: 14px; font-weight: 500; padding: 8px 16px; border-radius: 6px; transition: all 0.3s; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2);" onmouseover="this.style.background='rgba(255, 255, 255, 0.2)'" onmouseout="this.style.background='rgba(255, 255, 255, 0.1)'">数据分析</a>
|
||
<a href="#" class="nav-link" style="color: white; text-decoration: none; font-size: 14px; font-weight: 500; padding: 8px 16px; border-radius: 6px; transition: all 0.3s; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2);" onmouseover="this.style.background='rgba(255, 255, 255, 0.2)'" onmouseout="this.style.background='rgba(255, 255, 255, 0.1)'">帮助文档</a>
|
||
<a href="user-center.html" class="nav-link" id="userCenterLink" style="color: white; text-decoration: none; font-size: 14px; font-weight: 500; padding: 8px 16px; border-radius: 6px; transition: all 0.3s; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2);" onmouseover="this.style.background='rgba(255, 255, 255, 0.2)'" onmouseout="this.style.background='rgba(255, 255, 255, 0.1)'">👤 用户中心</a>
|
||
<a href="login.html" class="nav-link" id="loginLink" style="color: white; text-decoration: none; font-size: 14px; font-weight: 500; padding: 8px 16px; border-radius: 6px; transition: all 0.3s; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2);" onmouseover="this.style.background='rgba(255, 255, 255, 0.2)'" onmouseout="this.style.background='rgba(255, 255, 255, 0.1)'">🔐 登录</a>
|
||
<div id="userMenu" class="user-info" style="display: flex; align-items: center; gap: 10px;"></div>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="container">
|
||
<header class="header">
|
||
<h1>🚀 微信公众号文章爬虫系统</h1>
|
||
<p class="subtitle">Wechat Official Account Article Crawler</p>
|
||
</header>
|
||
|
||
<div class="main-content">
|
||
<!-- 功能选择卡片 -->
|
||
<div class="feature-cards">
|
||
<div class="card" id="card-homepage">
|
||
<div class="card-icon">🏠</div>
|
||
<h3>提取公众号主页</h3>
|
||
<p>输入文章链接获取公众号主页链接</p>
|
||
<button class="btn btn-primary" onclick="showSection('homepage')">进入</button>
|
||
</div>
|
||
|
||
<div class="card" id="card-list">
|
||
<div class="card-icon">📋</div>
|
||
<h3>获取文章列表</h3>
|
||
<p>获取公众号所有文章列表</p>
|
||
<button class="btn btn-primary" onclick="showSection('list')">进入</button>
|
||
</div>
|
||
|
||
<div class="card" id="card-batch">
|
||
<div class="card-icon">📦</div>
|
||
<h3>批量下载文章</h3>
|
||
<p>批量下载文章详细内容</p>
|
||
<button class="btn btn-primary" onclick="showSection('batch')">进入</button>
|
||
</div>
|
||
|
||
<div class="card" id="card-detail">
|
||
<div class="card-icon">📊</div>
|
||
<h3>获取文章详情</h3>
|
||
<p>获取文章阅读量、点赞数、评论等详细信息</p>
|
||
<button class="btn btn-primary" onclick="showSection('detail')">进入</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 提取公众号主页区域 -->
|
||
<div class="section" id="section-homepage" style="display:none;">
|
||
<div class="section-header">
|
||
<h2>🏠 提取公众号主页</h2>
|
||
<button class="btn btn-secondary" onclick="showSection('home')">返回</button>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>公众号文章链接:</label>
|
||
<input type="text" id="homepage-url" placeholder="请输入公众号下任意一篇已发布的文章链接...">
|
||
<small>支持公众号文章完整URL,无需Cookie即可获取公众号主页链接</small>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button class="btn btn-success" onclick="extractHomepage()">提取主页链接</button>
|
||
<button class="btn btn-info" onclick="loadExampleUrl()">查看示例</button>
|
||
</div>
|
||
<div class="result" id="homepage-result"></div>
|
||
</div>
|
||
|
||
<!-- 获取文章列表区域 -->
|
||
<div class="section" id="section-list" style="display:none;">
|
||
<div class="section-header">
|
||
<h2>📋 获取文章列表</h2>
|
||
<button class="btn btn-secondary" onclick="showSection('home')">返回</button>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Access Token URL:</label>
|
||
<textarea id="access-token" placeholder="请粘贴从Fiddler获取的完整URL..." rows="4"></textarea>
|
||
<small>包含 __biz, uin, key, pass_ticket 等参数的完整URL</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>获取页数:</label>
|
||
<input type="number" id="pages" value="1" min="1" max="999">
|
||
<small>留空表示获取全部</small>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button class="btn btn-success" onclick="getArticleList()">开始获取</button>
|
||
</div>
|
||
<div class="result" id="list-result"></div>
|
||
</div>
|
||
|
||
<!-- 批量下载区域 -->
|
||
<div class="section" id="section-batch" style="display:none;">
|
||
<div class="section-header">
|
||
<h2>📦 批量下载文章</h2>
|
||
<button class="btn btn-secondary" onclick="showSection('home')">返回</button>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>公众号名称或文章链接:</label>
|
||
<input type="text" id="official-account" placeholder="请输入公众号名称或任意一篇文章链接...">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="batch-save-image"> 保存图片
|
||
</label>
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="batch-save-content" checked> 保存内容
|
||
</label>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button class="btn btn-success" onclick="batchDownload()">开始批量下载</button>
|
||
</div>
|
||
<div class="result" id="batch-result"></div>
|
||
</div>
|
||
|
||
<!-- 获取文章详情区域 -->
|
||
<div class="section" id="section-detail" style="display:none;">
|
||
<div class="section-header">
|
||
<h2>📊 获取文章详情</h2>
|
||
<button class="btn btn-secondary" onclick="showSection('home')">返回</button>
|
||
</div>
|
||
<div class="help-text">
|
||
<p><strong>💡 功能说明:</strong></p>
|
||
<ul>
|
||
<li>📈 自动获取公众号所有文章列表</li>
|
||
<li>📊 下载每篇文章的阅读量、点赞数、分享数等统计数据</li>
|
||
<li>💬 获取文章评论信息(如果有)</li>
|
||
<li>📁 保存为TXT格式,便于查看和分析</li>
|
||
</ul>
|
||
<p><strong>⚠️ 注意事项:</strong></p>
|
||
<ul>
|
||
<li>需要提供有效的Access Token URL(包含登录凭证)</li>
|
||
<li>处理时间较长,请耐心等待</li>
|
||
<li>数据将保存在 data/公众号名称/文章详细 目录下</li>
|
||
</ul>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Access Token URL:</label>
|
||
<textarea id="detail-access-token" placeholder="请粘贴从Fiddler获取的完整URL...\n\n步骤:\n1. 在浏览器中登录微信公众号平台\n2. 访问目标公众号主页\n3. 向下滚动加载文章列表\n4. 在Fiddler中找到profile_ext?action=getmsg请求\n5. 复制完整的URL(包含__biz、uin、key、pass_ticket等参数)" rows="6"></textarea>
|
||
<small>示例:https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&__biz=...&uin=...&key=...&pass_ticket=...</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>获取页数:</label>
|
||
<input type="number" id="detail-pages" value="0" min="0" max="999" placeholder="留空或0表示获取全部">
|
||
<small>每页约10篇文章,留空或输入0表示获取全部文章</small>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button class="btn btn-success" onclick="getArticleDetail()">开始获取</button>
|
||
<button class="btn btn-info" onclick="loadDetailExample()">查看示例</button>
|
||
</div>
|
||
<div class="result" id="detail-result"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<footer class="footer">
|
||
<p>© 2025 微信公众号文章爬虫系统 | 仅供学习使用</p>
|
||
</footer>
|
||
</div>
|
||
|
||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||
<script src="js/app.js"></script>
|
||
<script>
|
||
// 登录状态管理
|
||
function checkLoginStatus() {
|
||
// 检查认证数据
|
||
const authData = localStorage.getItem('authData') || sessionStorage.getItem('authData');
|
||
|
||
if (authData) {
|
||
try {
|
||
const auth = JSON.parse(authData);
|
||
const username = auth.user_info && auth.user_info.username ? auth.user_info.username : '用户';
|
||
showLoggedInState(username);
|
||
} catch (e) {
|
||
console.error('解析登录数据失败:', e);
|
||
showLoggedOutState();
|
||
}
|
||
} else {
|
||
showLoggedOutState();
|
||
}
|
||
}
|
||
|
||
// 显示已登录状态
|
||
function showLoggedInState(username) {
|
||
const loginLink = document.getElementById('loginLink');
|
||
const userMenu = document.getElementById('userMenu');
|
||
|
||
if (loginLink) loginLink.style.display = 'none';
|
||
if (userMenu) {
|
||
userMenu.innerHTML = `
|
||
<span style="margin-right: 10px;">👋 ${username}</span>
|
||
<button onclick="logout()" style="
|
||
background: rgba(255, 255, 255, 0.2);
|
||
color: white;
|
||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||
padding: 6px 12px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 13px;
|
||
transition: all 0.3s;
|
||
" onmouseover="this.style.background='rgba(255, 255, 255, 0.3)'"
|
||
onmouseout="this.style.background='rgba(255, 255, 255, 0.2)'">
|
||
退出登录
|
||
</button>
|
||
`;
|
||
userMenu.style.display = 'flex';
|
||
}
|
||
}
|
||
|
||
// 显示未登录状态
|
||
function showLoggedOutState() {
|
||
const loginLink = document.getElementById('loginLink');
|
||
const userMenu = document.getElementById('userMenu');
|
||
|
||
if (loginLink) loginLink.style.display = 'inline';
|
||
if (userMenu) userMenu.innerHTML = '';
|
||
}
|
||
|
||
// 登出功能
|
||
function logout() {
|
||
if (confirm('确定要退出登录吗?')) {
|
||
// 获取认证数据
|
||
const authData = localStorage.getItem('authData') || sessionStorage.getItem('authData');
|
||
let token = '';
|
||
|
||
if (authData) {
|
||
try {
|
||
const auth = JSON.parse(authData);
|
||
token = auth.token || '';
|
||
} catch (e) {
|
||
console.error('解析token失败:', e);
|
||
}
|
||
}
|
||
|
||
// 调用后端登出API
|
||
fetch('http://localhost:8080/api/user/logout', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': token ? `Bearer ${token}` : ''
|
||
}
|
||
}).then(response => {
|
||
// 无论API调用成功与否,都清除本地数据
|
||
localStorage.removeItem('authData');
|
||
localStorage.removeItem('isLoggedIn');
|
||
localStorage.removeItem('username');
|
||
localStorage.removeItem('token');
|
||
sessionStorage.removeItem('authData');
|
||
sessionStorage.removeItem('userSession');
|
||
|
||
alert('已成功退出登录!');
|
||
window.location.href = 'login.html';
|
||
}).catch(error => {
|
||
console.error('登出请求失败:', error);
|
||
// 即使API调用失败,也清除本地数据
|
||
localStorage.removeItem('authData');
|
||
localStorage.removeItem('isLoggedIn');
|
||
localStorage.removeItem('username');
|
||
localStorage.removeItem('token');
|
||
sessionStorage.removeItem('authData');
|
||
sessionStorage.removeItem('userSession');
|
||
|
||
alert('已成功退出登录!');
|
||
window.location.href = 'login.html';
|
||
});
|
||
}
|
||
}
|
||
|
||
// 页面加载时检查登录状态
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
checkLoginStatus();
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|