import os import time import json import requests import hashlib from datetime import datetime from bs4 import BeautifulSoup import xml.etree.ElementTree as ET # ===== Channel.io 設定 ===== CHANNEL_ID = "200605" GROUP_ID = "534457" POST_URL = f"https://desk-api.channel.io/desk/channels/{CHANNEL_ID}/groups/{GROUP_ID}/messages" X_ACCOUNT = os.getenv("channeliotokenbot2") if not X_ACCOUNT: raise RuntimeError("環境変数 channeliotokenbot2 が設定されていません") HEADERS_POST = { "accept": "application/json", "accept-language": "ja", "content-type": "application/json", "x-account": X_ACCOUNT, } # ===== RSS ===== RSS_URL = "https://www.nippon.com/ja/rss-all/" # ===== 設定 ===== SENT_LOG_FILE = "sent_nippon_news.json" LAST_RUN_FILE = "last_run.json" TARGET_TIMES = {"06:30", "18:30"} # 朝・夕方 # ===== Utils ===== def load_sent_log(): if not os.path.exists(SENT_LOG_FILE): return set() with open(SENT_LOG_FILE, "r", encoding="utf-8") as f: return set(json.load(f)) def save_sent_log(sent_set): with open(SENT_LOG_FILE, "w", encoding="utf-8") as f: json.dump(list(sent_set), f, ensure_ascii=False, indent=2) def load_last_run(): if not os.path.exists(LAST_RUN_FILE): return "" with open(LAST_RUN_FILE, "r", encoding="utf-8") as f: return json.load(f).get("last_run", "") def save_last_run(value): with open(LAST_RUN_FILE, "w", encoding="utf-8") as f: json.dump({"last_run": value}, f) def hash_link(link: str) -> str: return hashlib.sha256(link.encode("utf-8")).hexdigest() def send_to_channel(text): payload = { "requestId": f"desk-web-{int(time.time() * 1000)}", "blocks": [ {"type": "text", "value": text} ], } res = requests.post( POST_URL, headers=HEADERS_POST, data=json.dumps(payload), timeout=30 ) res.raise_for_status() def fetch_rss_items(): res = requests.get(RSS_URL, timeout=30) res.raise_for_status() root = ET.fromstring(res.content) channel = root.find("channel") if channel is None: return [] items = [] for item in channel.findall("item"): title = item.findtext("title", "").strip() link = item.findtext("link", "").strip() description_raw = item.findtext("description", "").strip() soup = BeautifulSoup(description_raw, "lxml") description = soup.get_text(strip=True) if title and link: items.append({ "title": title, "link": link, "description": description, }) return items # ===== Main ===== def run_job(): sent_log = load_sent_log() items = fetch_rss_items() new_count = 0 for item in items: link_hash = hash_link(item["link"]) if link_hash in sent_log: continue message = ( f"" f"{item['title']}" f"\n\n" f"{item['description']}" ) send_to_channel(message) sent_log.add(link_hash) new_count += 1 time.sleep(1) if new_count > 0: save_sent_log(sent_log) print(f"{new_count} 件のニュースを送信しました") else: print("新しいニュースはありません") def main(): last_run = load_last_run() while True: now = datetime.now() now_key = now.strftime("%Y-%m-%d %H:%M") now_time = now.strftime("%H:%M") if now_time in TARGET_TIMES and last_run != now_key: print(f"{now_time} 実行開始") try: run_job() save_last_run(now_key) except Exception as e: print("エラー:", e) time.sleep(60) # 1分ごとにチェック if __name__ == "__main__": main()