// 全局变量 let isTaskRunning = false; let currentSection = 'home'; let taskCheckInterval; const API_BASE_URL = 'http://localhost:8080/api'; // API基础地址 // DOM加载完成后初始化 $(document).ready(function() { showSection('home'); console.log('✅ 微信公众号文章爬虫系统已加载'); }); // 显示指定区域 function showSection(sectionName) { // 隐藏所有区域 $('.section').hide(); $('.feature-cards').hide(); if (sectionName === 'home') { $('.feature-cards').show(); currentSection = 'home'; } else { $('#section-' + sectionName).show(); currentSection = sectionName; } } // 提取公众号主页相关函数 function extractHomepage() { const articleUrl = $('#homepage-url').val().trim(); if (!articleUrl) { showResult('homepage', 'error', '请输入文章链接'); return; } if (!articleUrl.includes('mp.weixin.qq.com')) { showResult('homepage', 'error', '请输入有效的微信公众号文章链接'); return; } if (isTaskRunning) { showResult('homepage', 'error', '有任务正在执行,请稍候...'); return; } isTaskRunning = true; showResult('homepage', 'loading', '正在提取公众号主页链接...'); // 调用后端API $.ajax({ url: `${API_BASE_URL}/homepage/extract`, method: 'POST', contentType: 'application/json', data: JSON.stringify({ url: articleUrl }), success: function(response) { isTaskRunning = false; if (response.success && response.data && response.data.homepage) { const homepageUrl = response.data.homepage; const safeUrl = homepageUrl.replace(/'/g, "\\'"); const resultHtml = `

✅ 提取成功

公众号主页链接:

${homepageUrl}
`; showResult('homepage', 'success', resultHtml); } else { showResult('homepage', 'error', response.message || '提取失败'); } }, error: function(xhr, status, error) { isTaskRunning = false; let errorMsg = '请求失败:' + error; if (xhr.status === 0) { errorMsg = '无法连接到后端服务器,请确保 API 服务器已启动(运行 api_server.exe)'; } showResult('homepage', 'error', errorMsg); } }); } // 生成模拟的公众号主页链接 function generateMockHomepageUrl(articleUrl) { // 从文章链接中提取__biz参数来模拟真实的主页链接 const bizMatch = articleUrl.match(/__biz=([^&]+)/); if (bizMatch) { const biz = bizMatch[1]; return `https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=${biz}&scene=124`; } // 如果无法提取,返回示例链接 return 'https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzI1NjEwMTM4OA==&scene=124'; } function loadExampleUrl() { const exampleUrl = 'https://mp.weixin.qq.com/s?__biz=MzI1NjEwMTM4OA==&mid=2651232405&idx=1&sn=7c8f5b2e3d4a1b9c8e7f6a5b4c3d2e1f&chksm=f1d7e8c4c6a061d2b9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0&scene=27'; $('#homepage-url').val(exampleUrl); showResult('homepage', 'info', '已加载文章链接示例,点击"提取主页链接"开始处理'); } // 打开链接的辅助函数 function openInNewTab(url) { window.open(url, '_blank'); } // 下载单篇文章 // 获取文章列表 function getArticleList() { const accessToken = $('#access-token').val().trim(); const pages = parseInt($('#pages').val()) || 0; if (!accessToken) { showResult('list', 'error', '请输入Access Token URL'); return; } if (isTaskRunning) { showResult('list', 'error', '有任务正在执行,请稍候...'); return; } isTaskRunning = true; showResult('list', 'loading', '正在获取文章列表,请稍候...'); // 调用后端API(同步等待) $.ajax({ url: `${API_BASE_URL}/article/list`, method: 'POST', contentType: 'application/json', data: JSON.stringify({ access_token: accessToken, pages: pages }), success: function(response) { isTaskRunning = false; if (response.success && response.data) { const data = response.data; const fileExt = data.filename.endsWith('.txt') ? 'TXT文件' : 'Excel文件'; const resultHtml = `

✅ 获取成功

公众号:${data.account}

文件:${data.filename}

📥 下载${fileExt}
`; showResult('list', 'success', resultHtml); // 自动触发下载 window.location.href = `${API_BASE_URL}${data.download}`; } else { showResult('list', 'error', response.message || '获取失败'); } }, error: function(xhr, status, error) { isTaskRunning = false; let errorMsg = '请求失败:' + error; if (xhr.status === 0) { errorMsg = '无法连接到后端服务器,请确保 API 服务器已启动'; } else if (xhr.responseJSON && xhr.responseJSON.message) { errorMsg = xhr.responseJSON.message; } showResult('list', 'error', errorMsg); }, timeout: 120000 // 2分钟超时 }); } // 批量下载文章 function batchDownload() { const officialAccount = $('#official-account').val().trim(); const saveImage = $('#batch-save-image').is(':checked'); const saveContent = $('#batch-save-content').is(':checked'); if (!officialAccount) { showResult('batch', 'error', '请输入公众号名称或文章链接'); return; } if (isTaskRunning) { showResult('batch', 'error', '有任务正在执行,请稍候...'); return; } isTaskRunning = true; showResult('batch', 'loading', '正在批量下载文章,请稍候...'); // 调用后端 API(同步等待) $.ajax({ url: `${API_BASE_URL}/article/batch`, method: 'POST', contentType: 'application/json', data: JSON.stringify({ official_account: officialAccount, save_image: saveImage, save_content: saveContent }), success: function(response) { isTaskRunning = false; if (response.success && response.data) { const data = response.data; const resultHtml = `

✅ ${response.message}

公众号:${data.account}

文章数量:${data.articleCount} 篇

保存路径:${data.path}

`; showResult('batch', 'success', resultHtml); } else { showResult('batch', 'error', response.message || '批量下载失败'); } }, error: function(xhr, status, error) { isTaskRunning = false; let errorMsg = '请求失败:' + error; if (xhr.status === 0) { errorMsg = '无法连接到后端服务器,请确保 API 服务器已启动'; } else if (xhr.responseJSON && xhr.responseJSON.message) { errorMsg = xhr.responseJSON.message; } showResult('batch', 'error', errorMsg); }, timeout: 300000 // 5分钟超时 }); } // 获取文章详情(功能4) function getArticleDetail() { const accessToken = $('#detail-access-token').val().trim(); const pages = parseInt($('#detail-pages').val()) || 0; const submitBtn = $('#section-detail .btn-success'); // 1. 验证输入 if (!accessToken) { showResult('detail', 'error', '⚠️ 请输入Access Token URL'); // 高亮输入框 $('#detail-access-token').css('border-color', '#e74c3c').focus(); setTimeout(() => { $('#detail-access-token').css('border-color', ''); }, 2000); return; } // 2. 检查是否有任务正在执行 if (isTaskRunning) { showResult('detail', 'error', '⚠️ 有任务正在执行,请稍候...'); return; } // 3. 设置任务状态并禁用按钮 isTaskRunning = true; submitBtn.prop('disabled', true) .addClass('disabled') .html('⏳ 处理中...'); // 4. 构建提示信息 const pagesInfo = pages > 0 ? `前${pages}页(约${pages * 10}篇文章)` : '全部文章'; // 5. 显示加载状态 showResult('detail', 'loading', `
⏳ 正在获取文章详情,请耐心等待...

📌 本次获取范围:${pagesInfo}

📝 执行步骤:

  1. 正在获取公众号文章列表...
  2. 正在下载每篇文章的详细数据...
  3. 正在保存为TXT文件...

⚠️ 此过程可能需要几分钟,系统会自动延时避免被封禁

💡 提示:请不要关闭页面或刷新浏览器

`); console.log('🚀 开始获取文章详情...'); console.log('📄 获取页数:', pages === 0 ? '全部' : pages); // 6. 调用后端 API $.ajax({ url: `${API_BASE_URL}/article/detail`, method: 'POST', contentType: 'application/json', data: JSON.stringify({ access_token: accessToken, pages: pages }), beforeSend: function() { console.log('📡 发送请求到后端 API...'); }, success: function(response) { console.log('✅ 收到服务器响应:', response); // 恢复任务状态和按钮 isTaskRunning = false; submitBtn.prop('disabled', false) .removeClass('disabled') .html('开始获取'); if (response.success && response.data) { const data = response.data; const resultHtml = `

✅ 获取成功!

📱 公众号:${data.account}

📊 文章数量:${data.articleCount} 篇

📁 保存路径:${data.path}

📊 数据包含:

💡 数据已保存在 data/${data.account}/文章详细 目录下

`; showResult('detail', 'success', resultHtml); } else { showResult('detail', 'error', `

❌ 获取失败

${response.message || '未知错误,请稍后重试'}

💡 可能的原因:

请重新从 Fiddler 获取 Access Token URL 并重试

`); } }, error: function(xhr, status, error) { console.error('❌ 请求失败:', { xhr, status, error }); // 恢复任务状态和按钮 isTaskRunning = false; submitBtn.prop('disabled', false) .removeClass('disabled') .html('开始获取'); let errorMsg = '请求失败'; let errorDetail = ''; if (xhr.status === 0) { errorMsg = '无法连接到后端服务器'; errorDetail = `

🔧 解决方法:

  1. 确认后端 API 服务器已启动
  2. 检查服务器地址:http://localhost:8080
  3. 查看服务器控制台是否有错误信息
`; } else if (xhr.status === 404) { errorMsg = '接口不存在'; errorDetail = `

请检查API路径配置是否正确

`; } else if (xhr.status === 500) { errorMsg = '服务器内部错误'; errorDetail = `

请查看服务器日志获取详细错误信息

`; } else if (xhr.responseJSON && xhr.responseJSON.message) { errorMsg = xhr.responseJSON.message; } else if (status === 'timeout') { errorMsg = '请求超时'; errorDetail = `

文章数量较多,处理时间超过10分钟。
建议:减少文章数量或稍后查看服务器是否已生成文件。

`; } else { errorMsg += ': ' + (error || '未知错误'); } showResult('detail', 'error', `

❌ ${errorMsg}

${errorDetail}

错误状态码: ${xhr.status || 'N/A'}
错误类型: ${status || 'N/A'}

`); }, complete: function() { console.log('🏁 请求完成'); }, timeout: 600000 // 10分钟超时(因为功能4需要较长时间) }); } // 加载示例 Access Token function loadDetailExample() { const exampleToken = 'https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&__biz=MzI1NjEwMTM4OA==&uin=MTIzNDU2Nzg5&key=abcdef123456&pass_ticket=xyz789&...'; $('#detail-access-token').val(exampleToken); showResult('detail', 'info', '已加载 Access Token 示例。

注意:请从 Fiddler 中获取实际的 Access Token URL,示例仅供参考。

获取步骤:
1. 在微信客户端打开公众号主页
2. 在 Fiddler 中查找 URL 为 /mp/profile_ext?action=getmsg 的请求
3. 按 Ctrl+U 复制完整 URL
4. 粘贴到此处'); } // 任务管理函数 function startTask(section, message) { isTaskRunning = true; showResult(section, 'loading', message); // 显示进度条 const resultDiv = $(`#${section}-result`); resultDiv.append(`
0%
`); // 禁用相关按钮 disableButtons(); } function updateTaskProgress(percent, message) { const progressFill = $('.progress-fill'); const progressText = $('.progress-text'); progressFill.css('width', percent + '%'); progressText.text(Math.floor(percent) + '% - ' + message); } function endTask(section, type, message) { isTaskRunning = false; // 移除进度条 $('.progress-container').remove(); showResult(section, type, message); enableButtons(); } function disableButtons() { $('.btn').prop('disabled', true).addClass('disabled'); } function enableButtons() { $('.btn').prop('disabled', false).removeClass('disabled'); } // 结果显示函数 function showResult(section, type, message) { const resultDiv = $(`#${section}-result`); resultDiv.removeClass('success error info loading') .addClass(type) .html(getResultIcon(type) + message) .show(); // 自动滚动到结果区域 resultDiv[0].scrollIntoView({ behavior: 'smooth' }); } function hideResult(section) { $(`#${section}-result`).hide(); } function getResultIcon(type) { switch (type) { case 'success': return '✅ '; case 'error': return '❌ '; case 'info': return 'ℹ️ '; case 'loading': return ''; default: return ''; } } // 表单验证函数 function validateUrl(url) { try { new URL(url); return true; } catch { return false; } } function validateInput(value, type) { switch (type) { case 'url': return validateUrl(value); case 'notEmpty': return value.trim().length > 0; case 'number': return !isNaN(value) && parseInt(value) > 0; default: return true; } } // 工具函数 function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } function formatDate(dateString) { const date = new Date(dateString); return date.getFullYear() + '-' + String(date.getMonth() + 1).padStart(2, '0') + '-' + String(date.getDate()).padStart(2, '0'); } function copyToClipboard(text) { navigator.clipboard.writeText(text).then(() => { alert('已复制到剪贴板'); }).catch(() => { alert('复制失败,请手动复制'); }); } // 快捷键支持 $(document).keydown(function(e) { // ESC键返回首页 if (e.keyCode === 27 && currentSection !== 'home') { showSection('home'); } // Ctrl+Enter 执行当前页面的主要操作 if (e.ctrlKey && e.keyCode === 13) { switch (currentSection) { case 'homepage': extractHomepage(); break; case 'single': downloadSingleArticle(); break; case 'list': getArticleList(); break; case 'batch': batchDownload(); break; case 'detail': getArticleDetail(); break; case 'data': loadDataList(); break; } } }); // 页面可见性变化时的处理 document.addEventListener('visibilitychange', function() { if (document.hidden) { console.log('页面已隐藏'); } else { console.log('页面已显示'); // 可以在这里刷新任务状态 } }); // 错误处理 window.onerror = function(message, source, lineno, colno, error) { console.error('页面错误:', message, '位置:', source + ':' + lineno); return false; }; // 控制台欢迎信息 console.log(` 🚀 微信公众号文章爬虫系统 Web界面 ==================================== 版本: 1.0.0 开发者: AI Assistant 更新时间: 2025-11-27 ==================================== 💡 提示: - 按 ESC 键返回首页 - 按 Ctrl+Enter 执行当前操作 - 所有操作都会显示详细进度 ==================================== `);