any-env-code / news.py
izuemon's picture
Create news.py
c382cb0 verified
import os
import time
import json
import requests
import hashlib
from datetime import datetime, timezone
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/"
# ===== 設定 =====
INTERVAL_SECONDS = 60 * 60 * 12 # 12時間
SENT_LOG_FILE = "sent_nippon_news.json"
# ===== 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 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()
# CDATA 内のHTMLをテキスト化
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 main():
sent_log = load_sent_log()
while True:
try:
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("新しいニュースはありません")
except Exception as e:
print("エラー:", e)
time.sleep(INTERVAL_SECONDS)
if __name__ == "__main__":
main()