0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

arXiv の export API が429を返し続けた — 待っても直らず、RSS なら200で取れた

0
Last updated at Posted at 2026-10-20

はじめに

📝 この記事は note ・ Zenn にも投稿しています。

平日の朝 9:10 に、生成AIまわりの新着を集めるジョブが launchd から動いている。Hugging Face のモデル、GitHub、PyPI、それに arXiv の論文。arXiv の分は export API に次のクエリを投げ、新しい順に6件を取っていた。

https://export.arxiv.org/api/query?search_query=(cat:cs.CV+OR+cat:cs.SD)+AND+(abs:diffusion+OR+abs:generation)&sortBy=submittedDate&sortOrder=descending&max_results=6

2026-09-14、自動ジョブの棚卸しでこのジョブのログを読み返した。ジョブは毎回 exit 0 で終わっている。ところが 9月の10回のうち7回、arXiv の行が arxiv: 0 だった。

09-01  arxiv: 6
09-02  arxiv: 0
09-03  arxiv: 0
09-04  arxiv: 0
09-07  arxiv: 0
09-08  arxiv: 6
09-09  arxiv: 0
09-10  arxiv: 6
09-11  arxiv: 0
09-14  arxiv: 0

取れなかったときの理由は2種類あった。HTTP Error 429 と、読み取りのタイムアウト(20秒)。

WARN fetch failed [http://export.arxiv.org/api/query?search_query=(cat:cs.CV+OR+cat:cs.SD)+AND+(abs]: The read operation timed out

収集の関数は失敗を WARN にとどめて空のリストを返す作りなので、ジョブ全体は「成功」になる。

待っても429

まず、待てば通るかを試した。https に変え、タイムアウトを60秒に延ばし、失敗したら30秒、さらに90秒待ってから叩き直す。

結果は3回とも429。ジョブが走る 9:10 とは別の 13時台に試しても同じだった。

User-Agent も変えた。独自の名前を付けても、curl の既定のままでも429。応答には Retry-After ヘッダーが無く、どれだけ待てばいいかをサーバーは返してこない。応答ヘッダーを見ると前段は Google Frontend と varnish で、制限はその手前でかかっているように見えた。

待てば通る作りではない、と判断した。叩き直すたびに制限を延ばしている可能性もあるので、試す回数はここで止めた。

RSS なら200

arXiv には export API とは別に、カテゴリごとの RSS がある。

curl -s -o /dev/null -w "%{http_code}\n" "https://rss.arxiv.org/rss/cs.CV"
# 200(144件)

429 が続いていたのと同じ時間帯に、200 で144件取れた。カテゴリは + でつなげば1回で取れる。

curl -s "https://rss.arxiv.org/rss/cs.CV+cs.SD" | grep -c "<item>"
# 159(うち cs.SD 17件)

選択肢を2つ出した。「1. arXiv を RSS に切り替える」「2. 再試行のまま様子を見る」。1 が選ばれた。

旧クエリを RSS で再現する

RSS と API は返すものが違う。RSS はその日に発表された分だけで、検索はできない。旧クエリの条件(要約に diffusion か generation を含む・新しい順・6件)は、受け取ったあとで絞って再現した。

RSS の各 <item> には <arxiv:announce_type> が入っていて、値は new / cross / replace / replace-cross の4種類。replace 系は既存論文の改訂なので、新着としては落とす。要約は <description> の中にある。

ARXIV_CATEGORIES = ["cs.CV", "cs.SD"]
ARXIV_MAX = 6
ARXIV_KEYWORDS = re.compile(r"diffusion|generation", re.I)  # 旧 API クエリと同条件

def fetch_arxiv() -> list[dict]:
    url = "https://rss.arxiv.org/rss/" + "+".join(ARXIV_CATEGORIES)
    raw = fetch(url, timeout=60, accept="application/rss+xml")
    items = []
    for e in re.findall(r"<item>(.*?)</item>", raw, re.S):
        tm = re.search(r"<title>(.*?)</title>", e, re.S)
        im = re.search(r"<link>(.*?)</link>", e, re.S)
        dm = re.search(r"<description>(.*?)</description>", e, re.S)
        if not tm or not im:
            continue
        # replace / replace-cross は既存論文の改訂なので新着として扱わない
        at = re.search(r"<arxiv:announce_type>(.*?)</arxiv:announce_type>", e)
        if at and at.group(1).strip() not in ("new", "cross"):
            continue
        if not ARXIV_KEYWORDS.search(dm.group(1) if dm else ""):
            continue
        title = re.sub(r"\s+", " ", html.unescape(tm.group(1))).strip()
        items.append({"title": title, "url": im.group(1).strip()})
    return items[:ARXIV_MAX]

実際のコードは待機つきの再試行と、取得が0件だった日に WARN 収集元0件: arxiv を1行出す処理を残している。ここでは絞り込みの部分だけを載せた。タイトルには &amp; のような実体参照が入るので html.unescape で戻している。

切り替えた日の確認はこう。

確かめたこと 結果
本物の RSS から取る 0.1秒で6件
保存した159件のサンプルで絞る 上限の6件に収まり、replace の混入は0
取得を空にして通しで回す WARN 収集元0件: arxiv が出る

切り替えたあとの4週間

翌日 09-15 から 10-09 までのログを並べた。

09-15 6   09-16 6   09-17 6   09-18 6
09-21 0   09-22 6   09-23 6   09-24 6   09-25 6
09-28 0   09-29 6   09-30 6   10-01 6   10-02 6
10-05 0   10-06 6   10-07 6   10-08 6   10-09 6

429 は1回も出ていない。そのかわり、0 が3回ある。09-21、09-28、10-05。3日とも月曜だった。

RSS の先頭には <skipDays> があり、土曜と日曜が入っている。arXiv は週末に発表しない。切り替えたときの記録にも「土日は発表が無い。平日のジョブなら問題ない」と書いていた。

月曜の朝に RSS を1回だけ取ってみた。

$ date
Mon Oct 12 05:58:44 JST 2026
$ curl -s "https://rss.arxiv.org/rss/cs.CV+cs.SD" | grep -c "<item>"
0
<lastBuildDate>Sun, 11 Oct 2026 20:58:44 +0000</lastBuildDate>
<pubDate>Sun, 11 Oct 2026 00:00:00 -0400</pubDate>
<skipDays>
  <day>Sunday</day>
  <day>Saturday</day>
</skipDays>

日本は月曜でも、RSS の日付はまだ日曜(米東部時間)だった。ジョブの 9:10 も、米東部では日曜の 20:10 にあたる。平日だけ動くジョブにしたのに、月曜の回は相手側の日曜を読んでいた。0件の警告はそのたびに出ていて、ログには3回とも WARN 収集元0件: arxiv が残っている。

10-12 の時点で、コードは月曜を特別扱いしていない。


待てば通ると思って、待ち時間を延ばしていた。止まっていた理由が向こうの制限なら、こちらがどれだけ待っても同じだった。曜日も同じで、こちらの平日が向こうの平日とは限らなかった。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?