|
@@ -7,11 +7,17 @@ import re
|
|
|
import sys
|
|
import sys
|
|
|
import time
|
|
import time
|
|
|
|
|
|
|
|
-sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
|
|
|
|
|
|
+import requests
|
|
|
|
|
+
|
|
|
|
|
+# 仅在交互式运行时包装 stdout;由计划任务调用时保持原生流
|
|
|
|
|
+if not sys.stdout.isatty():
|
|
|
|
|
+ try:
|
|
|
|
|
+ sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
|
|
|
+ except Exception:
|
|
|
|
|
+ pass
|
|
|
|
|
|
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
-XHS_DIR = os.path.dirname(SCRIPT_DIR)
|
|
|
|
|
-OPERATION_DIR = os.path.dirname(XHS_DIR)
|
|
|
|
|
|
|
+OPERATION_DIR = SCRIPT_DIR # 本脚本位于 运营文案/ 目录,配置文件也在这
|
|
|
CONFIG_PATH = os.path.join(OPERATION_DIR, "xhs_daily_config.json")
|
|
CONFIG_PATH = os.path.join(OPERATION_DIR, "xhs_daily_config.json")
|
|
|
|
|
|
|
|
XHS_SKILLS_PATH = r"C:\code\XiaohongshuSkills\scripts"
|
|
XHS_SKILLS_PATH = r"C:\code\XiaohongshuSkills\scripts"
|
|
@@ -19,7 +25,7 @@ sys.path.insert(0, XHS_SKILLS_PATH)
|
|
|
sys.path.insert(0, OPERATION_DIR)
|
|
sys.path.insert(0, OPERATION_DIR)
|
|
|
|
|
|
|
|
from cdp_publish import XiaohongshuPublisher
|
|
from cdp_publish import XiaohongshuPublisher
|
|
|
-from xhs_feishu import send_daily_report
|
|
|
|
|
|
|
+from xhs_feishu import _get_token, FEISHU_MSG_URL
|
|
|
|
|
|
|
|
|
|
|
|
|
def _load_config():
|
|
def _load_config():
|
|
@@ -28,7 +34,10 @@ def _load_config():
|
|
|
|
|
|
|
|
|
|
|
|
|
def extract_comment_counts(publisher, limit=10):
|
|
def extract_comment_counts(publisher, limit=10):
|
|
|
- """从笔记管理页提取每篇笔记的评论数"""
|
|
|
|
|
|
|
+ """从笔记管理页提取每篇笔记的评论数。
|
|
|
|
|
+
|
|
|
|
|
+ 页面数字顺序:阅读 / 评论 / 点赞 / 收藏 / 分享
|
|
|
|
|
+ """
|
|
|
publisher._navigate("https://creator.xiaohongshu.com/new/note-manager")
|
|
publisher._navigate("https://creator.xiaohongshu.com/new/note-manager")
|
|
|
time.sleep(6)
|
|
time.sleep(6)
|
|
|
|
|
|
|
@@ -39,23 +48,24 @@ def extract_comment_counts(publisher, limit=10):
|
|
|
i = 0
|
|
i = 0
|
|
|
while i < len(lines) and len(notes) < limit:
|
|
while i < len(lines) and len(notes) < limit:
|
|
|
ln = lines[i]
|
|
ln = lines[i]
|
|
|
- # 匹配日期格式
|
|
|
|
|
|
|
+
|
|
|
if re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$", ln) and i + 5 < len(lines):
|
|
if re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$", ln) and i + 5 < len(lines):
|
|
|
title = lines[i - 1].strip() if i >= 1 else ""
|
|
title = lines[i - 1].strip() if i >= 1 else ""
|
|
|
- # 后面5个数字:阅读/点赞/收藏/评论/分享
|
|
|
|
|
|
|
+
|
|
|
nums = []
|
|
nums = []
|
|
|
j = i + 1
|
|
j = i + 1
|
|
|
while j < len(lines) and len(nums) < 5 and lines[j].isdigit():
|
|
while j < len(lines) and len(nums) < 5 and lines[j].isdigit():
|
|
|
nums.append(int(lines[j]))
|
|
nums.append(int(lines[j]))
|
|
|
j += 1
|
|
j += 1
|
|
|
if len(nums) >= 5 and title:
|
|
if len(nums) >= 5 and title:
|
|
|
|
|
+ # 页面顺序:阅读 / 评论 / 点赞 / 收藏 / 分享
|
|
|
notes.append({
|
|
notes.append({
|
|
|
"title": title,
|
|
"title": title,
|
|
|
"publish_date": ln[:10],
|
|
"publish_date": ln[:10],
|
|
|
"read_count": nums[0],
|
|
"read_count": nums[0],
|
|
|
- "like_count": nums[1],
|
|
|
|
|
- "collect_count": nums[2],
|
|
|
|
|
- "comment_count": nums[3],
|
|
|
|
|
|
|
+ "comment_count": nums[1],
|
|
|
|
|
+ "like_count": nums[2],
|
|
|
|
|
+ "collect_count": nums[3],
|
|
|
"share_count": nums[4],
|
|
"share_count": nums[4],
|
|
|
})
|
|
})
|
|
|
i = j if j > i + 1 else i + 1
|
|
i = j if j > i + 1 else i + 1
|
|
@@ -81,29 +91,43 @@ def check_comments():
|
|
|
noted_with_comments = [n for n in notes if n["comment_count"] > 0]
|
|
noted_with_comments = [n for n in notes if n["comment_count"] > 0]
|
|
|
|
|
|
|
|
if not noted_with_comments:
|
|
if not noted_with_comments:
|
|
|
- print("没有发现新评论")
|
|
|
|
|
|
|
+ print("没有发现有评论的笔记")
|
|
|
return
|
|
return
|
|
|
|
|
|
|
|
- # 构建推送消息
|
|
|
|
|
date = time.strftime("%Y-%m-%d")
|
|
date = time.strftime("%Y-%m-%d")
|
|
|
- overview = {
|
|
|
|
|
- "fans_count": 0,
|
|
|
|
|
- "follow_count": 0,
|
|
|
|
|
- "interact_count": 0,
|
|
|
|
|
- "period_7d": {},
|
|
|
|
|
- "period_30d": {},
|
|
|
|
|
- }
|
|
|
|
|
- # 只推送评论笔记列表
|
|
|
|
|
- notes_for_card = noted_with_comments
|
|
|
|
|
|
|
|
|
|
print(f"发现 {len(noted_with_comments)} 篇有评论的笔记")
|
|
print(f"发现 {len(noted_with_comments)} 篇有评论的笔记")
|
|
|
|
|
+ lines = []
|
|
|
for n in noted_with_comments:
|
|
for n in noted_with_comments:
|
|
|
- print(f" - {n['title']}: {n['comment_count']} 条评论")
|
|
|
|
|
-
|
|
|
|
|
- # 发送飞书消息
|
|
|
|
|
|
|
+ lines.append(f" · 《{n['title']}》({n['publish_date']}):{n['comment_count']} 条评论")
|
|
|
|
|
+ msg = (
|
|
|
|
|
+ "📬 小红书评论提醒(" + date + ")\n\n"
|
|
|
|
|
+ + "\n".join(lines)
|
|
|
|
|
+ + "\n\n注:当前无法检测“未回复”状态,"
|
|
|
|
|
+ "请前往创作者中心查看具体评论回复情况。"
|
|
|
|
|
+ )
|
|
|
|
|
+ print(msg)
|
|
|
|
|
+
|
|
|
|
|
+ # 发送简洁文本通知(不发完整日报卡片,避免与日报重复)
|
|
|
try:
|
|
try:
|
|
|
- send_daily_report(CONFIG_PATH, date, overview, notes_for_card)
|
|
|
|
|
- print("评论通知已推送")
|
|
|
|
|
|
|
+ cfg = _load_config()
|
|
|
|
|
+ token = _get_token(cfg["feishu_app_id"], cfg["feishu_app_secret"])
|
|
|
|
|
+ url = f"{FEISHU_MSG_URL}?receive_id_type=chat_id"
|
|
|
|
|
+ r = requests.post(
|
|
|
|
|
+ url,
|
|
|
|
|
+ headers={"Authorization": f"Bearer {token}"},
|
|
|
|
|
+ json={
|
|
|
|
|
+ "receive_id": cfg["feishu_chat_id"],
|
|
|
|
|
+ "msg_type": "text",
|
|
|
|
|
+ "content": json.dumps({"text": msg}, ensure_ascii=False),
|
|
|
|
|
+ },
|
|
|
|
|
+ timeout=20,
|
|
|
|
|
+ )
|
|
|
|
|
+ d = r.json()
|
|
|
|
|
+ if d.get("code") == 0:
|
|
|
|
|
+ print(f"[OK] 评论通知已推送")
|
|
|
|
|
+ else:
|
|
|
|
|
+ print(f"[WARN] 推送失败: {d.get('msg')}")
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
print(f"推送失败: {e}")
|
|
print(f"推送失败: {e}")
|
|
|
|
|
|