From e6845620cc0d724226252c06f1f90fe9ffe2d977 Mon Sep 17 00:00:00 2001 From: mzl Date: Fri, 9 Jan 2026 17:28:03 +0800 Subject: [PATCH] =?UTF-8?q?Excel=20=E6=96=87=E4=BB=B6=E7=A7=BB=E9=99=A4=20?= =?UTF-8?q?href=20=E5=92=8C=20detail=5Fcontent=20=E5=AD=97=E6=AE=B5=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B4=A6=E5=8F=B7=E8=A7=A3=E6=9E=90=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E6=AD=A3=E7=A1=AE=E6=8F=90=E5=8F=96=E6=98=B5?= =?UTF-8?q?=E7=A7=B0=E5=92=8C=E8=B4=A6=E5=8F=B7=20=E4=BC=98=E5=8C=96=20Web?= =?UTF-8?q?=20=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/static/index.html | 18 ++++++++++++++---- xhs_crawler_core.py | 28 ++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/app/static/index.html b/app/static/index.html index 1a64053..00ec8e9 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -881,12 +881,17 @@ } } let _lastProg = ''; + let _lastUpdateTime = 0; function updateProgressLine(s){ if(!s || !s.progress) return; const p = s.progress; const key = `${p.status}-${p.done}-${p.total}-${p.current}`; if(key === _lastProg) return; + // 限制更新频率:最多每 2 秒更新一次进度 + const now = Date.now(); + if(now - _lastUpdateTime < 2000 && key === _lastProg) return; _lastProg = key; + _lastUpdateTime = now; if(p.status === 'running'){ log(`进度:${p.done}/${p.total} 当前:${p.current || '-'}`); }else if(p.status && p.status !== 'idle'){ @@ -1367,13 +1372,18 @@ }); // ========= 文件输出 ========= + let _refreshFilesPending = false; async function refreshOutFiles(){ if(!authed) return; + if(_refreshFilesPending) return; // 防止重复请求 + _refreshFilesPending = true; try{ const files = await apiGet('/api/files'); renderFiles(files || []); }catch(e){ // ignore + }finally{ + _refreshFilesPending = false; } } @@ -1477,10 +1487,10 @@ log('页面加载完成。'); connectLogs(); await pollStatus(); - // 每2秒无感检测一次(不刷新页面) - setInterval(pollStatus, 5000); - // 输出文件偶尔刷新一下 - setInterval(refreshOutFiles, 15000); + // 状态轮询:降低频率到 10 秒(原 5 秒) + setInterval(pollStatus, 10000); + // 输出文件偶尔刷新一下:降低频率到 30 秒(原 15 秒) + setInterval(refreshOutFiles, 30000); })(); diff --git a/xhs_crawler_core.py b/xhs_crawler_core.py index 04d1312..21eb0d8 100644 --- a/xhs_crawler_core.py +++ b/xhs_crawler_core.py @@ -558,11 +558,31 @@ def resolve_profile_by_search( if use_anchor_only: href = (it.get_attribute("href") or "").strip() nickname = "" + xhs_no = "" try: - nickname = (it.inner_text() or "").strip() + full_text = (it.inner_text() or "").strip() + # 解析昵称和账号:从完整文本中提取 + # 示例:青岛西门子家电规划师-海燕呀 1天前更新 小红书号:V13863940939 粉丝・52 笔记・217 关注 + # 提取昵称:从开头到 "小红书号" 之前,去除时间信息 + lines = full_text.split('\n') + main_text = lines[0] if lines else full_text + + # 提取小红书号 + m = re.search(r'小红书号[::]\s*([A-Za-z0-9]+)', main_text) + if m: + xhs_no = m.group(1).strip() + + # 提取昵称:去除时间信息和账号信息 + # 先移除小红书号部分 + nickname_part = re.sub(r'小红书号[::]\s*[A-Za-z0-9]+.*', '', main_text) + # 移除时间信息(如 "1天前更新") + nickname_part = re.sub(r'\d+[天小时分秒]*前更新', '', nickname_part) + # 移除粉丝、笔记、关注信息 + nickname_part = re.sub(r'粉丝[・・]\d+\s*笔记[・・]\d+\s*关注.*', '', nickname_part) + nickname = nickname_part.strip() except Exception: nickname = "" - xhs_no = "" + xhs_no = "" else: href = (it.locator("a[href^='/user/profile/']").first.get_attribute("href") or "").strip() nickname = "" @@ -947,8 +967,8 @@ def crawl_detail( wb = Workbook() ws = wb.active ws.title = "data" - # 按需求文档的字段顺序 - headers = ["href", "detail_title", "detail_content", "like", "collect", "comment", "detail_date_loc", "crawled_at"] + # Excel 导出字段(不包含 href 和 detail_content) + headers = ["detail_title", "like", "collect", "comment", "detail_date_loc", "crawled_at"] ws.append(headers) for r in results: ws.append([r.get(h, "") for h in headers])