mcpField
P
paper-fetch

paper-fetch

github.com/agents365-ai生産性973.4k 回インストール2 週間前に更新
リポジトリ

paper-fetch について

paper-fetchは、DOIまたは論文タイトルからPDFを探してダウンロードするコマンドラインツールです。文献取得の自動化向けに、優先順で複数の取得元を試し、バッチ入力、JSON出力、エージェント向けのCLIスキーマに対応します。

主な機能

  1. 01DOIまたはタイトルからPDF取得
  2. 02複数の取得元を順に試行
  3. 03DOIの一括ダウンロード
  4. 04JSON結果と進捗イベントの出力
  5. 05機械可読なCLIスキーマ

活用シーン

  1. 01DOIを指定して論文をダウンロード
  2. 02タイトルから論文を解決して取得
  3. 03DOIリストを一括処理
  4. 04自動化処理で取得結果を読み込む

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/agents365-ai/365-skills --skill paper-fetch

インストール後、Claude Code で/paper-fetchを入力して読み込まれたか確認します。

同梱ファイルscripts/cloak_pdf.pyscripts/fetch.py

詳細

paper-fetch

DOI(またはタイトル)を指定して論文の PDF を取得します。優先順位に従って複数のソースを試し、最初に見つかった時点で停止します。

解決の優先順位

  1. Unpaywall — https://api.unpaywall.org/v2/{doi}?email=$UNPAYWALL_EMAIL を呼び出し、best_oa_location.url_for_pdf を読み取ります(UNPAYWALL_EMAIL が設定されていない場合はスキップします)。
  2. Semantic Scholar — https://api.semanticscholar.org/graph/v1/paper/DOI:{doi}?fields=openAccessPdf,externalIds
  3. arXiv — externalIds.ArXiv が存在する場合、https://arxiv.org/pdf/{arxiv_id}.pdf
  4. PubMed Central OA — PMCID が存在する場合、https://www.ncbi.nlm.nih.gov/pmc/articles/{pmcid}/pdf/
  5. bioRxiv / medRxiv — DOI のプレフィックスが 10.1101 の場合、https://api.biorxiv.org/details/{server}/{doi} を呼び出して最新バージョンの PDF URL を取得します。
  6. 出版社から直接取得(機関モードのみ — PAPER_FETCH_INSTITUTIONAL=1)— DOI プレフィックスから出版社の PDF テンプレートを適用します(Nature / Science / Wiley / Springer / ACS / PNAS / NEJM / Sage / T&F / Elsevier)。取得を許可するのは呼び出し元自身の購読 IP / Cookie / EZproxy です。許可されていない応答は %PDF チェックに失敗し、ステップ 7 に進みます。
  7. Sci-Hub ミラー(デフォルトで有効。無効にするには PAPER_FETCH_NO_SCIHUB=1 を指定)— 最後の手段となるフォールバックです。PAPER_FETCH_SCIHUB_MIRRORS に指定されたミラー(または組み込みのデフォルト sci-hub.ru、sci-hub.st、sci-hub.su、sci-hub.box、sci-hub.red、sci-hub.al、sci-hub.mk、sci-hub.ee)を順に試します。すべて失敗した場合は、プロセスごとに 1 回だけ https://www.sci-hub.pub/ をスクレイピングして新しいミラーを取得します。CAPTCHA / 論文が見つからないページには PDF の iframe がないため、通知なしで次に進みます。
  8. それ以外の場合 → タイトルと著者を添えて失敗を報告し、ユーザーが ILL で依頼できるようにします。

CloakBrowser によるフォールバック(ダウンロード層、オプトイン — PAPER_FETCH_CLOAK=1)。 これは独立した取得元ではなく、ダウンロードのボトルネックに適用されるため、上記の取得元すべてに適用されます。解決された PDF URL が Cloudflare にブロックされた場合(HTTP 403/429、またはファイルの代わりに「Just a moment…」という HTML のインタースティシャルが返される場合)、オペレーターがオプトインしていれば、cloak_pdf.py コンパニオンを介して CloakBrowser(JS チャレンジを通過できるステルス Chromium)経由で URL を再試行します。返されたバイト列は、同じ %PDF マジックバイトと 50 MB のチェックで再検証されます。成功すると、結果には via: "cloak" が含まれます。デフォルトでは無効で、フェイルクローズドです(CloakBrowser がない場合は通知なしで次に進みます)。エージェントはオプトインできません。下記の CloakBrowser access を参照してください。

タイトルだけが指定された場合は、--title "<title>" で直接渡します。解決チェーンは次のとおりです。

  1. Crossref query.title — 優先。主要なジャーナルや学会の DOI を網羅します。
  2. Semantic Scholar /paper/search/match — Crossref の最上位候補の信頼度が低い(match_score < 40)場合、または次点候補との差が < 3 の場合のフォールバックです。特に重要なのは、S2 が arXiv のみのプレプリント(Crossref DOI なし)も扱うことです。S2 で arXiv ID のみを持つ論文が見つかった場合は、正規の 10.48550/arXiv.<id> を生成し、ダウンロードチェーンを統一します。
  3. Crossref の最有力候補(信頼度低) — 両方の解決サービスでうまく解決できなかった場合にのみ使用します。結果のエンベロープでは、meta.title_resolution.low_confidence: true と low_confidence_reason(score_below_threshold / ambiguous_runner_up)が設定されます。これにより、エージェントは処理を中断するか、--dry-run で確認できます。

いずれの場合も、解決された DOI、採用された解決サービス、完全な resolvers_tried リスト、および最上位候補との一致状況が meta.title_resolution に表示されます。

semanticscholar-skill が登録されている場合は、タイトルから DOI への解決に、より充実した前段階の処理として利用できます。単に DOI が必要なだけでなく、関連度のランキング、スニペット検索、引用のコンテキストも必要な場合に便利です。エージェントは、このスキルの match_title() を使って externalIds.DOI を読み取る Python スクリプトを作成し、その後 paper-fetch <doi> を実行します。結果に ArXiv ID のみが含まれ、DOI がない場合は、10.48550/arXiv.<ArXiv> を生成して paper-fetch に渡します。

DOI だけが必要な場合は、--title が単一コマンドで実行する方法です。paper-fetch に組み込まれた Crossref → S2 チェーンが、ほとんどのケースに対応します。

使い方

python scripts/fetch.py <DOI> [options]
python scripts/fetch.py --title "<paper title>" [options]
python scripts/fetch.py --batch <FILE|-> [options]
python scripts/fetch.py schema           # machine-readable self-description
フラグ

通常の使用時にエージェントが構成するフラグは以下のとおりです。--dry-run、--pretty、--stream、--overwrite、--timeout、--version、パラメーターの型、終了コードの対応関係を含む完全な仕様を確認するには、python scripts/fetch.py schema を実行してください(機械可読で、schema_version によるドリフトチェックに対応しています)。

フラグデフォルト説明
doi—取得する DOI(位置引数)。標準入力から単一の DOI を読み取るには - を使用します
--title TITLE—論文のタイトル。ダウンロード前に Crossref で DOI に解決します。位置引数の DOI/--batch とは併用できません
--batch FILE—一括ダウンロード用の、1 行につき 1 つの DOI を記載したファイル。標準入力から読み取るには - を使用します
--out DIRpdfs出力ディレクトリ
--format自動エージェント向けの json、人間向けの text。自動判定では、stdout が TTY でない場合は json、TTY の場合は text を使用します
--idempotency-key KEY—安全な再試行用のキー。同じキーで再実行すると、ネットワーク I/O を行わずに <out>/.paper-fetch-idem/ から元のエンベロープを再生します
エージェントによる検出:schema サブコマンド
python scripts/fetch.py schema

ネットワークアクセスなしで、CLI の完全な機械可読の説明を stdout に出力します。cli_version、schema_version、パラメーターの型、終了コード、エラーコード、エンベロープの形式、環境変数が含まれます。エージェントはこれを一度読み取って schema_version と照合してキャッシュし、キャッシュしたバージョンにドリフトがあった場合に再読み込みする必要があります。

出力仕様

stdout には、単一の JSON エンベロープが出力されます。すべてのエンベロープには meta スロットが含まれます。

成功(すべての DOI を解決):

{
  "ok": true,
  "data": {
    "results": [
      {
        "doi": "10.1038/s41586-021-03819-2",
        "success": true,
        "source": "unpaywall",
        "pdf_url": "https://www.nature.com/articles/s41586-021-03819-2.pdf",
        "file": "pdfs/Jumper_2021_Highly_accurate_protein_structure_predic.pdf",
        "meta": {"title": "Highly accurate protein structure prediction with AlphaFold", "year": 2021, "author": "Jumper"},
        "sources_tried": ["unpaywall"]
      }
    ],
    "summary": {"total": 1, "succeeded": 1, "failed": 0},
    "next": []
  },
  "meta": {
    "request_id": "req_a908f5156fc1",
    "latency_ms": 2036,
    "schema_version": "1.9.0",
    "cli_version": "0.13.1",
    "sources_tried": ["unpaywall"]
  }
}

一部成功(バッチモード — 一部の DOI が失敗し、終了コードは失敗の種類を反映します):

{
  "ok": "partial",
  "data": {
    "results": [
      { "doi": "10.1038/s41586-021-03819-2", "success": true, "source": "unpaywall", ... },
      {
        "doi": "10.1234/nonexistent",
        "success": false,
        "source": null,
        "pdf_url": null,
        "file": null,
        "meta": {},
        "sources_tried": ["unpaywall", "semantic_scholar"],
        "error": {
          "code": "not_found",
          "message": "No open-access PDF found",
          "retryable": true,
          "retry_after_hours": 168,
          "reason": "OA availability changes over time; retry after embargo lifts or preprint appears"
        }
      }
    ],
    "summary": {"total": 2, "succeeded": 1, "failed": 1},
    "next": ["paper-fetch 10.1234/nonexistent --out pdfs"]
  },
  "meta": { ... }
}

next スロットは、推奨される後続コマンドの配列です。これらのコマンドを再実行すると、失敗した項目のみが再試行されます。--idempotency-key と組み合わせると、すでに成功した項目を再ダウンロードせずにバッチ全体を安全に再試行できます。

失敗(引数が不正、終了コード 3):

{
  "ok": false,
  "error": {
    "code": "validation_error",
    "message": "Provide a DOI or --batch file",
    "retryable": false
  },
  "meta": { ... }
}

項目単位のスキップ(保存先がすでに存在し、--overwrite が指定されていない):

{
  "doi": "10.1038/s41586-021-03819-2",
  "success": true,
  "source": "unpaywall",
  "pdf_url": "https://...",
  "file": "pdfs/Jumper_2021_...pdf",
  "skipped": true,
  "skip_reason": "file_exists",
  "sources_tried": ["unpaywall"]
}

冪等性キーによる再生(同じ --idempotency-key を指定して再実行):

キャッシュされたエンベロープがそのまま返されますが、現在の呼び出しに合わせて meta.request_id と meta.latency_ms が再設定され、meta.replayed_from_idempotency_key が設定されます。ネットワーク I/O は発生しません。

stderr の進捗(NDJSON)

--format json の場合、stderr には稼働状況を示す JSON オブジェクトが 1 行につき 1 つ出力されます。

{"event": "session",     "request_id": "req_...", "elapsed_ms": 0,    "cli_version": "0.13.1", "schema_version": "1.9.0"}
{"event": "start",       "request_id": "req_...", "elapsed_ms": 2,    "doi": "10.1038/..."}
{"event": "source_try",  "request_id": "req_...", "elapsed_ms": 2,    "doi": "...", "source": "unpaywall"}
{"event": "source_hit",  "request_id": "req_...", "elapsed_ms": 2036, "doi": "...", "source": "unpaywall", "pdf_url": "..."}
{"event": "download_ok", "request_id": "req_...", "elapsed_ms": 4120, "doi": "...", "file": "..."}

イベントの種類:session、start、source_try、source_hit、source_miss、source_skip、source_enrich、source_enrich_failed、download_ok、download_error、download_skip、dry_run、not_found、resolve_error。すべてのイベントには request_id と elapsed_ms が含まれるため、オーケストレーターは stderr の進捗状況と最終的な stdout エンベロープを関連付けられます。session イベントは各呼び出しにつき一度だけ、DOI の処理やネットワーク I/O より前に発生します。また、cli_version/schema_version が含まれるため、エージェントは最終エンベロープを待たずにキャッシュしたコピーとの照合でスキーマのドリフトを検出できます。

Semantic Scholar が、別のソースからすでに提供された PDF URL に対して、欠落している author/title の補完のみを目的に呼び出された場合、source_enrich が発生します。その fields 配列には、補完されたフィールドのみが正確に列挙されます。その補完呼び出しが失敗した場合は source_enrich_failed が発生します。その場合も Unpaywall の PDF URL が使用され、ファイル名は unknown_<year>_… にフォールバックします。

--format text の場合、stderr には人間が読める形式のテキストが出力されます。

終了コード
コード意味再試行可能な分類
0すべての DOI を解決/プレビューしました—
1未解決 — 1 つ以上の DOI に OA コピーがなく、トランスポート障害もありません今は再試行しない(retry_after_hours 経過後に再試行)
2認証エラー用に予約(現在は未使用)—
3検証エラー(引数が不正、入力が不足)いいえ
4トランスポートエラー(ネットワーク/ダウンロード/IO 障害)はい

この分類体系により、オーケストレーターは失敗を確実に振り分けられます。終了コード 4 はすぐに再試行する価値があり、終了コード 1 は再試行せず、終了コード 3 は呼び出し側のバグです。

JSON のエラーコード

再試行可能なエラーにはすべて、エラーオブジェクトに retry_after_hours のヒントが含まれているため、オーケストレーターは推測せずに再試行をスケジュールできます。

コード意味再試行可能retry_after_hours
validation_error引数が不正、または入力が空ですいいえ—
title_resolve_failed指定された --title クエリに対して Crossref から項目が返されませんでした(より長く、整理されたタイトルを試すか、DOI を直接指定してください)いいえ—
not_foundオープンアクセスの PDF が見つかりませんでしたはい168(1 週間 — OA が利用可能になるまでの期間は、エンバーゴ/プレプリントのタイムスケールに相当します)
resolve_network_errorメタデータ解決サービスでトランスポートエラー(タイムアウト/5xx/403)が発生しました。OA の利用可否は不明です。not_found として扱わず、再試行してください。終了コード 4 に対応します。はい1
download_network_errorダウンロード中にネットワーク障害が発生しましたはい1
download_not_a_pdfPDF ではない応答でした(HTML のランディングページ)いいえ—
download_host_not_allowedPDF URL が SSRF 安全性チェックに失敗しました(プライベート IP/非 http(s)/80、443 以外/ブロック対象のメタデータホスト/プライベート空間に解決されるホスト名/安全でないリダイレクト先)いいえ—
download_size_exceeded応答が 50 MB の上限を超えましたはい24
download_io_errorローカルファイルシステムへの書き込みに失敗しましたはい1
internal_error予期しないエラーですいいえ—

正式なマッピングは scripts/fetch.py の RETRY_AFTER_HOURS にあり、schema.error_codes で公開されています。

例
# Single DOI (JSON output when piped; text when in a terminal)
python scripts/fetch.py 10.1038/s41586-020-2649-2

# Single title (resolved to DOI via Crossref, then downloaded)
python scripts/fetch.py --title "Highly accurate protein structure prediction with AlphaFold"

# Dry-run preview (resolve without downloading)
python scripts/fetch.py 10.1038/s41586-020-2649-2 --dry-run

# Title + dry-run — preview the resolved DOI and candidate matches
python scripts/fetch.py --title "Attention Is All You Need" --dry-run

# Force JSON (for agents even inside a terminal)
python scripts/fetch.py 10.1038/s41586-020-2649-2 --format json

# Human-readable with pretty colors in a pipeline
python scripts/fetch.py 10.1038/s41586-020-2649-2 --format text

# Batch download, safely retriable
python scripts/fetch.py --batch dois.txt --out ./papers \
    --idempotency-key monday-review-batch

# Pipe DOIs from another tool
zot -F ids.json query ... | jq -r '.[].doi' | python scripts/fetch.py --batch -

# Agent discovery
python scripts/fetch.py schema --pretty

# Streaming mode — one result per line as each DOI resolves
python scripts/fetch.py --batch dois.txt --stream

# Works without UNPAYWALL_EMAIL (skips Unpaywall, uses remaining 4 sources)
python scripts/fetch.py 10.1038/s41586-020-2649-2

環境

変数デフォルト目的
UNPAYWALL_EMAIL未設定Unpaywall API 用の連絡先メールアドレスです。任意ですが、設定を推奨します。設定しない場合、Unpaywall はスキップされます(ほかのソースは引き続き利用できます)。
PAPER_FETCH_INSTITUTIONAL未設定任意の値(例:1)を設定すると、機関モードが有効になり、1 req/s のレート制限と出版社への直接フォールバックが有効になります。詳しくは以下を参照してください。
PAPER_FETCH_NO_SCIHUB未設定任意の値を設定すると、Sci-Hub へのフォールバック(ステップ 7)が無効になります。
PAPER_FETCH_SCIHUB_MIRRORS未設定優先順位順に試すミラーホスト名をカンマ区切りで指定します(例:sci-hub.ru,sci-hub.st,sci-hub.su)。組み込みのデフォルト設定を上書きします。
PAPER_FETCH_CLOAK未設定任意の値を設定すると、CloakBrowser フォールバックが有効になります。Cloudflare にブロックされた PDF(HTTP 403/429、または PDF ではないインタースティシャル)は、ステルス Chromium 経由で再試行されます。以下の CloakBrowser へのアクセス を参照してください。
CLOAKBROWSER_PYTHON自動cloakbrowser を import できる Python のパスです。cloak フォールバックで使用されます。自動検出の順序:この変数 → ~/github/CloakBrowser/.venv/bin/python → 現在のインタープリター。
PAPER_FETCH_CLOAK_HEADED未設定任意の値を設定すると、ヘッドレスではなく、画面に表示される ヘッド付きブラウザーを起動します。より難しい Cloudflare チャレンジ(例:science.org)ではヘッドレスモードが失敗し、実ウィンドウでのみ解除できることがあります。cloak フォールバックで HTTP 403/「Just a moment…」が返され続ける場合に設定してください。ディスプレイが必要です。

CloakBrowser によるアクセス(オプトイン)

一部の出版社(例:science.org)は Cloudflare の背後にあり、通常の HTTP クライアントに PDF ではなく 403/429 や「Just a moment…」という JavaScript チャレンジページを返します。そのため、ブラウザーからは正当にアクセスできる URL でも、デフォルトの urllib によるダウンロードでは取得できません。CloakBrowser は、こうしたチャレンジを通過できるステルス Chromium です。このスキルは cloakFetch のアプローチを取り入れています。

オプトイン: export PAPER_FETCH_CLOAK=1 を設定します(さらに、cloakbrowser をインポートできる Python が必要です。CLOAKBROWSER_PYTHON を参照してください)。

仕組み: フォールバックは新しい取得元としてではなく、ダウンロード層に組み込まれています。そのため、解決済みの URL(Unpaywall、出版社の直接配信、Sci-Hub など)すべてに適用されます。Cloudflare によってブロックされると、fetch.py は解決済みの Python を使って cloak_pdf.py コンパニオンを起動します。CloakBrowser は PDF ホストのオリジンを読み込んで JavaScript チャレンジを解決し、その後、ページ内の fetch() で PDF を取得します(これにより、ブラウザー本来のフィンガープリントと cf_clearance Cookie を伴うリクエストになります)。そして、バイト列を標準出力に返します。fetch.py 自体は標準ライブラリーのみを使用し、cloakbrowser をインポートすることはありません。

ヘッドレスとヘッド付き。 コンパニオンはデフォルトでヘッドレス実行されます。一部のチャレンジ(例:science.org)はヘッドレス Chromium では突破できず、「Just a moment…」のままになるため、PAPER_FETCH_CLOAK_HEADED=1 を設定してウィンドウを表示すると解決できます。確認済みの例:通常のクライアントでは 403 が返される www.science.org/doi/pdf/… の PDF を、ヘッド付きの Cloak フォールバック経由で正常にダウンロードできます。

同一オリジンのみ。 ページ内の fetch は同一オリジンで実行されるため、解決済み URL がブロックされたホスト上の PDF への直接リンクである場合(例:www.science.org/doi/pdf/…)にフォールバックが機能します。クロスオリジンにリダイレクトされる URL(例:単体の doi.org/… リンク)や、チャレンジが解決されない旧式のホストでは、フェイルクローズして次の取得元に移ります。

変更されない点:

  • 返されたバイト列は、同じ %PDF マジックバイト検査と 50 MB のサイズ上限で再検証されます。ブラウザーを起動する前に URL を検査する SSRF 防御も引き続き適用されます。
  • CAPTCHA は解決しません。 CloakBrowser が突破するのは自動化された JavaScript チャレンジであり、インタラクティブなチャレンジではありません。インタラクティブな Turnstile では引き続きフェイルクローズし、次の取得元に移ります。
  • フェイルクローズします。 cloakbrowser をインポートできる Python がない、ヘルパーが見つからない、またはエラーが発生した場合は、何も通知せず次の取得元に移ります。ブロックされた取得に成功したとエージェントに伝えることはありません。
  • エージェント自身ではオプトインできません。PAPER_FETCH_CLOAK は人間のオペレーターが設定する必要があります。機関モードと同じ信頼境界です。
  • 成功すると、結果ごとのオブジェクトに via: "cloak" が含まれ、オーケストレーターはフォールバックが使用されたことを確認できます。

コスト: フォールバックが発動すると、実際のブラウザーが起動します(約 20〜40 秒、初回ダウンロード時は Chromium が約 200 MB)。通常のダウンロードがブロックされた後にのみ発動するため、通常の成功パスには影響しません。

機関認証によるアクセス(オプトイン)

多くの研究者は、所属機関の IP 範囲(キャンパス内または VPN 経由)を通じて、正規のサブスクリプションアクセス権を利用しています。Paper-fetch は、PDF を提供するかどうかを出版社独自の認証(お使いの IP、セッション Cookie)に判断させることで、そのアクセスを利用できます。

モードによってホストへの到達性が変わることはありません。パブリックモードでも、OA API(Unpaywall、Semantic Scholar、bioRxiv、PMC)が返す URL をすでに信頼しており、SSRF 防御を通過した HTTPS ホストであれば取得します。機関モードでは、次の 2 つが追加されます。(1)すべての OA ソースで見つからなかった場合に、DOI のプレフィックスをもとに出版社側の PDF URL を組み立てる出版社への直接フォールバック(上記のステップ 6)。これにより、機関の IP/Cookie を使って取得を認証できます。(2)バッチジョブによって IP がスロットリングされたり、「体系的なダウンロード」を理由にアクセス禁止になったりしないようにする、1 秒あたり 1 リクエストのレートリミッター。

オプトインするには: export PAPER_FETCH_INSTITUTIONAL=1

機関モードでの変更点:

項目パブリック(デフォルト)機関
ホストへの到達性SSRF 防御を通過した、あらゆる公開 HTTPS ホスト同じ
SSRF 防御適用(プライベート IP/非 HTTP(S)/80・443 以外/クラウドメタデータをすべてブロック)適用 — 同じルール
出版社への直接フォールバックオフオン — DOI プレフィックスから出版社の PDF URL を構築し、すべての OA ソースで見つからなかった場合の最終手段として使用
レート制限なし1 秒あたり 1 リクエストのトークンバケット(すべての送信リクエストが対象)
meta.auth_mode"public""institutional"

変わらない点:

  • %PDF のマジックバイトチェックと 50 MB のサイズ上限(HTML のランディングページやサイズ超過のレスポンスが通過するのを防止します)
  • CAPTCHA の解除は一切行いません。出版社がチャレンジを表示した場合、レスポンスは %PDF で始まらないため、paper-fetch は次のソースに進みます。
  • 機関モード自体では、ブラウザー自動化、Playwright、ステルス機能を使用しません。出版社への直接 URL に対する通常の HTTP 取得です。(ブラウザー自動化は別途オプトインする機能で、上記の CloakBrowser フォールバックを PAPER_FETCH_CLOAK で有効にします。)
  • エージェント自身ではオプトインできません。PAPER_FETCH_INSTITUTIONAL は、シェル環境で人間の運用担当者が設定する必要があります。これが信頼境界です。

パブリックモードで paper-fetch が OA 版を見つけられなかった場合、エラーエンベロープには suggest_institutional: true が含まれ、環境変数を設定するようユーザーに案内するヒントが表示されます。エージェントは、何も通知せずに失敗するのではなく、この内容をそのまま表示できます。

利用規約に関する注意: ほぼすべての出版社のサブスクリプションでは、「体系的なダウンロード」が禁止されています。1 秒あたり 1 リクエストのレート制限と既存のファイルごとの冪等性は、個人の研究利用が許容範囲内に収まるように設計されています。paper-fetch プロセスを多数並行して実行したり、レート制限を解除したりすると、出版社による機関全体への IP 禁止措置を招く可能性があります。絶対に行わないでください。

注意事項

  • 認証は委任されます。 エージェントがログイン用サブコマンドを実行することはありません。人間またはオーケストレーターが環境内で UNPAYWALL_EMAIL を設定し、エージェントはそれを引き継ぎます。メールアドレスが設定されていない場合は、残りの 4 つのソースに自動的に切り替わります。
  • 信頼の適用方向は決まっています。 CLI 引数はエントリーポイントで一度だけ検証されます。SSRF 防御、%PDF のマジックバイトチェック、50 MB のサイズ上限は、エージェントのリクエスト時ではなく環境レイヤーで適用されます。エージェントがフラグを渡して安全性を緩めることはできません。機関モード(およびそのレート制限に伴うリスクプロファイル)のオプトインは、環境変数を使って運用担当者が行います。
  • ダウンロードは自然に冪等になります。 同じ --out を指定して再実行すると、すでに存在するファイルはスキップされます(決定的なファイル名:{first_author}_{year}_{journal_abbrev}_{short_title}.pdf。メタデータにジャーナル/開催地がない場合は、ジャーナルの部分が省略されます)。--idempotency-key を併用すると、ネットワーク I/O を一切行わずに、同一のエンベロープを再現できます。
  • デフォルトの出力ディレクトリ: ./pdfs/

コメント