mcpField
P
paper-fetch

paper-fetch

github.com/agents365-ai生産性116 回インストール
リポジトリ

paper-fetch について

DOI またはタイトルから論文を特定し、複数のソースを順に試して PDF を取得するコマンドラインスキルです。バッチ処理とエージェント向けの構造化出力にも対応します。

主な機能

  1. 01DOI またはタイトルで論文を特定
  2. 02優先順に PDF ソースを検索
  3. 03複数論文の一括ダウンロード
  4. 04JSON と進捗イベントの出力
  5. 05機械可読な CLI スキーマ

活用シーン

  1. 01DOI から論文 PDF を取得
  2. 02論文タイトルから PDF を検索
  3. 03論文リストの一括ダウンロード
  4. 04構造化エラーに基づく再試行

インストール

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

$npx skills add https://github.com/agents365-ai/paper-fetch --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 を 1 つ読み込む場合は - を使用します
--title TITLE—論文のタイトル。ダウンロード前に Crossref を使って DOI に解決します。位置引数の DOI/--batch とは併用できません
--batch FILE—一括ダウンロード用の、1 行に DOI が 1 つ記載されたファイル。標準入力から読み込む場合は - を使用します
--out DIRpdfs出力ディレクトリ
--formatautoエージェント向けの 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 に 1 行につき 1 つの JSON オブジェクトが出力されます。

{"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 が含まれており、最後のエンベロープを待たずに、キャッシュしたコピーと照合してスキーマの変更を検出できます。

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

--format text の場合、stderr には人間が読みやすい文章が出力されます。

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

この分類により、オーケストレーターは失敗を確実に振り分けられます。終了コード 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_pdf応答が PDF ではありませんでした(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自動import cloakbrowser を実行できる 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 を、画面表示ありの CloakBrowser フォールバックで正常にダウンロードできます。

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

変わらない点:

  • 返されたバイト列は、同じ %PDF マジックバイト検証と 50 MB のサイズ上限で再検証されます。ブラウザーが起動される前に、引き続き SSRF 対策によって URL が制限されます。
  • 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 リクエスト/秒のレートリミッター。

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

機関モードでの変更点:

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

変わらない点:

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

パブリックモードで OA 版を見つけられない場合、エラーエンベロープには suggest_institutional: true と、ユーザーに環境変数の設定を促すヒントが含まれます。エージェントは、何も知らせずに失敗するのではなく、この情報をそのまま表示できます。

利用規約に関する注意: ほぼすべての出版社のサブスクリプションで「組織的なダウンロード」が禁止されています。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/。

コメント