any-env-code / news.py
izuemon's picture
Update news.py
4281abb verified
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"<link type=\"url\" value=\"{item['link']}\">"
f"{item['title']}"
f"</link>\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()