From b1d6e62ca96bda9134c400c01204ca6e892e9a61 Mon Sep 17 00:00:00 2001 From: blade <8019068@qq.com> Date: Tue, 21 Oct 2025 17:49:04 +0800 Subject: [PATCH] support auto-fetch-push Trump articles on Truth Social at 9:00 am (Beijing) --- auto_fetch_truth_social.py | 4 +- config.py | 1 + core/db/db_truth_social_content.py | 16 +++++ .../truth_social_retriever.cpython-312.pyc | Bin 8173 -> 11681 bytes core/media/truth_social_retriever.py | 58 +++++++++++++++++- core/wechat.py | 34 +++++++++- truth_social_retriever_main.py | 2 + 7 files changed, 108 insertions(+), 7 deletions(-) diff --git a/auto_fetch_truth_social.py b/auto_fetch_truth_social.py index b4be396..0a33541 100644 --- a/auto_fetch_truth_social.py +++ b/auto_fetch_truth_social.py @@ -25,8 +25,8 @@ def run_script(): subprocess.run([python_path, script_path]) end_time = time.time() logger.info(f"Script execution time: {end_time - start_time} seconds") -# 设置每天凌晨00:00 运行一次 -schedule.every().day.at("00:00:00").do(run_script) +# 设置每天上午09:00:00 运行一次 +schedule.every().day.at("09:00:00").do(run_script) # schedule.every(60).seconds.do(run_script) # 保持程序运行并检查调度 diff --git a/config.py b/config.py index ef10b04..4804750 100644 --- a/config.py +++ b/config.py @@ -210,6 +210,7 @@ A_MYSQL_CONFIG = { WECHAT_CONFIG = { "general_key": "11e6f7ac-efa9-418a-904c-9325a9f5d324", "btc_key": "529e135d-843b-43dc-8aca-677a860f4b4b", + "trump_key": "dabe1166-9faa-49b0-b41e-64c4507a2f5b", } ITICK_API_KEY = "dfd4bc0caed148d6bc03b960224754ffb5356349e389431f828702b3a27e8a2b" diff --git a/core/db/db_truth_social_content.py b/core/db/db_truth_social_content.py index 6e3b9eb..0cf2c88 100644 --- a/core/db/db_truth_social_content.py +++ b/core/db/db_truth_social_content.py @@ -117,6 +117,22 @@ class DBTruthSocialContent: condition_dict = {"user_id": user_id, "limit": limit} return self.db_manager.query_data(sql, condition_dict, return_multi=True) + def query_data_by_article_id(self, article_id: str): + """ + 根据文章ID查询数据 + :param article_id: 文章ID + """ + sql = """ + SELECT * FROM truth_social_content + WHERE article_id = :article_id + """ + condition_dict = {"article_id": article_id} + result = self.db_manager.query_data(sql, condition_dict, return_multi=False) + if result: + return result + else: + return None + def query_data_by_timestamp_range( self, start_timestamp: int = None, diff --git a/core/media/__pycache__/truth_social_retriever.cpython-312.pyc b/core/media/__pycache__/truth_social_retriever.cpython-312.pyc index 6953118245c88398b8ebadb76d4c876f59a5862c..9cc9fa1030595958df57865b7aa170991bd6132c 100644 GIT binary patch delta 4684 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 delta 1509 zcmX|BT}&KR6uxI>XZC*=c4wE}?LrZRx-46|r8b4u(gtW73XPZ;?GUmVnJMhL%aS{@ zV*jjBUQB8Pj|o0$jW23_Ai?y-r0JVUg+yW#lBrEie6q%b3h}4a#CwO*yP5BvIo~rSEruIB8haj}>Wfm+dvRH;lrJW=+{b)wDeo?R7&hQZpmteQ79U%FLnJS&s$= z@CCW-u4fwa0l_8t$K~tps*u>lW7bivXc~ocRa!7D&8nGH#{IthXe%e>DQ#LW8@5=Z zWt!s}4>io0>a=OtF0)#jvEAkbEzVdb-OE_Yt7c0T&6=1pc{jHc;7Bw0jqe1s;A7v7 zY}PR=7b`_;;zYH^aXI97OHe zDD?1B;+#(}q#p5hSXFvy{o!(j%tOV=!op1|g0kAH}3hdG=< zJz0ee-bo$`KF<`U!CLk<*@$B@)dv08mpTkR%NJ8~Lg&v)VqMv{rtDi+2G^9qTg5xd zi~l^l4E^BE|1|>;8-@+S@$pt2>W!}+8IB0I1F2zIy4`*}&0bbyX*ld%@w>SkX&l)v zt#pM(L}^uwGkG-`8p%nkIf=>CS{{4uD^TJrql`eGrknAx`zJeE9rr6;+K zhdO1jm~4A$)&OJ@Wm>vc@LrgR5g=!2g>|x)03|BfL@E+dpSb{9h zXWPJwH?nP4I=EFI2j|GkOtMAOqK@a6g!19v4#mfva^M4J?qM)THifX%z1dPPDG%FU z0x5s3f0OWiV~P>+C2@n)BY-_7pN$O>0Pc~-d*s-C fa_|=tzDxXfiI-`Za1XEKqTy2l#Qz{1opApH 0: + self.wechat.send_image(media_thumbnail) + else: + contents = [] + contents.append(f"### 川普推文") + contents.append(text) + contents.append(f"### 推文时间") + contents.append(date_time) + mark_down_text = "\n\n".join(contents) + self.wechat.send_markdown(mark_down_text) + except Exception as e: + logger.error(f"发送企业微信消息失败: {e}") + continue + def transform_datetime(self, datetime_text: str): utc_time = datetime.strptime(datetime_text, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=pytz.UTC) diff --git a/core/wechat.py b/core/wechat.py index ac91a4f..14ce006 100644 --- a/core/wechat.py +++ b/core/wechat.py @@ -6,7 +6,9 @@ """ import core.logger as logging import requests - +import base64 +import hashlib +import json logger = logging.logger class Wechat: @@ -25,6 +27,7 @@ class Wechat: "text": {"content": text} } response = requests.post(self.url, json=data) + response.raise_for_status() return response.json() def send_markdown(self, text: str): @@ -36,18 +39,43 @@ class Wechat: "markdown_v2": {"content": text} } response = requests.post(self.url, json=data) + response.raise_for_status() return response.json() def send_image(self, image_url: str): """ 发送图片消息 """ + # data = { + # "msgtype": "image", + # "image": {"url": image_url} + # } + # response = requests.post(self.url, json=data) + # return response.json() + image_bytes = self.download_image(image_url) + base64_str, md5_str = self.get_base64_and_md5(image_bytes) data = { "msgtype": "image", - "image": {"url": image_url} + "image": { + "base64": base64_str, + "md5": md5_str, + } } response = requests.post(self.url, json=data) + response.raise_for_status() return response.json() + + def download_image(self, image_url): + """下载图片并返回 bytes""" + response = requests.get(image_url, timeout=10) + response.raise_for_status() # 抛出 HTTP 错误 + return response.content + + def get_base64_and_md5(self,image_bytes): + """计算 Base64(不带 data: 前缀)和 MD5""" + b64 = base64.b64encode(image_bytes).decode('utf-8') + md5 = hashlib.md5(image_bytes).hexdigest() + return b64, md5 def send_file(self, file_url: str): """ @@ -58,6 +86,7 @@ class Wechat: "file": {"url": file_url} } response = requests.post(self.url, json=data) + response.raise_for_status() return response.json() def send_news(self, news: list): @@ -69,5 +98,6 @@ class Wechat: "news": {"articles": news} } response = requests.post(self.url, json=data) + response.raise_for_status() return response.json() \ No newline at end of file diff --git a/truth_social_retriever_main.py b/truth_social_retriever_main.py index 568d5e2..46ed5f8 100644 --- a/truth_social_retriever_main.py +++ b/truth_social_retriever_main.py @@ -4,6 +4,8 @@ from core.media.truth_social_retriever import TruthSocialRetriever def main(): truth_social_retriever = TruthSocialRetriever() truth_social_retriever.get_user_posts() + # json_file_name = r"./output/media/truth_social/realDonaldTrump/realDonaldTrump_20251021172241.json" + # truth_social_retriever.send_message_by_json_file(json_file_name) if __name__ == "__main__":