mirror of
https://gitee.com/houhuan/TrendRadar.git
synced 2025-12-21 14:27:15 +08:00
v2.3.0
This commit is contained in:
parent
b73f16d7cd
commit
89ab87cad2
5
.github/workflows/crawler.yml
vendored
5
.github/workflows/crawler.yml
vendored
@ -53,6 +53,11 @@ jobs:
|
||||
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||||
DINGTALK_WEBHOOK_URL: ${{ secrets.DINGTALK_WEBHOOK_URL }}
|
||||
WEWORK_WEBHOOK_URL: ${{ secrets.WEWORK_WEBHOOK_URL }}
|
||||
EMAIL_FROM: ${{ secrets.EMAIL_FROM }}
|
||||
EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }}
|
||||
EMAIL_TO: ${{ secrets.EMAIL_TO }}
|
||||
EMAIL_SMTP_SERVER: ${{ secrets.EMAIL_SMTP_SERVER }}
|
||||
EMAIL_SMTP_PORT: ${{ secrets.EMAIL_SMTP_PORT }}
|
||||
GITHUB_ACTIONS: true
|
||||
run: python main.py
|
||||
|
||||
|
||||
@ -53,6 +53,11 @@ notification:
|
||||
wework_url: "" # 企业微信机器人的 webhook URL
|
||||
telegram_bot_token: "" # Telegram Bot Token
|
||||
telegram_chat_id: "" # Telegram Chat ID
|
||||
email_from: "" # 发件人邮箱地址
|
||||
email_password: "" # 发件人邮箱密码或授权码
|
||||
email_to: "" # 收件人邮箱地址,多个收件人用逗号分隔
|
||||
email_smtp_server: "" # SMTP服务器地址(可选,留空自动识别)
|
||||
email_smtp_port: "" # SMTP端口(可选,留空自动识别)
|
||||
|
||||
# 用于让关注度更高的新闻在更前面显示,即用算法重新组合不同平台的热搜排序形成你侧重的热搜,合起来是 1 就行
|
||||
weight:
|
||||
|
||||
@ -4,6 +4,11 @@ TELEGRAM_BOT_TOKEN=
|
||||
TELEGRAM_CHAT_ID=
|
||||
DINGTALK_WEBHOOK_URL=
|
||||
WEWORK_WEBHOOK_URL=
|
||||
EMAIL_FROM=
|
||||
EMAIL_PASSWORD=
|
||||
EMAIL_TO=
|
||||
EMAIL_SMTP_SERVER=
|
||||
EMAIL_SMTP_PORT=
|
||||
|
||||
# 运行配置
|
||||
CRON_SCHEDULE=*/30 * * * * # 定时任务表达式,每 30 分钟执行一次(比如 8点,8点半,9点,9点半这种时间规律执行)
|
||||
|
||||
@ -17,6 +17,11 @@ services:
|
||||
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID:-}
|
||||
- DINGTALK_WEBHOOK_URL=${DINGTALK_WEBHOOK_URL:-}
|
||||
- WEWORK_WEBHOOK_URL=${WEWORK_WEBHOOK_URL:-}
|
||||
- EMAIL_FROM=${EMAIL_FROM:-}
|
||||
- EMAIL_PASSWORD=${EMAIL_PASSWORD:-}
|
||||
- EMAIL_TO=${EMAIL_TO:-}
|
||||
- EMAIL_SMTP_SERVER=${EMAIL_SMTP_SERVER:-}
|
||||
- EMAIL_SMTP_PORT=${EMAIL_SMTP_PORT:-}
|
||||
- CRON_SCHEDULE=${CRON_SCHEDULE:-*/5 * * * *}
|
||||
- RUN_MODE=${RUN_MODE:-cron}
|
||||
- IMMEDIATE_RUN=${IMMEDIATE_RUN:-true}
|
||||
|
||||
@ -15,6 +15,11 @@ services:
|
||||
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID:-}
|
||||
- DINGTALK_WEBHOOK_URL=${DINGTALK_WEBHOOK_URL:-}
|
||||
- WEWORK_WEBHOOK_URL=${WEWORK_WEBHOOK_URL:-}
|
||||
- EMAIL_FROM=${EMAIL_FROM:-}
|
||||
- EMAIL_PASSWORD=${EMAIL_PASSWORD:-}
|
||||
- EMAIL_TO=${EMAIL_TO:-}
|
||||
- EMAIL_SMTP_SERVER=${EMAIL_SMTP_SERVER:-}
|
||||
- EMAIL_SMTP_PORT=${EMAIL_SMTP_PORT:-}
|
||||
- CRON_SCHEDULE=${CRON_SCHEDULE:-*/5 * * * *}
|
||||
- RUN_MODE=${RUN_MODE:-cron}
|
||||
- IMMEDIATE_RUN=${IMMEDIATE_RUN:-true}
|
||||
|
||||
264
main.py
264
main.py
@ -6,6 +6,11 @@ import random
|
||||
import re
|
||||
import time
|
||||
import webbrowser
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.header import Header
|
||||
from email.utils import formataddr, formatdate, make_msgid
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple, Optional, Union
|
||||
@ -15,9 +20,69 @@ import requests
|
||||
import yaml
|
||||
|
||||
|
||||
VERSION = "2.2.0"
|
||||
VERSION = "2.3.0"
|
||||
|
||||
|
||||
# === SMTP邮件配置 ===
|
||||
SMTP_CONFIGS = {
|
||||
# Gmail
|
||||
'gmail.com': {
|
||||
'server': 'smtp.gmail.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
|
||||
# QQ邮箱
|
||||
'qq.com': {
|
||||
'server': 'smtp.qq.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
|
||||
# Outlook
|
||||
'outlook.com': {
|
||||
'server': 'smtp-mail.outlook.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
'hotmail.com': {
|
||||
'server': 'smtp-mail.outlook.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
'live.com': {
|
||||
'server': 'smtp-mail.outlook.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
|
||||
# 网易邮箱
|
||||
'163.com': {
|
||||
'server': 'smtp.163.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
'126.com': {
|
||||
'server': 'smtp.126.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
|
||||
# 新浪邮箱
|
||||
'sina.com': {
|
||||
'server': 'smtp.sina.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
},
|
||||
|
||||
# 搜狐邮箱
|
||||
'sohu.com': {
|
||||
'server': 'smtp.sohu.com',
|
||||
'port': 587,
|
||||
'encryption': 'TLS'
|
||||
}
|
||||
}
|
||||
|
||||
# === 配置管理 ===
|
||||
def load_config():
|
||||
"""加载配置文件"""
|
||||
@ -96,6 +161,23 @@ def load_config():
|
||||
config["TELEGRAM_CHAT_ID"] = os.environ.get(
|
||||
"TELEGRAM_CHAT_ID", ""
|
||||
).strip() or webhooks.get("telegram_chat_id", "")
|
||||
|
||||
# 邮件配置
|
||||
config["EMAIL_FROM"] = os.environ.get(
|
||||
"EMAIL_FROM", ""
|
||||
).strip() or webhooks.get("email_from", "")
|
||||
config["EMAIL_PASSWORD"] = os.environ.get(
|
||||
"EMAIL_PASSWORD", ""
|
||||
).strip() or webhooks.get("email_password", "")
|
||||
config["EMAIL_TO"] = os.environ.get(
|
||||
"EMAIL_TO", ""
|
||||
).strip() or webhooks.get("email_to", "")
|
||||
config["EMAIL_SMTP_SERVER"] = os.environ.get(
|
||||
"EMAIL_SMTP_SERVER", ""
|
||||
).strip() or webhooks.get("email_smtp_server", "")
|
||||
config["EMAIL_SMTP_PORT"] = os.environ.get(
|
||||
"EMAIL_SMTP_PORT", ""
|
||||
).strip() or webhooks.get("email_smtp_port", "")
|
||||
|
||||
# 输出配置来源信息
|
||||
webhook_sources = []
|
||||
@ -114,7 +196,10 @@ def load_config():
|
||||
)
|
||||
chat_source = "环境变量" if os.environ.get("TELEGRAM_CHAT_ID") else "配置文件"
|
||||
webhook_sources.append(f"Telegram({token_source}/{chat_source})")
|
||||
|
||||
if config["EMAIL_FROM"] and config["EMAIL_PASSWORD"] and config["EMAIL_TO"]:
|
||||
from_source = "环境变量" if os.environ.get("EMAIL_FROM") else "配置文件"
|
||||
webhook_sources.append(f"邮件({from_source})")
|
||||
|
||||
if webhook_sources:
|
||||
print(f"Webhook 配置来源: {', '.join(webhook_sources)}")
|
||||
else:
|
||||
@ -1464,6 +1549,7 @@ def generate_html_report(
|
||||
id_to_name: Optional[Dict] = None,
|
||||
mode: str = "daily",
|
||||
is_daily_summary: bool = False,
|
||||
update_info: Optional[Dict] = None,
|
||||
) -> str:
|
||||
"""生成HTML报告"""
|
||||
if is_daily_summary:
|
||||
@ -1481,7 +1567,7 @@ def generate_html_report(
|
||||
report_data = prepare_report_data(stats, failed_ids, new_titles, id_to_name, mode)
|
||||
|
||||
html_content = render_html_content(
|
||||
report_data, total_titles, is_daily_summary, mode
|
||||
report_data, total_titles, is_daily_summary, mode, update_info
|
||||
)
|
||||
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
@ -1500,6 +1586,7 @@ def render_html_content(
|
||||
total_titles: int,
|
||||
is_daily_summary: bool = False,
|
||||
mode: str = "daily",
|
||||
update_info: Optional[Dict] = None,
|
||||
) -> str:
|
||||
"""渲染HTML内容"""
|
||||
html = """
|
||||
@ -1876,7 +1963,7 @@ def render_html_content(
|
||||
.footer-content {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
line-height: 1.4;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
@ -2157,7 +2244,16 @@ def render_html_content(
|
||||
由 <span class="project-name">TrendRadar</span> 生成 ·
|
||||
<a href="https://github.com/sansan0/TrendRadar" target="_blank" class="footer-link">
|
||||
GitHub 开源项目
|
||||
</a>
|
||||
</a>"""
|
||||
|
||||
if update_info:
|
||||
html += f"""
|
||||
<br>
|
||||
<span style="color: #ea580c; font-weight: 500;">
|
||||
发现新版本 {update_info['remote_version']},当前版本 {update_info['current_version']}
|
||||
</span>"""
|
||||
|
||||
html += """
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -2823,6 +2919,7 @@ def send_to_webhooks(
|
||||
update_info: Optional[Dict] = None,
|
||||
proxy_url: Optional[str] = None,
|
||||
mode: str = "daily",
|
||||
html_file_path: Optional[str] = None,
|
||||
) -> Dict[str, bool]:
|
||||
"""发送数据到多个webhook平台"""
|
||||
results = {}
|
||||
@ -2851,6 +2948,11 @@ def send_to_webhooks(
|
||||
wework_url = CONFIG["WEWORK_WEBHOOK_URL"]
|
||||
telegram_token = CONFIG["TELEGRAM_BOT_TOKEN"]
|
||||
telegram_chat_id = CONFIG["TELEGRAM_CHAT_ID"]
|
||||
email_from = CONFIG["EMAIL_FROM"]
|
||||
email_password = CONFIG["EMAIL_PASSWORD"]
|
||||
email_to = CONFIG["EMAIL_TO"]
|
||||
email_smtp_server = CONFIG.get("EMAIL_SMTP_SERVER", "")
|
||||
email_smtp_port = CONFIG.get("EMAIL_SMTP_PORT", "")
|
||||
|
||||
update_info_to_send = update_info if CONFIG["SHOW_VERSION_UPDATE"] else None
|
||||
|
||||
@ -2884,6 +2986,18 @@ def send_to_webhooks(
|
||||
mode,
|
||||
)
|
||||
|
||||
# 发送邮件
|
||||
if email_from and email_password and email_to:
|
||||
results["email"] = send_to_email(
|
||||
email_from,
|
||||
email_password,
|
||||
email_to,
|
||||
report_type,
|
||||
html_file_path,
|
||||
email_smtp_server,
|
||||
email_smtp_port,
|
||||
)
|
||||
|
||||
if not results:
|
||||
print("未配置任何webhook URL,跳过通知发送")
|
||||
|
||||
@ -3156,6 +3270,137 @@ def send_to_telegram(
|
||||
print(f"Telegram所有 {len(batches)} 批次发送完成 [{report_type}]")
|
||||
return True
|
||||
|
||||
def send_to_email(
|
||||
from_email: str,
|
||||
password: str,
|
||||
to_email: str,
|
||||
report_type: str,
|
||||
html_file_path: str,
|
||||
custom_smtp_server: Optional[str] = None,
|
||||
custom_smtp_port: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""发送邮件通知"""
|
||||
try:
|
||||
if not html_file_path or not Path(html_file_path).exists():
|
||||
print(f"错误:HTML文件不存在或未提供: {html_file_path}")
|
||||
return False
|
||||
|
||||
print(f"使用HTML文件: {html_file_path}")
|
||||
with open(html_file_path, "r", encoding="utf-8") as f:
|
||||
html_content = f.read()
|
||||
|
||||
domain = from_email.split('@')[-1].lower()
|
||||
|
||||
if custom_smtp_server and custom_smtp_port:
|
||||
# 使用自定义 SMTP 配置
|
||||
smtp_server = custom_smtp_server
|
||||
smtp_port = int(custom_smtp_port)
|
||||
use_tls = smtp_port == 587
|
||||
elif domain in SMTP_CONFIGS:
|
||||
# 使用预设配置
|
||||
config = SMTP_CONFIGS[domain]
|
||||
smtp_server = config['server']
|
||||
smtp_port = config['port']
|
||||
use_tls = config['encryption'] == 'TLS'
|
||||
else:
|
||||
print(f"未识别的邮箱服务商: {domain},使用通用 SMTP 配置")
|
||||
smtp_server = f"smtp.{domain}"
|
||||
smtp_port = 587
|
||||
use_tls = True
|
||||
|
||||
msg = MIMEMultipart('alternative')
|
||||
|
||||
# 严格按照 RFC 标准设置 From header
|
||||
sender_name = "TrendRadar"
|
||||
msg['From'] = formataddr((sender_name, from_email))
|
||||
|
||||
# 设置收件人
|
||||
recipients = [addr.strip() for addr in to_email.split(',')]
|
||||
if len(recipients) == 1:
|
||||
msg['To'] = recipients[0]
|
||||
else:
|
||||
msg['To'] = ', '.join(recipients)
|
||||
|
||||
# 设置邮件主题
|
||||
now = get_beijing_time()
|
||||
subject = f"TrendRadar 热点分析报告 - {report_type} - {now.strftime('%m月%d日 %H:%M')}"
|
||||
msg['Subject'] = Header(subject, 'utf-8')
|
||||
|
||||
# 设置其他标准 header
|
||||
msg['MIME-Version'] = '1.0'
|
||||
msg['Date'] = formatdate(localtime=True)
|
||||
msg['Message-ID'] = make_msgid()
|
||||
|
||||
# 添加纯文本部分(作为备选)
|
||||
text_content = f"""
|
||||
TrendRadar 热点分析报告
|
||||
========================
|
||||
报告类型:{report_type}
|
||||
生成时间:{now.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
|
||||
请使用支持HTML的邮件客户端查看完整报告内容。
|
||||
"""
|
||||
text_part = MIMEText(text_content, 'plain', 'utf-8')
|
||||
msg.attach(text_part)
|
||||
|
||||
html_part = MIMEText(html_content, 'html', 'utf-8')
|
||||
msg.attach(html_part)
|
||||
|
||||
print(f"正在发送邮件到 {to_email}...")
|
||||
print(f"SMTP 服务器: {smtp_server}:{smtp_port}")
|
||||
print(f"发件人: {from_email}")
|
||||
|
||||
try:
|
||||
if use_tls:
|
||||
# TLS 模式
|
||||
server = smtplib.SMTP(smtp_server, smtp_port, timeout=30)
|
||||
server.set_debuglevel(0) # 设为1可以查看详细调试信息
|
||||
server.ehlo()
|
||||
server.starttls()
|
||||
server.ehlo()
|
||||
else:
|
||||
# SSL 模式
|
||||
server = smtplib.SMTP_SSL(smtp_server, smtp_port, timeout=30)
|
||||
server.set_debuglevel(0)
|
||||
server.ehlo()
|
||||
|
||||
# 登录
|
||||
server.login(from_email, password)
|
||||
|
||||
# 发送邮件
|
||||
server.send_message(msg)
|
||||
server.quit()
|
||||
|
||||
print(f"邮件发送成功 [{report_type}] -> {to_email}")
|
||||
return True
|
||||
|
||||
except smtplib.SMTPServerDisconnected:
|
||||
print(f"邮件发送失败:服务器意外断开连接,请检查网络或稍后重试")
|
||||
return False
|
||||
|
||||
except smtplib.SMTPAuthenticationError as e:
|
||||
print(f"邮件发送失败:认证错误,请检查邮箱和密码/授权码")
|
||||
print(f"详细错误: {str(e)}")
|
||||
return False
|
||||
except smtplib.SMTPRecipientsRefused as e:
|
||||
print(f"邮件发送失败:收件人地址被拒绝 {e}")
|
||||
return False
|
||||
except smtplib.SMTPSenderRefused as e:
|
||||
print(f"邮件发送失败:发件人地址被拒绝 {e}")
|
||||
return False
|
||||
except smtplib.SMTPDataError as e:
|
||||
print(f"邮件发送失败:邮件数据错误 {e}")
|
||||
return False
|
||||
except smtplib.SMTPConnectError as e:
|
||||
print(f"邮件发送失败:无法连接到 SMTP 服务器 {smtp_server}:{smtp_port}")
|
||||
print(f"详细错误: {str(e)}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"邮件发送失败 [{report_type}]:{e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
# === 主分析器 ===
|
||||
class NewsAnalyzer:
|
||||
@ -3374,6 +3619,7 @@ class NewsAnalyzer:
|
||||
id_to_name=id_to_name,
|
||||
mode=mode,
|
||||
is_daily_summary=is_daily_summary,
|
||||
update_info=self.update_info if CONFIG["SHOW_VERSION_UPDATE"] else None,
|
||||
)
|
||||
|
||||
return stats, html_file
|
||||
@ -3386,6 +3632,7 @@ class NewsAnalyzer:
|
||||
failed_ids: Optional[List] = None,
|
||||
new_titles: Optional[Dict] = None,
|
||||
id_to_name: Optional[Dict] = None,
|
||||
html_file_path: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""统一的通知发送逻辑,包含所有判断条件"""
|
||||
has_webhook = self._has_webhook_configured()
|
||||
@ -3404,6 +3651,7 @@ class NewsAnalyzer:
|
||||
self.update_info,
|
||||
self.proxy_url,
|
||||
mode=mode,
|
||||
html_file_path=html_file_path,
|
||||
)
|
||||
return True
|
||||
elif CONFIG["ENABLE_NOTIFICATION"] and not has_webhook:
|
||||
@ -3456,14 +3704,16 @@ class NewsAnalyzer:
|
||||
)
|
||||
|
||||
print(f"{summary_type}报告已生成: {html_file}")
|
||||
|
||||
|
||||
# 发送通知
|
||||
self._send_notification_if_needed(
|
||||
stats,
|
||||
mode_strategy["summary_report_type"],
|
||||
mode_strategy["summary_mode"],
|
||||
failed_ids=[],
|
||||
new_titles=new_titles,
|
||||
id_to_name=id_to_name,
|
||||
html_file_path=html_file,
|
||||
)
|
||||
|
||||
return html_file
|
||||
@ -3596,6 +3846,7 @@ class NewsAnalyzer:
|
||||
failed_ids=failed_ids,
|
||||
new_titles=historical_new_titles,
|
||||
id_to_name=combined_id_to_name,
|
||||
html_file_path=html_file,
|
||||
)
|
||||
else:
|
||||
print("❌ 严重错误:无法读取刚保存的数据文件")
|
||||
@ -3624,6 +3875,7 @@ class NewsAnalyzer:
|
||||
failed_ids=failed_ids,
|
||||
new_titles=new_titles,
|
||||
id_to_name=id_to_name,
|
||||
html_file_path=html_file,
|
||||
)
|
||||
|
||||
# 生成汇总报告(如果需要)
|
||||
|
||||
110
readme.md
110
readme.md
@ -9,12 +9,13 @@
|
||||
[](https://github.com/sansan0/TrendRadar/stargazers)
|
||||
[](https://github.com/sansan0/TrendRadar/network/members)
|
||||
[](LICENSE)
|
||||
[](https://github.com/sansan0/TrendRadar)
|
||||
[](https://github.com/sansan0/TrendRadar)
|
||||
|
||||
[](https://work.weixin.qq.com/)
|
||||
[](https://telegram.org/)
|
||||
[](#)
|
||||
[](https://www.feishu.cn/)
|
||||
[](https://work.weixin.qq.com/)
|
||||
[](https://telegram.org/)
|
||||
[](#)
|
||||
[](https://www.feishu.cn/)
|
||||
[](mailto:)
|
||||
[](https://github.com/sansan0/TrendRadar)
|
||||
[](https://sansan0.github.io/TrendRadar)
|
||||
[](https://hub.docker.com/)
|
||||
@ -29,7 +30,7 @@
|
||||
- 遇到问题可选择以上 2 种方式获得帮助,[点此跳转到两者的区别](#问题答疑与1元点赞)
|
||||
|
||||
<details>
|
||||
<summary>👉 点击查看<strong>致谢名单</strong> (当前 <strong>🔥22🔥</strong> 位)</summary>
|
||||
<summary>👉 点击查看<strong>致谢名单</strong> (当前 <strong>🔥23🔥</strong> 位)</summary>
|
||||
|
||||
### 数据支持
|
||||
|
||||
@ -49,6 +50,7 @@
|
||||
|
||||
| 点赞人 | 金额 | 日期 | 备注 |
|
||||
| :-------------------------: | :----: | :----: | :-----------------------: |
|
||||
| *🍍 | 10 | 2025.9.21 | |
|
||||
| E*f | 1 | 2025.9.20 | |
|
||||
| *记 | 1 | 2025.9.20 | |
|
||||
| z*u | 2 | 2025.9.19 | |
|
||||
@ -186,7 +188,11 @@ weight:
|
||||
|
||||
### **多渠道实时推送**
|
||||
|
||||
支持**企业微信**(微信方案)、**飞书**、**钉钉**、**Telegram**,消息直达手机
|
||||
支持**企业微信**(+ 微信推送方案)、**飞书**、**钉钉**、**Telegram**、**邮件**,消息直达手机和邮箱
|
||||
|
||||
- **邮件推送**:支持 QQ邮箱、Gmail、Outlook、163邮箱等主流邮箱服务
|
||||
- **智能识别**:自动识别邮箱服务商,也可以手动配置 SMTP 服务器
|
||||
- **HTML 格式**:精美的 HTML 邮件格式,与网页版效果一致
|
||||
|
||||
### **多端适配**
|
||||
- **GitHub Pages**:自动生成精美网页报告,PC/移动端适配
|
||||
@ -212,7 +218,7 @@ GitHub 一键 Fork 即可使用,无需编程基础。
|
||||
**典型场景:** 股市投资监控、品牌舆情追踪、行业动态关注、生活资讯获取
|
||||
|
||||
|
||||
| Github Pages 网页效果(手机端适配) | 飞书推送效果 |
|
||||
| Github Pages 效果(手机端适配、邮箱推送效果) | 飞书推送效果 |
|
||||
|:---:|:---:|
|
||||
|  |  |
|
||||
|
||||
@ -290,6 +296,28 @@ GitHub 一键 Fork 即可使用,无需编程基础。
|
||||
>
|
||||
> 下一次**新功能**,大概会是 ai 分析功能(●'◡'●)
|
||||
|
||||
### 2025/09/22 - v2.3.0
|
||||
|
||||
- **新增邮件推送功能**,支持将热点新闻报告发送到邮箱
|
||||
- **智能 SMTP 识别**:自动识别 Gmail、QQ邮箱、Outlook、网易邮箱等 10+ 种邮箱服务商配置
|
||||
- **HTML 精美格式**:邮件内容采用与网页版相同的 HTML 格式,排版精美,移动端适配
|
||||
- **批量发送支持**:支持多个收件人,用逗号分隔即可同时发送给多人
|
||||
- **自定义 SMTP**:可自定义 SMTP 服务器和端口
|
||||
|
||||
**使用说明**:
|
||||
- 适用场景:适合需要邮件归档、团队分享、定时报告的用户
|
||||
- 注意事项:为防止邮件群发功能被**滥用**,当前的群发是所有收件人都能看到彼此的邮箱地址,适合熟人间交流资讯
|
||||
|
||||
**支持的邮箱服务**:
|
||||
- Gmail、QQ邮箱、Outlook/Hotmail、163/126邮箱、新浪邮箱、搜狐邮箱等
|
||||
|
||||
**更新提示**:
|
||||
- 此次更新的内容比较多,建议删除原有 fork, 重新 fork 并配置
|
||||
|
||||
|
||||
<details>
|
||||
<summary><strong>👉 历史更新</strong></summary>
|
||||
|
||||
### 2025/09/17 - v2.2.0
|
||||
|
||||
- 新增一键保存新闻图片功能,让你轻松分享关注的热点
|
||||
@ -300,9 +328,6 @@ GitHub 一键 Fork 即可使用,无需编程基础。
|
||||
- 实际效果:系统会自动将当前的新闻报告制作成一张精美图片,保存到你的手机相册或电脑桌面
|
||||
- 分享便利:你可以直接把这张图片发给朋友、发到朋友圈,或分享到工作群,让别人也能看到你发现的重要资讯
|
||||
|
||||
<details>
|
||||
<summary><strong>👉 历史更新</strong></summary>
|
||||
|
||||
### 2025/09/13 - v2.1.2
|
||||
|
||||
- 解决钉钉的推送容量限制导致的新闻推送失败问题(采用分批推送)
|
||||
@ -581,6 +606,49 @@ frequency_words.txt 文件增加了一个【必须词】功能,使用 + 号
|
||||
- `TELEGRAM_CHAT_ID`:填入第 2 步获得的 Chat ID
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary> <strong>👉 邮件推送</strong>(支持所有主流邮箱)</summary>
|
||||
<br>
|
||||
|
||||
- 注意事项:为防止邮件群发功能被**滥用**,当前的群发是所有收件人都能看到彼此的邮箱地址,适合熟人间交流资讯。
|
||||
- 仅供参考:请根据实际情况调整,邮箱方面并没有一一验证,是按照 SMTP 的标准配置的
|
||||
|
||||
**GitHub Secret 配置:**
|
||||
- 名称:`EMAIL_FROM` - 发件人邮箱地址
|
||||
- 名称:`EMAIL_PASSWORD` - 邮箱密码或授权码
|
||||
- 名称:`EMAIL_TO` - 收件人邮箱地址(多个收件人用英文逗号分隔)
|
||||
- 名称:`EMAIL_SMTP_SERVER` - SMTP服务器地址(可选,留空则自动识别)
|
||||
- 名称:`EMAIL_SMTP_PORT` - SMTP端口(可选,留空则自动识别)
|
||||
|
||||
**常见邮箱设置:**
|
||||
|
||||
#### QQ邮箱:
|
||||
1. 登录 QQ邮箱网页版 → 设置 → 账户
|
||||
2. 开启 POP3/SMTP 服务
|
||||
3. 生成授权码(16位字母)
|
||||
4. `EMAIL_PASSWORD` 填写授权码,而非 QQ 密码
|
||||
|
||||
#### Gmail:
|
||||
1. 开启两步验证
|
||||
2. 生成应用专用密码
|
||||
3. `EMAIL_PASSWORD` 填写应用专用密码
|
||||
|
||||
#### 163/126邮箱:
|
||||
1. 登录网页版 → 设置 → POP3/SMTP/IMAP
|
||||
2. 开启 SMTP 服务
|
||||
3. 设置客户端授权码
|
||||
4. `EMAIL_PASSWORD` 填写授权码
|
||||
|
||||
**高级配置**:
|
||||
如果自动识别失败,可手动配置 SMTP:
|
||||
- `EMAIL_SMTP_SERVER`:如 smtp.gmail.com
|
||||
- `EMAIL_SMTP_PORT`:如 587(TLS)或 465(SSL)
|
||||
|
||||
**多收件人设置**:
|
||||
- EMAIL_TO="user1@example.com,user2@example.com,user3@example.com"
|
||||
|
||||
</details>
|
||||
|
||||
3. **主要配置**:
|
||||
|
||||
- **推送设置:** : 在 [config/config.yaml](config/config.yaml) 中进行,可根据里面的描述文字操作,这里不重复了
|
||||
@ -765,7 +833,7 @@ docker run -d --name trend-radar \
|
||||
-e IMMEDIATE_RUN="true" \
|
||||
wantcat/trendradar:latest
|
||||
|
||||
# 或者启用手机应用推送通知
|
||||
# 或者启用手机应用推送通知或邮件通知
|
||||
docker run -d --name trend-radar \
|
||||
-v ./config:/app/config:ro \
|
||||
-v ./output:/app/output \
|
||||
@ -774,6 +842,9 @@ docker run -d --name trend-radar \
|
||||
-e WEWORK_WEBHOOK_URL="你的企业微信webhook" \
|
||||
-e TELEGRAM_BOT_TOKEN="你的telegram_bot_token" \
|
||||
-e TELEGRAM_CHAT_ID="你的telegram_chat_id" \
|
||||
-e EMAIL_FROM="你的发件邮箱" \
|
||||
-e EMAIL_PASSWORD="你的邮箱密码或授权码" \
|
||||
-e EMAIL_TO="收件人邮箱" \
|
||||
-e CRON_SCHEDULE="*/30 * * * *" \
|
||||
-e RUN_MODE="cron" \
|
||||
-e IMMEDIATE_RUN="true" \
|
||||
@ -946,21 +1017,14 @@ docker exec -it trend-radar ls -la /app/config/
|
||||
|
||||
> 心意到就行,收到的**点赞**用于提高开发者开源的积极性。你们的**点赞**已记录于最顶部的【致谢名单】
|
||||
|
||||
<div align="center">
|
||||
|
||||
|公众号关注 |微信点赞 | 支付宝点赞 |
|
||||
|:---:|:---:|:---:|
|
||||
| <img src="_image/weixin.png" width="300" title="硅基茶水间"/> | <img src="https://cdn-1258574687.cos.ap-shanghai.myqcloud.com/img/%2F2025%2F07%2F17%2F2ae0a88d98079f7e876c2b4dc85233c6-9e8025.JPG" width="300" title="微信支付"/> | <img src="https://cdn-1258574687.cos.ap-shanghai.myqcloud.com/img/%2F2025%2F07%2F17%2Fed4f20ab8e35be51f8e84c94e6e239b4-fe4947.JPG" width="300" title="支付宝支付"/> |
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
| 答疑方式 | 适用场景 | 响应时间 | 详细程度 | 如何提问 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| **GitHub Issues** | 部署配置问题<br/>功能异常 | 1-2天内 | 针对性强 | 📋 **提供完整信息**:<br/>• 尽量截图<br/>• 错误日志<br/>• 系统环境等等 |
|
||||
| **公众号留言** | 快速咨询<br/>使用疑问<br/>功能了解 | 几小时 | 简要指导 | 💡 **抓住问题核心**:<br/>• 一句话描述问题<br/>• 说明想要的效果 |
|
||||
|
||||
|
||||
| 答疑方式 | 适用场景 | 响应时间 | 详细程度 | 社区参与度 | 如何提问 |
|
||||
|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| **GitHub Issues** | 部署配置问题<br/>功能异常 | 1-2天内 | 针对性强 | **公开讨论**<br/>其他用户可参与<br/>问题记录可搜索 | 📋 **提供完整信息**:<br/>• 尽量截图<br/>• 错误日志<br/>• 系统环境等等 |
|
||||
| **公众号交流** | 快速咨询<br/>使用疑问<br/>功能了解 | 几小时 | 简要指导 | 可以文章下留言<br/>也可以私信交流 | 💡 **抓住问题核心**:<br/>• 一句话描述问题<br/>• 说明想要的效果 |
|
||||
|
||||
### 项目相关
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user