📖

arXivの気になるカテゴリの最新の論文をdiscordに共有する

2024/10/05に公開

はじめに

新しい技術を追っていると高頻度でarXivの論文を見ていることがあります。XのTLに流れてきているものを見ていますが、探すのも大変なのでDiscordに送ってしまおうと思いました

Demo

今は以下の画像のように WebHookを使って定期的に共有しています。

arXivから情報を取得

以下のコードにて、カテゴリを コンピューターサイエンス に限定して5時間以内に更新されたものを取得します

import urllib.parse
import feedparser
from datetime import datetime, timedelta
import requests  # Discordへの送信に使用
import os
import time

# DiscordのWebhook URLを環境変数から取得
WEBHOOK_URL = os.environ.get('DISCORD_WEBHOOK_URL')

if not WEBHOOK_URL:
    print('Error: DISCORD_WEBHOOK_URL is not set.')
    exit(1)

# 現在のUTC時刻を取得
now = datetime.utcnow()

# 3時間前のUTC時刻を取得
time_threshold = now - timedelta(hours=5)

# 検索クエリを定義
# Computer Scienceのカテゴリを指定
query = 'cat:cs.*'

# ベースとなるAPIのURL
base_url = 'http://export.arxiv.org/api/query?'

# APIパラメータの設定
params = {
    'search_query': query,
    'start': 0,                   # 取得開始位置
    'max_results': 300,           # 取得する結果の最大数(必要に応じて増やしてください)
    'sortBy': 'submittedDate',    # 提出日の新しい順にソート
    'sortOrder': 'descending',
}

# パラメータをURLエンコードしてクエリ文字列を作成
query_string = urllib.parse.urlencode(params, safe=':')

# 完全なAPIリクエストURLを構築
url = base_url + query_string

# フィードをパース
feed = feedparser.parse(url)

# Discordに送信した論文の数をカウント
paper_count = 0

# 各論文について、3時間以内に公開されたものをフィルタリングして情報を表示
for entry in feed.entries:
    # 'published' フィールドの日付を解析
    published_str = entry.published
    published = datetime.strptime(published_str, '%Y-%m-%dT%H:%M:%SZ')
    
    # 'published' が3時間以内かを確認
    if published >= time_threshold:
        title = entry.title
        summary = entry.summary.replace('\n', ' ')  # 改行を削除して整形
        paper_id = entry.id.split('/abs/')[-1]
        pdf_url = ''
        for link in entry.links:
            if 'title' in link and link.title == 'pdf':
                pdf_url = link.href
                break
        categories = ', '.join(tag['term'] for tag in entry.tags)
        
        # 論文情報をフォーマット
        message_content = f"""**タイトル:** {title}
**Summary:** {summary}
**PDFのURL:** {pdf_url}
**カテゴリー:** {categories}"""

        # Discordに送信するペイロードを作成
        payload = {
            'content': message_content
        }

        # DiscordのWebhookにPOSTリクエストを送信
        response = requests.post(DISCORD_WEBHOOK_URL, data=payload)

        if response.status_code != 204:
            print(f'Failed to send message for paper ID {paper_id}. Status code: {response.status_code}')
        else:
            print(f'Sent paper ID {paper_id} to Discord.')
            paper_count += 1
        time.sleep(3)  # 連続して送信しないように3秒待機

# 処理が完了したことを表示
print(f'Total {paper_count} papers sent to Discord.')

定期実行するためにActionsの設定

定期的にスクリプトを実行するための選択はいろいろありますが、簡単なものとしてGitHub Actionsがあるので今回はこちらを使用します。
以下のようにymlを定義して3時間ごとに実行します(2時間ほど差分があるのは、GitHub Actionsがきっちり同じ時間に実行されなかったときの予備時間です)

name: Fetch arXiv Papers

on:
  schedule:
    - cron: '0 */3 * * *'  # 3時間ごとに実行
  workflow_dispatch:       # 手動実行も可能にする
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
        - uses: actions/checkout@v4
  
        - name: Install uv
          uses: astral-sh/setup-uv@v3
          with:
            enable-cache: true
  
        - name: Set up Python
          run: uv python install
  
        - name: Install the project
          run: uv sync --all-extras --dev
  
        - name: Run fetch_arxiv_papers.py
          env:
            DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
          run: uv run fetch_arxiv_papers.py
MidraLab(ミドラボ)

Discussion