From aa51b52135cefdab7496f8d6136479d972f022b9 Mon Sep 17 00:00:00 2001 From: littlejie-qinjinshan <18685329778@163.com> Date: Wed, 3 Jun 2026 23:53:14 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E9=9B=B6=E9=A3=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- financebot.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/financebot.py b/financebot.py index f9af3638..5ed54e5e 100644 --- a/financebot.py +++ b/financebot.py @@ -46,6 +46,59 @@ }, } +# 关键词过滤(中文 + 英文),可按需扩展 +FILTER_KEYWORDS = [ + "零食", "零售", "连锁", + "snack", "snacks", "retail", "chain", "chains", + "convenience", "convenience store", "grocery", "supermarket", + "store", "retailer" +] + +# 是否启用 DeepSeek 语义分类(需要设置 OPENAI_API_KEY) +USE_DEEPSEEK = bool(openai_api_key) + + +def contains_keyword(text: str) -> bool: + """快速关键词匹配(中/英混合)。""" + if not text: + return False + text_lower = text.lower() + for kw in FILTER_KEYWORDS: + if kw.lower() in text_lower: + return True + return False + + +def classify_with_deepseek(text: str) -> bool: + """ + 使用 DeepSeek(OpenAI 兼容接口)对文章进行相关性判断。 + 要求模型只返回 YES 或 NO。出错时返回 False(不相关)。 + """ + if not USE_DEEPSEEK: + return False + try: + # 尽量控制输入长度以减少 token 消耗 + prompt_text = text[:3000] + completion = openai_client.chat.completions.create( + model="deepseek-chat", + messages=[ + {"role": "system", "content": ( + "你是一个简洁的二分类文本判断器。判断给定新闻是否与零食、零售、连锁相关," + "同时包含它们的英文对应词(例如 snack, retail, chain 等)。只返回一个单词:YES 表示相关,NO 表示不相关。" + )}, + {"role": "user", "content": prompt_text} + ], + max_tokens=6, + temperature=0 + ) + resp = completion.choices[0].message.content.strip().upper() + if resp.startswith("Y") or resp.startswith("是") or "YES" in resp: + return True + return False + except Exception as e: + print(f"⚠️ DeepSeek 分类出错:{e}") + return False + # 获取北京时间 def today_date(): return datetime.now(pytz.timezone("Asia/Shanghai")).date() @@ -101,19 +154,41 @@ def fetch_rss_articles(rss_feeds, max_articles=10): continue print(f"✅ {source} RSS 获取成功,共 {len(feed.entries)} 条新闻") - articles = [] # 每个source都需要重新初始化列表 - for entry in feed.entries[:5]: + articles = [] # 每个 source 都需要重新初始化列表 + for entry in feed.entries[:max_articles]: title = entry.get('title', '无标题') link = entry.get('link', '') or entry.get('guid', '') + summary = entry.get('summary', '') or entry.get('description', '') or '' if not link: print(f"⚠️ {source} 的新闻 '{title}' 没有链接,跳过") continue - # 爬取正文用于分析(不展示) - article_text = fetch_article_text(link) - analysis_text += f"【{title}】\n{article_text}\n\n" + # 先做快速关键词匹配 + quick_text = f"{title}\n{summary}" + quick_hit = contains_keyword(quick_text) + + # 爬取正文用于深度分析(仅在需要时使用) + article_text = None + if quick_hit: + # 若关键词命中,再爬正文用于后续汇总 + article_text = fetch_article_text(link) + relevant = True + else: + # 关键词未命中,尝试爬取正文并用 DeepSeek 判定 + article_text = fetch_article_text(link) + check_text = f"{title}\n{summary}\n{article_text}" + if USE_DEEPSEEK: + relevant = classify_with_deepseek(check_text) + else: + relevant = False + + if not relevant: + print(f"⛔ 已移除不相关新闻: {title}") + continue - print(f"🔹 {source} - {title} 获取成功") + # 若相关,加入分析文本和展示列表 + analysis_text += f"【{title}】\n{article_text}\n\n" + print(f"🔹 {source} - {title} 获取并保留") articles.append(f"- [{title}]({link})") if articles: From 6023f8002679a018fefa663368b017371e2cd340 Mon Sep 17 00:00:00 2001 From: littlejie-qinjinshan <18685329778@163.com> Date: Wed, 3 Jun 2026 23:53:14 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E9=9B=B6=E9=A3=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- financebot.py | 153 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 6 deletions(-) diff --git a/financebot.py b/financebot.py index f9af3638..d5460627 100644 --- a/financebot.py +++ b/financebot.py @@ -7,6 +7,7 @@ import time import pytz import os +import re # OpenAI API Key openai_api_key = os.getenv("OPENAI_API_KEY") @@ -46,6 +47,129 @@ }, } +# 关键词过滤(中文 + 英文),可按需扩展 +FILTER_KEYWORDS = [ + "零食", "零售", "连锁", + "snack", "snacks", "retail", "chain", "chains", + "convenience", "convenience store", "grocery", "supermarket", + "store", "retailer" +] + +# 是否启用 DeepSeek 语义分类(需要设置 OPENAI_API_KEY) +USE_DEEPSEEK = bool(openai_api_key) + + +def contains_keyword(text: str) -> bool: + """快速关键词匹配(中/英混合)。""" + if not text: + return False + text_lower = text.lower() + for kw in FILTER_KEYWORDS: + if kw.lower() in text_lower: + return True + return False + + +def classify_titles_with_deepseek(titles: list) -> dict: + """ + 对一组新闻标题进行批量判定,返回编号到标签的映射。 + 标签为 'YES'/'NO'/'MAYBE'。如果 DeepSeek 不可用,则基于关键词做保守回退(命中关键词为 YES,其他为 MAYBE)。 + """ + labels = {} + if not titles: + return labels + + # 初始化默认为 MAYBE(不剔除) + for i in range(1, len(titles) + 1): + labels[i] = 'MAYBE' + + if not USE_DEEPSEEK: + for i, t in enumerate(titles, start=1): + labels[i] = 'YES' if contains_keyword(t) else 'MAYBE' + return labels + + # 构造编号标题列表 + numbered = "\n".join([f"{i}. {titles[i-1]}" for i in range(1, len(titles)+1)]) + system_prompt = ( + "你是一个简洁的三分类文本判断器。给定编号的新闻标题列表,判断每条标题是否与零食、零售、连锁相关(包括英文关键词 snack/retail/chain 等)。\n" + "对于每个编号仅输出一行,格式为:编号: YES|NO|MAYBE。YES 表示明确相关,NO 表示明确不相关,MAYBE 表示仅凭标题无法判断。不要输出额外说明。" + ) + try: + resp = openai_client.chat.completions.create( + model="deepseek-chat", + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": numbered} + ], + max_tokens= max(64, len(titles) * 6), + temperature=0 + ) + text = resp.choices[0].message.content + # 解析每行结果 + for line in text.splitlines(): + line = line.strip() + if not line: + continue + m = re.match(r"^\s*(\d+)\s*[:\.\)\-]?\s*([A-Za-z]+)", line, re.IGNORECASE) + if m: + idx = int(m.group(1)) + tag = m.group(2).upper() + if tag.startswith('Y'): + labels[idx] = 'YES' + elif tag.startswith('N'): + labels[idx] = 'NO' + else: + labels[idx] = 'MAYBE' + else: + # 如果没有数字开头,尝试解析类似 "1 YES" 或包含 YES/NO 的行 + m2 = re.search(r"(YES|NO|MAYBE)", line, re.IGNORECASE) + midx = re.search(r"^(\d+)", line) + if midx and m2: + idx = int(midx.group(1)) + tag = m2.group(1).upper() + labels[idx] = tag + return labels + except Exception as e: + print(f"⚠️ 标题级 DeepSeek 判定出错:{e},使用关键词回退") + for i, t in enumerate(titles, start=1): + labels[i] = 'YES' if contains_keyword(t) else 'MAYBE' + return labels + + +def classify_text_with_deepseek(text: str) -> str: + """ + 对单篇文章(标题+正文)进行判定,返回 'YES'/'NO'/'MAYBE'。 + DeepSeek 不可用时基于关键词回退。出错时返回 'MAYBE'。 + """ + if not text: + return 'MAYBE' + if not USE_DEEPSEEK: + return 'YES' if contains_keyword(text) else 'MAYBE' + try: + prompt_text = text[:3000] + system_prompt = ( + "你是一个简洁的三分类文本判断器。判断给定新闻标题与正文是否与零食、零售、连锁相关(包括英文词如 snack, retail, chain 等)。\n" + "只返回一个单词:YES 表示相关,NO 表示不相关,MAYBE 表示不确定或无法判断。不要额外说明。" + ) + resp = openai_client.chat.completions.create( + model="deepseek-chat", + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": prompt_text} + ], + max_tokens=6, + temperature=0 + ) + out = resp.choices[0].message.content.strip().upper() + if out.startswith('Y') or 'YES' in out: + return 'YES' + if out.startswith('N') or 'NO' in out: + return 'NO' + return 'MAYBE' + except Exception as e: + print(f"⚠️ 正文级 DeepSeek 判定出错:{e}") + return 'MAYBE' + # 获取北京时间 def today_date(): return datetime.now(pytz.timezone("Asia/Shanghai")).date() @@ -101,19 +225,36 @@ def fetch_rss_articles(rss_feeds, max_articles=10): continue print(f"✅ {source} RSS 获取成功,共 {len(feed.entries)} 条新闻") - articles = [] # 每个source都需要重新初始化列表 - for entry in feed.entries[:5]: + # 两轮筛选:1) 标题编号批量判定;2) 对保留项抓取正文并二次判定 + entries = feed.entries[:max_articles] + titles = [e.get('title', '无标题') for e in entries] + title_labels = classify_titles_with_deepseek(titles) + print(f"🔎 {source} 标题级判定: " + ", ".join([f"{i}:{title_labels.get(i)}" for i in sorted(title_labels.keys())])) + + articles = [] + for idx, entry in enumerate(entries, start=1): title = entry.get('title', '无标题') link = entry.get('link', '') or entry.get('guid', '') if not link: print(f"⚠️ {source} 的新闻 '{title}' 没有链接,跳过") continue - # 爬取正文用于分析(不展示) + tlabel = title_labels.get(idx, 'MAYBE') + if tlabel == 'NO': + print(f"⛔ 标题判定为非相关,跳过: [{idx}] {title}") + continue + + # 对保留项抓取正文并做二次判定 article_text = fetch_article_text(link) - analysis_text += f"【{title}】\n{article_text}\n\n" + check_text = f"{title}\n{article_text}" + final_label = classify_text_with_deepseek(check_text) + if final_label == 'NO': + print(f"⛔ 正文判定为非相关,移除: [{idx}] {title}") + continue - print(f"🔹 {source} - {title} 获取成功") + # 保留(YES 或 MAYBE) + analysis_text += f"【{title}】\n{article_text}\n\n" + print(f"🔹 {source} - [{idx}] {title} 保留 (标题判定={tlabel} -> 正文判定={final_label})") articles.append(f"- [{title}]({link})") if articles: @@ -129,7 +270,7 @@ def summarize(text): model="deepseek-chat", messages=[ {"role": "system", "content": """ - 你是一名专业的财经新闻分析师,请根据以下新闻内容,按照以下步骤完成任务: + 你是一名专业零食连锁零售行业的财经新闻分析师,请根据以下新闻内容,按照以下步骤完成任务: 1. 提取新闻中涉及的主要行业和主题,找出近1天涨幅最高的3个行业或主题,以及近3天涨幅较高且此前2周表现平淡的3个行业/主题。(如新闻未提供具体涨幅,请结合描述和市场情绪推测热点) 2. 针对每个热点,输出: - 催化剂:分析近期上涨的可能原因(政策、数据、事件、情绪等)。 From 37c9e3d8bcc8874b615f68a17894b1d6eb2b2a7d Mon Sep 17 00:00:00 2001 From: littlejie-qinjinshan <18685329778@163.com> Date: Thu, 4 Jun 2026 01:22:29 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20financebot.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- financebot.py | 156 ++++++++++++++++++++------------------------------ 1 file changed, 62 insertions(+), 94 deletions(-) diff --git a/financebot.py b/financebot.py index 3a9564da..789d7592 100644 --- a/financebot.py +++ b/financebot.py @@ -1,5 +1,9 @@ # 福生无量天尊 -from openai import OpenAI +try: + from openai import OpenAI +except Exception: + OpenAI = None + print("⚠️ openai 模块不可用,DeepSeek 相关功能将被禁用。若需要,请安装 openai 包并设置 OPENAI_API_KEY。") import feedparser import requests from newspaper import Article @@ -8,16 +12,29 @@ import pytz import os import re +import traceback # OpenAI API Key openai_api_key = os.getenv("OPENAI_API_KEY") -# 从环境变量获取 Server酱 SendKeys -server_chan_keys_env = os.getenv("SERVER_CHAN_KEYS") -if not server_chan_keys_env: - raise ValueError("环境变量 SERVER_CHAN_KEYS 未设置,请在Github Actions中设置此变量!") -server_chan_keys = server_chan_keys_env.split(",") -openai_client = OpenAI(api_key=openai_api_key, base_url="https://api.deepseek.com/v1") +# 从环境变量获取 Server酱 SendKeys(非必须,未设置时仅打印摘要) +server_chan_keys_env = os.getenv("SERVER_CHAN_KEYS", "") +if server_chan_keys_env and server_chan_keys_env.strip(): + server_chan_keys = [k.strip() for k in server_chan_keys_env.split(",") if k.strip()] +else: + server_chan_keys = [] + print("⚠️ 环境变量 SERVER_CHAN_KEYS 未设置,推送功能将被禁用。设置 SERVER_CHAN_KEYS 后可启用微信推送。") + +# 初始化 OpenAI/DeepSeek 客户端(可选) +openai_client = None +if openai_api_key: + try: + openai_client = OpenAI(api_key=openai_api_key, base_url="https://api.deepseek.com/v1") + except Exception as e: + print(f"⚠️ 无法初始化 OpenAI/DeepSeek 客户端: {e}") + +# 是否启用 DeepSeek 语义分类(以客户端是否可用为准) +USE_DEEPSEEK = bool(openai_client) # RSS源地址列表 rss_feeds = { @@ -55,10 +72,6 @@ "store", "retailer" ] -# 是否启用 DeepSeek 语义分类(需要设置 OPENAI_API_KEY) -USE_DEEPSEEK = bool(openai_api_key) - - def contains_keyword(text: str) -> bool: """快速关键词匹配(中/英混合)。""" if not text: @@ -70,7 +83,6 @@ def contains_keyword(text: str) -> bool: return False -<<<<<<< HEAD def classify_titles_with_deepseek(titles: list) -> dict: """ 对一组新闻标题进行批量判定,返回编号到标签的映射。 @@ -84,7 +96,7 @@ def classify_titles_with_deepseek(titles: list) -> dict: for i in range(1, len(titles) + 1): labels[i] = 'MAYBE' - if not USE_DEEPSEEK: + if not USE_DEEPSEEK or not openai_client: for i, t in enumerate(titles, start=1): labels[i] = 'YES' if contains_keyword(t) else 'MAYBE' return labels @@ -102,7 +114,7 @@ def classify_titles_with_deepseek(titles: list) -> dict: {"role": "system", "content": system_prompt}, {"role": "user", "content": numbered} ], - max_tokens= max(64, len(titles) * 6), + max_tokens=max(64, len(titles) * 6), temperature=0 ) text = resp.choices[0].message.content @@ -144,7 +156,7 @@ def classify_text_with_deepseek(text: str) -> str: """ if not text: return 'MAYBE' - if not USE_DEEPSEEK: + if not USE_DEEPSEEK or not openai_client: return 'YES' if contains_keyword(text) else 'MAYBE' try: prompt_text = text[:3000] @@ -156,31 +168,11 @@ def classify_text_with_deepseek(text: str) -> str: model="deepseek-chat", messages=[ {"role": "system", "content": system_prompt}, -======= -def classify_with_deepseek(text: str) -> bool: - """ - 使用 DeepSeek(OpenAI 兼容接口)对文章进行相关性判断。 - 要求模型只返回 YES 或 NO。出错时返回 False(不相关)。 - """ - if not USE_DEEPSEEK: - return False - try: - # 尽量控制输入长度以减少 token 消耗 - prompt_text = text[:3000] - completion = openai_client.chat.completions.create( - model="deepseek-chat", - messages=[ - {"role": "system", "content": ( - "你是一个简洁的二分类文本判断器。判断给定新闻是否与零食、零售、连锁相关," - "同时包含它们的英文对应词(例如 snack, retail, chain 等)。只返回一个单词:YES 表示相关,NO 表示不相关。" - )}, ->>>>>>> aa51b52135cefdab7496f8d6136479d972f022b9 {"role": "user", "content": prompt_text} ], max_tokens=6, temperature=0 ) -<<<<<<< HEAD out = resp.choices[0].message.content.strip().upper() if out.startswith('Y') or 'YES' in out: return 'YES' @@ -190,15 +182,6 @@ def classify_with_deepseek(text: str) -> bool: except Exception as e: print(f"⚠️ 正文级 DeepSeek 判定出错:{e}") return 'MAYBE' -======= - resp = completion.choices[0].message.content.strip().upper() - if resp.startswith("Y") or resp.startswith("是") or "YES" in resp: - return True - return False - except Exception as e: - print(f"⚠️ DeepSeek 分类出错:{e}") - return False ->>>>>>> aa51b52135cefdab7496f8d6136479d972f022b9 # 获取北京时间 def today_date(): @@ -255,7 +238,6 @@ def fetch_rss_articles(rss_feeds, max_articles=10): continue print(f"✅ {source} RSS 获取成功,共 {len(feed.entries)} 条新闻") -<<<<<<< HEAD # 两轮筛选:1) 标题编号批量判定;2) 对保留项抓取正文并二次判定 entries = feed.entries[:max_articles] titles = [e.get('title', '无标题') for e in entries] @@ -264,10 +246,6 @@ def fetch_rss_articles(rss_feeds, max_articles=10): articles = [] for idx, entry in enumerate(entries, start=1): -======= - articles = [] # 每个 source 都需要重新初始化列表 - for entry in feed.entries[:max_articles]: ->>>>>>> aa51b52135cefdab7496f8d6136479d972f022b9 title = entry.get('title', '无标题') link = entry.get('link', '') or entry.get('guid', '') summary = entry.get('summary', '') or entry.get('description', '') or '' @@ -275,7 +253,6 @@ def fetch_rss_articles(rss_feeds, max_articles=10): print(f"⚠️ {source} 的新闻 '{title}' 没有链接,跳过") continue -<<<<<<< HEAD tlabel = title_labels.get(idx, 'MAYBE') if tlabel == 'NO': print(f"⛔ 标题判定为非相关,跳过: [{idx}] {title}") @@ -292,34 +269,6 @@ def fetch_rss_articles(rss_feeds, max_articles=10): # 保留(YES 或 MAYBE) analysis_text += f"【{title}】\n{article_text}\n\n" print(f"🔹 {source} - [{idx}] {title} 保留 (标题判定={tlabel} -> 正文判定={final_label})") -======= - # 先做快速关键词匹配 - quick_text = f"{title}\n{summary}" - quick_hit = contains_keyword(quick_text) - - # 爬取正文用于深度分析(仅在需要时使用) - article_text = None - if quick_hit: - # 若关键词命中,再爬正文用于后续汇总 - article_text = fetch_article_text(link) - relevant = True - else: - # 关键词未命中,尝试爬取正文并用 DeepSeek 判定 - article_text = fetch_article_text(link) - check_text = f"{title}\n{summary}\n{article_text}" - if USE_DEEPSEEK: - relevant = classify_with_deepseek(check_text) - else: - relevant = False - - if not relevant: - print(f"⛔ 已移除不相关新闻: {title}") - continue - - # 若相关,加入分析文本和展示列表 - analysis_text += f"【{title}】\n{article_text}\n\n" - print(f"🔹 {source} - {title} 获取并保留") ->>>>>>> aa51b52135cefdab7496f8d6136479d972f022b9 articles.append(f"- [{title}]({link})") if articles: @@ -331,22 +280,41 @@ def fetch_rss_articles(rss_feeds, max_articles=10): # AI 生成内容摘要(基于爬取的正文) def summarize(text): - completion = openai_client.chat.completions.create( - model="deepseek-chat", - messages=[ - {"role": "system", "content": """ - 你是一名专业零食连锁零售行业的财经新闻分析师,请根据以下新闻内容,按照以下步骤完成任务: - 1. 提取新闻中涉及的主要行业和主题,找出近1天涨幅最高的3个行业或主题,以及近3天涨幅较高且此前2周表现平淡的3个行业/主题。(如新闻未提供具体涨幅,请结合描述和市场情绪推测热点) - 2. 针对每个热点,输出: - - 催化剂:分析近期上涨的可能原因(政策、数据、事件、情绪等)。 - - 复盘:梳理过去3个月该行业/主题的核心逻辑、关键动态与阶段性走势。 - - 展望:判断该热点是短期炒作还是有持续行情潜力。 - 3. 将以上分析整合为一篇1500字以内的财经热点摘要,逻辑清晰、重点突出,适合专业投资者阅读。 - """}, - {"role": "user", "content": text} - ] - ) - return completion.choices[0].message.content.strip() + """ + 使用 DeepSeek/OpenAI 生成摘要;若未配置 OpenAI,则回退为简单标题列表,且整体捕获异常保证脚本不崩溃。 + """ + try: + if not USE_DEEPSEEK or not openai_client: + # 回退:从 analysis_text 中提取标题列表 + titles = re.findall(r'【([^】]+)】', text) + if not titles: + return "(未配置 OPENAI_API_KEY,且未抓取到可分析的文章。)" + return "未配置 OPENAI_API_KEY,以下为筛选后抓取到的相关文章标题:\n" + "\n".join([f"{i+1}. {t}" for i, t in enumerate(titles)]) + + completion = openai_client.chat.completions.create( + model="deepseek-chat", + messages=[ + {"role": "system", "content": """ + 你是一名专业零食连锁零售行业的财经新闻分析师,请根据以下新闻内容,按照以下步骤完成任务: + 1. 提取新闻中涉及的主要行业和主题,找出近1天涨幅最高的3个行业或主题,以及近3天涨幅较高且此前2周表现平淡的3个行业/主题。(如新闻未提供具体涨幅,请结合描述和市场情绪推测热点) + 2. 针对每个热点,输出: + - 催化剂:分析近期上涨的可能原因(政策、数据、事件、情绪等)。 + - 复盘:梳理过去3个月该行业/主题的核心逻辑、关键动态与阶段性走势。 + - 展望:判断该热点是短期炒作还是有持续行情潜力。 + 3. 将以上分析整合为一篇1500字以内的财经热点摘要,逻辑清晰、重点突出,适合专业投资者阅读。 + """}, + {"role": "user", "content": text} + ] + ) + return completion.choices[0].message.content.strip() + except Exception as e: + print(f"❌ 生成摘要时出错:{e}") + traceback.print_exc() + # 回退到简单标题列表 + titles = re.findall(r'【([^】]+)】', text) + if not titles: + return "(生成摘要失败,且未抓取到可分析的文章。)" + return "生成摘要失败,以下为筛选后抓取到的相关文章标题:\n" + "\n".join([f"{i+1}. {t}" for i, t in enumerate(titles)]) # 发送微信推送 def send_to_wechat(title, content): From 93dcdeab7cb6b317e7a934c74fbeeaf0c07da75e Mon Sep 17 00:00:00 2001 From: littlejie-qinjinshan <18685329778@163.com> Date: Thu, 4 Jun 2026 23:43:14 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0RSS=E6=BA=90-V1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- financebot.py | 100 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/financebot.py b/financebot.py index 789d7592..6d0c2c41 100644 --- a/financebot.py +++ b/financebot.py @@ -38,29 +38,89 @@ # RSS源地址列表 rss_feeds = { - "💲 华尔街见闻":{ - "华尔街见闻":"https://dedicated.wallstreetcn.com/rss.xml", + "💲 财经媒体": { + "华尔街见闻": "https://dedicated.wallstreetcn.com/rss.xml", + "东方财富": "http://rss.eastmoney.com/rss_partener.xml", + "财联社": "https://www.cls.cn/rss", + "第一财经": "https://www.yicai.com/rss/rss.xml", + "每日经济新闻": "https://www.nbd.com.cn/rss", + "财经网": "https://www.caijing.com.cn/rss/index.xml", + "证券时报": "https://www.stcn.com/rss/", + "界面新闻": "https://www.jiemian.com/feed", + "香港经济日报": "https://www.hket.com/rss/china", + "中新网财经": "https://www.chinanews.com.cn/rss/finance.xml", + "人民日报财经": "http://www.people.com.cn/rss/finance.xml", }, - "💻 36氪":{ - "36氪":"https://36kr.com/feed", - }, - "🇨🇳 中国经济": { - "香港經濟日報":"https://www.hket.com/rss/china", - "东方财富":"http://rss.eastmoney.com/rss_partener.xml", - "百度股票焦点":"http://news.baidu.com/n?cmd=1&class=stock&tn=rss&sub=0", - "中新网":"https://www.chinanews.com.cn/rss/finance.xml", - "国家统计局-最新发布":"https://www.stats.gov.cn/sj/zxfb/rss.xml", + "💻 科技媒体": { + "36氪": "https://36kr.com/feed", + "虎嗅网": "https://www.huxiu.com/rss/0.xml", + "钛媒体": "https://www.tmtpost.com/rss", + "爱范儿": "https://www.ifanr.com/feed", + "PingWest品玩": "https://www.pingwest.com/feed", + "新浪科技": "https://tech.sina.com.cn/rss/tech.xml", + "网易科技": "https://tech.163.com/special/000915JB/rss_tech.xml", + "腾讯科技": "https://tech.qq.com/rss/tech.xml", + "极客公园": "https://www.geekpark.net/rss", + "IT之家": "https://www.ithome.com/rss/", + "cnBeta": "https://www.cnbeta.com/backend.php", + "Engadget中文": "https://cn.engadget.com/rss.xml", }, - "🇺🇸 美国经济": { - "华尔街日报 - 经济":"https://feeds.content.dowjones.io/public/rss/WSJcomUSBusiness", - "华尔街日报 - 市场":"https://feeds.content.dowjones.io/public/rss/RSSMarketsMain", - "MarketWatch美股": "https://www.marketwatch.com/rss/topstories", - "ZeroHedge华尔街新闻": "https://feeds.feedburner.com/zerohedge/feed", - "ETF Trends": "https://www.etftrends.com/feed/", + "🛒 零售与电商": { + "亿欧": "https://www.iyiou.com/rss", + "联商网": "https://www.linkshop.com.cn/rss", + "零售老板内参": "https://www.lslb.com/feed", + "电商报": "https://www.dsb.cn/feed", + "天下网商": "https://www.wshang.com/rss", }, - "🌍 世界经济": { - "华尔街日报 - 经济":"https://feeds.content.dowjones.io/public/rss/socialeconomyfeed", - "BBC全球经济": "http://feeds.bbci.co.uk/news/business/rss.xml", + "📱 社交与内容": { + "新榜": "https://www.newrank.cn/feed", + "微果酱": "https://www.wogame.com/feed", + "广告门": "https://www.adquan.com/rss", + "知乎每日精选": "https://www.zhihu.com/rss", + }, + "📰 综合新闻": { + "今日头条": "https://toutiao.com/rss", + "澎湃新闻": "https://www.thepaper.cn/rss", + "封面新闻": "https://www.thecover.cn/rss", + "人民日报时政": "http://www.people.com.cn/rss/politics.xml", + "人民日报国际": "http://www.people.com.cn/rss/world.xml", + }, + "🇺🇸 国际财经": { + "华尔街日报": "https://feeds.content.dowjones.io/public/rss/WSJcomUSBusiness", + "MarketWatch": "https://www.marketwatch.com/rss/topstories", + "BBC商业": "http://feeds.bbci.co.uk/news/business/rss.xml", + "CNBC财经": "https://www.cnbc.com/id/10000664/device/rss/rss.html", + "CNBC商业": "https://www.cnbc.com/id/10001147/device/rss/rss.html", + "CNBC投资": "https://www.cnbc.com/id/15839069/device/rss/rss.html", + "CNBC财报": "https://www.cnbc.com/id/15839135/device/rss/rss.html", + "CNBC新闻": "https://www.cnbc.com/id/100003114/device/rss/rss.html", + }, + "📈 A股市场": { + "个股频道": "http://rss.jrj.com.cn/stock/725.xml", + "综合频道": "http://rss.jrj.com.cn/stock/734.xml", + "个股异动": "http://rss.jrj.com.cn/stock/677.xml", + "报刊头条": "http://rss.jrj.com.cn/stock/742.xml", + "新股要闻": "http://rss.jrj.com.cn/stock/724.xml", + "公告速递": "http://rss.jrj.com.cn/stock/729.xml", + "今日提示": "http://rss.jrj.com.cn/stock/727.xml", + "行业新闻": "http://rss.jrj.com.cn/stock/740.xml", + "数据掘金": "http://rss.jrj.com.cn/stock/736.xml", + "融资融券": "http://rss.jrj.com.cn/stock/733.xml", + "机会情报": "http://rss.jrj.com.cn/stock/745.xml", + }, + "🌍 港股市场": { + "港交所参与者通告": "https://sc.hkex.com.hk/TuniS/www.hkex.com.hk/Services/RSS-Feeds/The-Stock-Exchange-of-Hong-Kong-Limited?sc_lang=zh-HK", + "港交所研究资料": "https://sc.hkex.com.hk/TuniS/www.hkex.com.hk/Services/RSS-Feeds/Research-Materials?sc_lang=zh-HK", + }, + "🇺🇸 美股市场": { + "SeekingAlpha ETF策略": "https://seekingalpha.com/tag/etf-portfolio-strategy.xml", + "SeekingAlpha IPO分析": "https://seekingalpha.com/tag/ipo-analysis.xml", + "SeekingAlpha医疗板块": "https://seekingalpha.com/sector/healthcare.xml", + "SeekingAlpha突发新闻": "https://seekingalpha.com/market_currents.xml", + "纳斯达克财报": "https://www.nasdaq.com/feed/rssoutbound?category=Earnings", + "纳斯达克市场": "https://www.nasdaq.com/feed/rssoutbound?category=Markets", + "纳斯达克分红": "https://www.nasdaq.com/feed/rssoutbound?category=Dividends", + "SEC文件": "https://www.sec.gov/Archives/edgar/xbrlrss.all.xml", }, } From 3abc83ef7e6a37e71f24e71ab17990084f34a293 Mon Sep 17 00:00:00 2001 From: littlejie-qinjinshan <18685329778@163.com> Date: Fri, 5 Jun 2026 00:12:30 +0800 Subject: [PATCH 5/5] =?UTF-8?q?5=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- financebot.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/financebot.py b/financebot.py index 6d0c2c41..3e426939 100644 --- a/financebot.py +++ b/financebot.py @@ -284,7 +284,7 @@ def fetch_feed_with_retry(url, retries=3, delay=5): return None # 获取RSS内容(爬取正文但不展示) -def fetch_rss_articles(rss_feeds, max_articles=10): +def fetch_rss_articles(rss_feeds, max_articles=None): news_data = {} analysis_text = "" # 用于AI分析的正文内容 @@ -299,10 +299,21 @@ def fetch_rss_articles(rss_feeds, max_articles=10): print(f"✅ {source} RSS 获取成功,共 {len(feed.entries)} 条新闻") # 两轮筛选:1) 标题编号批量判定;2) 对保留项抓取正文并二次判定 - entries = feed.entries[:max_articles] + if max_articles: + entries = feed.entries[:max_articles] + else: + entries = feed.entries titles = [e.get('title', '无标题') for e in entries] title_labels = classify_titles_with_deepseek(titles) - print(f"🔎 {source} 标题级判定: " + ", ".join([f"{i}:{title_labels.get(i)}" for i in sorted(title_labels.keys())])) + # 打印所有判定结果 + label_strs = [f"{i}:{title_labels.get(i)}" for i in sorted(title_labels.keys())] + # 如果结果太多,分块打印,每行最多10个 + for i in range(0, len(label_strs), 10): + chunk = label_strs[i:i+10] + if i == 0: + print(f"🔎 {source} 标题级判定: " + ", ".join(chunk)) + else: + print(" " + ", ".join(chunk)) articles = [] for idx, entry in enumerate(entries, start=1): @@ -391,8 +402,8 @@ def send_to_wechat(title, content): if __name__ == "__main__": today_str = today_date().strftime("%Y-%m-%d") - # 每个网站获取最多 5 篇文章 - articles_data, analysis_text = fetch_rss_articles(rss_feeds, max_articles=5) + # 每个网站获取所有文章 + articles_data, analysis_text = fetch_rss_articles(rss_feeds) # AI生成摘要 summary = summarize(analysis_text)