pyPaperFlow 0.3.0__tar.gz → 0.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pypaperflow-0.6.1/.claude/settings.local.json +8 -0
- pypaperflow-0.6.1/.github/workflows/docs.yml +35 -0
- pypaperflow-0.6.1/.gitignore +24 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/PKG-INFO +229 -39
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/README.md +228 -38
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/README_zh.md +790 -75
- pypaperflow-0.6.1/mkdoc_site/index.md +61 -0
- pypaperflow-0.6.1/mkdocs.yml +53 -0
- pypaperflow-0.6.1/requirements-docs.txt +1 -0
- pypaperflow-0.6.1/scripts/sync_docs.py +228 -0
- pypaperflow-0.6.1/src/pyPaperFlow/__init__.py +1 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/cli.py +309 -33
- pypaperflow-0.6.1/src/pyPaperFlow/integrations/cloak_fallback.py +72 -0
- pypaperflow-0.6.1/src/pyPaperFlow/integrations/cloak_pdf.py +221 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/integrations/pdf_fetch.py +514 -51
- pypaperflow-0.6.1/src/pyPaperFlow/integrations/undetected_fallback.py +77 -0
- pypaperflow-0.6.1/src/pyPaperFlow/integrations/undetected_pdf.py +362 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/preprint/arxiv_fetcher.py +153 -58
- pypaperflow-0.6.1/src/pyPaperFlow/preprint/biorxiv_fetcher.py +830 -0
- pypaperflow-0.3.0/src/pyPaperFlow/preprint/biorxiv_fetcher.py → pypaperflow-0.6.1/src/pyPaperFlow/preprint/chemrxiv_fetcher.py +180 -137
- pypaperflow-0.6.1/src/pyPaperFlow/preprint/europepmc_fetcher.py +204 -0
- pypaperflow-0.6.1/src/pyPaperFlow/preprint/source_merge.py +52 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/preprint/source_utils.py +23 -2
- pypaperflow-0.3.0/.gitignore +0 -12
- pypaperflow-0.3.0/src/pyPaperFlow/__init__.py +0 -1
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/LICENSE +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/pyproject.toml +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/integrations/github_export.py +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/integrations/mineru_parser.py +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/preprint/source_models.py +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/pubmed/__init__.py +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/pubmed/pubmed_fetcher.py +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/pubmed/pubmed_merger.py +0 -0
- {pypaperflow-0.3.0 → pypaperflow-0.6.1}/src/pyPaperFlow/utils.py +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(curl -s -m 40 --noproxy '*' \"https://www.ebi.ac.uk/europepmc/webservices/rest/search?query=SRC:PPR%20AND%20zinc%20AND%20finger%20AND%20263%20AND%20FIRST_PDATE:%5B2026-08-01%20TO%202026-12-31%5D&format=json&pageSize=25&cursorMark=*&resultType=core\" -o /tmp/epmc_date.json -w \"HTTP=%{http_code}\\\\n\")",
|
|
5
|
+
"Bash(python3 -c ' *)"
|
|
6
|
+
]
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "README_zh.md"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
pages: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: pages
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
deploy:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
- uses: actions/setup-python@v7
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.13"
|
|
27
|
+
- run: pip install -r requirements-docs.txt
|
|
28
|
+
- run: python scripts/sync_docs.py
|
|
29
|
+
- run: mkdocs build
|
|
30
|
+
- uses: actions/configure-pages@v6
|
|
31
|
+
- uses: actions/upload-pages-artifact@v5
|
|
32
|
+
with:
|
|
33
|
+
path: site
|
|
34
|
+
- id: deployment
|
|
35
|
+
uses: actions/deploy-pages@v5
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# build product
|
|
2
|
+
dist/
|
|
3
|
+
build/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
|
|
6
|
+
# Python cache
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
|
|
10
|
+
# environment
|
|
11
|
+
.env
|
|
12
|
+
venv/
|
|
13
|
+
CLAUDE.md
|
|
14
|
+
pdfs/
|
|
15
|
+
refers/
|
|
16
|
+
|
|
17
|
+
# mkdocs build output
|
|
18
|
+
site/
|
|
19
|
+
.cache/
|
|
20
|
+
|
|
21
|
+
# generated docs (from scripts/sync_docs.py)
|
|
22
|
+
# ignore everything under mkdoc_site/ except the hand-written homepage
|
|
23
|
+
mkdoc_site/*
|
|
24
|
+
!mkdoc_site/index.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pyPaperFlow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Automated paper fetching and analysis platform.
|
|
5
5
|
Project-URL: Homepage, https://github.com/MaybeBio/pyPaperFlow
|
|
6
6
|
Project-URL: Issues, https://github.com/MaybeBio/pyPaperFlow/issues
|
|
@@ -35,7 +35,7 @@ Description-Content-Type: text/markdown
|
|
|
35
35
|
|
|
36
36
|
<p><strong>An automated literature processing platform for scientific researchers.</strong></p>
|
|
37
37
|
|
|
38
|
-
<p>Batch retrieve, fetch, parse, and structure papers from PubMed, arXiv, bioRxiv, and DOI-based sources.</p>
|
|
38
|
+
<p>Batch retrieve, fetch, parse, and structure papers from PubMed, arXiv, bioRxiv, ChemRxiv, and DOI-based sources.</p>
|
|
39
39
|
|
|
40
40
|
<p>From paper retrieval to knowledge internalization, automate the heavy lifting and keep the judgment human.</p>
|
|
41
41
|
|
|
@@ -44,17 +44,20 @@ Description-Content-Type: text/markdown
|
|
|
44
44
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
45
45
|
[](http://makeapullrequest.com)
|
|
46
46
|
[](docs/Design.md)
|
|
47
|
-
[](#features)
|
|
47
|
+
[](#features)
|
|
48
48
|
[](https://pypi.org/project/pyPaperFlow/)
|
|
49
49
|
[](https://pypi.org/project/pyPaperFlow/)
|
|
50
50
|
[](https://pepy.tech/project/pyPaperFlow)
|
|
51
|
+
[](https://maybebio.github.io/pyPaperFlow/)
|
|
51
52
|
|
|
52
53
|
<p>
|
|
53
|
-
|
|
54
|
+
文档阅读👉
|
|
54
55
|
<a href="README.md">English</a> |
|
|
55
|
-
<a href="README_zh.md">中文</a>
|
|
56
|
+
<a href="README_zh.md">中文</a> |
|
|
57
|
+
<a href="https://maybebio.github.io/pyPaperFlow/" target="_blank">中文在线文档</a>
|
|
56
58
|
</p>
|
|
57
59
|
|
|
60
|
+
|
|
58
61
|
<p>
|
|
59
62
|
<a href="./docs/Design.md">Design</a> |
|
|
60
63
|
<a href="./docs/Cases.md">Cases</a>
|
|
@@ -109,6 +112,7 @@ This tool is designed to `complement rather than replace` reference management s
|
|
|
109
112
|
|
|
110
113
|
- **Automated Retrieval from Multiple Sources**: Automatically search and retrieve paper metadata and full-text records from `PubMed/Medline, arXiv, medRxiv, chemRxiv and bioRxiv`. The repository focuses primarily on biomedical research and computational interdisciplinary fields (`Biomedicine + Computational Biology`).
|
|
111
114
|
- **Full-Text Access**: Enable automatic downloading of open-access full texts in XML/Text format from `PMC`. For preprints and other publications without accessible PMC full texts, alternative acquisition modules are integrated to fetch `original PDFs`, with `Sci-Hub` set as the fallback provider.
|
|
115
|
+
- **Preprint Full-Text Fetch (no PDF parsing)**: For preprints without an OA PDF, dedicated methods return clean section-headed text directly — `ArxivFetcher.fetch_full_text(arxiv_id)` reads ar5iv-rendered HTML (arXiv LaTeX → HTML), and `BioRxivFetcher.fetch_full_text(doi)` / `EuropePMCFullText.full_text_xml(doi)` read JATS full-text XML from Europe PMC (bioRxiv / medRxiv and other DOI-indexed preprints).
|
|
112
116
|
- **Structured Storage**:
|
|
113
117
|
- **Metadata**: Preserved in well-structured detailed JSON files.
|
|
114
118
|
- **Full Text**: Stored in multiple formats including parsed JSON and Markdown for versatile downstream usage — JSON for programmatic data analysis, and Markdown optimized for LLM comprehension and processing.
|
|
@@ -179,6 +183,8 @@ flowchart TD
|
|
|
179
183
|
|
|
180
184
|
## 📦 Installation
|
|
181
185
|
|
|
186
|
+
> ⚠️ For typical usage, you only need to install our tool, seen below:
|
|
187
|
+
|
|
182
188
|
```bash
|
|
183
189
|
# 1. install our tool
|
|
184
190
|
## ✏️1️⃣ option1: Install via pip (Recommended)
|
|
@@ -188,9 +194,11 @@ pip install pyPaperFlow
|
|
|
188
194
|
git clone https://github.com/MaybeBio/pyPaperFlow.git
|
|
189
195
|
cd pyPaperFlow
|
|
190
196
|
pip install -e .
|
|
197
|
+
```
|
|
191
198
|
|
|
192
|
-
|
|
199
|
+
> Some optional dependencies, if you do not need to use the corresponding functional modules, you can ignore the installation. seen below:
|
|
193
200
|
|
|
201
|
+
```bash
|
|
194
202
|
# 2. install MinerU
|
|
195
203
|
# follow the official installation guide: https://github.com/opendatalab/MinerU
|
|
196
204
|
# verify installation: mineru --help
|
|
@@ -210,10 +218,11 @@ pip install openai anthropic
|
|
|
210
218
|
pip install paperscraper
|
|
211
219
|
```
|
|
212
220
|
|
|
213
|
-
> ⚠️ For typical usage, you only need to install the repository from source and MinerU, which are steps 1 and 2.
|
|
214
221
|
|
|
215
222
|
## 🛠️ Usage
|
|
216
223
|
|
|
224
|
+
> 📌 **Tip**: If you want to get started directly, please refer to the usage examples in [Cases.md](./docs/Cases.md). The content below is theoretical process analysis and can be skipped.
|
|
225
|
+
|
|
217
226
|
We designed pyPaperFlow as a versatile academic research tool built strictly around the `real‑world workflow of researchers conducting literature investigation, paper reading, literature comprehension and analysis, and corpus utilization`.
|
|
218
227
|
|
|
219
228
|
Therefore, please follow our step‑by‑step operations, which mirror your full literature research process. Through this hands‑on experience, you will fully grasp the design philosophy and usage of this tool.
|
|
@@ -227,33 +236,39 @@ Current available modules include (`will be continuously updated`):
|
|
|
227
236
|
|
|
228
237
|
```python
|
|
229
238
|
❯ paperflow --help
|
|
230
|
-
|
|
231
|
-
Usage: paperflow [OPTIONS] COMMAND [ARGS]...
|
|
232
|
-
|
|
233
|
-
pyPaperFlow CLI
|
|
234
|
-
|
|
235
|
-
╭─ Options
|
|
236
|
-
│ --install-completion Install completion for the current shell.
|
|
237
|
-
│ --show-completion Show completion for the current shell, to copy it or customize the installation.
|
|
238
|
-
│ --help Show this message and exit.
|
|
239
|
-
|
|
240
|
-
╭─ Commands
|
|
241
|
-
│ pubmed-search Search PubMed using Your customized query and return PMIDs.
|
|
242
|
-
│ pubmed-meta Fetch paper metadata from PubMed using Your customized query, pmid list file and save to storage.
|
|
243
|
-
│ pubmed-content Download full text (PMC) for given PMIDs if the paper has a PMC ID.
|
|
244
|
-
│ pubmed-all Fetch BOTH metadata and full text (if available) for papers.
|
|
245
|
-
│ Also extracts URLs from full text and updates metadata links.
|
|
246
|
-
│ pubmed-merge-json Create a merged JSON (or JSONL) file from PubMed paper directories.
|
|
247
|
-
│ pubmed-export-md Export a single Markdown view from a merged JSON file using optional YAML config.
|
|
248
|
-
│ arxiv-search Search arXiv and write matching IDs to a text file.
|
|
249
|
-
│ arxiv-fetch Fetch arXiv metadata and attempt to download PDFs.
|
|
250
|
-
│ biorxiv-search Search bioRxiv and write matching IDs to a text file.
|
|
251
|
-
│ biorxiv-fetch Fetch bioRxiv metadata and attempt to download PDFs.
|
|
252
|
-
│
|
|
253
|
-
│
|
|
254
|
-
│
|
|
255
|
-
│
|
|
256
|
-
|
|
239
|
+
|
|
240
|
+
Usage: paperflow [OPTIONS] COMMAND [ARGS]...
|
|
241
|
+
|
|
242
|
+
pyPaperFlow CLI
|
|
243
|
+
|
|
244
|
+
╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
245
|
+
│ --install-completion Install completion for the current shell. │
|
|
246
|
+
│ --show-completion Show completion for the current shell, to copy it or customize the installation. │
|
|
247
|
+
│ --help Show this message and exit. │
|
|
248
|
+
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
249
|
+
╭─ Commands ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
250
|
+
│ pubmed-search Search PubMed using Your customized query and return PMIDs. │
|
|
251
|
+
│ pubmed-meta Fetch paper metadata from PubMed using Your customized query, pmid list file and save to storage. │
|
|
252
|
+
│ pubmed-content Download full text (PMC) for given PMIDs if the paper has a PMC ID. │
|
|
253
|
+
│ pubmed-all Fetch BOTH metadata and full text (if available) for papers. │
|
|
254
|
+
│ Also extracts URLs from full text and updates metadata links. │
|
|
255
|
+
│ pubmed-merge-json Create a merged JSON (or JSONL) file from PubMed paper directories. │
|
|
256
|
+
│ pubmed-export-md Export a single Markdown view from a merged JSON file using optional YAML config. │
|
|
257
|
+
│ arxiv-search Search arXiv and write matching IDs to a text file. │
|
|
258
|
+
│ arxiv-fetch Fetch arXiv metadata and attempt to download PDFs. │
|
|
259
|
+
│ biorxiv-search Search bioRxiv and write matching IDs to a text file. │
|
|
260
|
+
│ biorxiv-fetch Fetch bioRxiv metadata and attempt to download PDFs. │
|
|
261
|
+
│ medrxiv-search Search medRxiv and write matching IDs to a text file. │
|
|
262
|
+
│ medrxiv-fetch Fetch medRxiv metadata and attempt to download PDFs. │
|
|
263
|
+
│ chemrxiv-search Search ChemRxiv and write matching IDs to a text file. │
|
|
264
|
+
│ chemrxiv-fetch Fetch ChemRxiv metadata and attempt to download PDFs. │
|
|
265
|
+
│ paper-fetch Fetch PDFs by DOI — passes through to the paper-fetch engine. │
|
|
266
|
+
│ pdf-parse Parse a PDF file using MinerU engine, and clean up the output directory. │
|
|
267
|
+
│ mineru-parse Parse mineru output content_list_v2.json into canonical sectioned JSON. │
|
|
268
|
+
│ mineru-export-md Export structured mineru JSON to a clean Markdown file for LLM processing. │
|
|
269
|
+
│ github-export Export GitHub links from merged PubMed JSON, validate accessibility, │
|
|
270
|
+
│ and aggregate `ghresearcher parse <owner/repo> --view` outputs into one markdown. │
|
|
271
|
+
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
257
272
|
|
|
258
273
|
```
|
|
259
274
|
|
|
@@ -275,11 +290,20 @@ bioRxiv Modules:
|
|
|
275
290
|
- biorxiv-search # search bioRxiv and return matching IDs
|
|
276
291
|
- biorxiv-fetch # fetch bioRxiv metadata and attempt to download PDFs
|
|
277
292
|
|
|
293
|
+
medRxiv Modules:
|
|
294
|
+
- medrxiv-search # search medRxiv and return matching IDs
|
|
295
|
+
- medrxiv-fetch # fetch medRxiv metadata and attempt to download PDFs
|
|
296
|
+
|
|
297
|
+
ChemRxiv Modules:
|
|
298
|
+
- chemrxiv-search # search ChemRxiv and return matching IDs
|
|
299
|
+
- chemrxiv-fetch # fetch ChemRxiv metadata and attempt to download PDFs
|
|
300
|
+
|
|
278
301
|
Third-party Modules:
|
|
279
302
|
- paper-fetch # fetch PDFs by DOI
|
|
280
303
|
- pdf-parse # parse PDF files into JSON, Markdown format using the MinerU engine
|
|
281
304
|
- mineru-parse # Based on your custom section configuration, re-parse the MinerU output file into a structured JSON format clustered by standard literature sections
|
|
282
305
|
- mineru-export-md # Based on your custom section configuration, export the structured mineru JSON to a clean Markdown file for LLM processing (🌟 e.g., batch export of introductions as your research background)
|
|
306
|
+
- github-export # export GitHub links from merged PubMed JSON, validate accessibility, and aggregate `ghresearcher parse <owner/repo> --view` outputs into one markdown
|
|
283
307
|
```
|
|
284
308
|
|
|
285
309
|
> ⚠️ `Other preprint platforms modules are under development, please stay tuned!`
|
|
@@ -323,6 +347,20 @@ Our literature database primarily covers biomedical research and computational i
|
|
|
323
347
|
- arXiv
|
|
324
348
|
- bioRxiv,medRxiv,chemRxiv
|
|
325
349
|
|
|
350
|
+
> **⚠️ — Preprint search = Crossref relevance search + local boolean re-check (not a full-corpus pull, and not each server's official API).** Each request asks Crossref to search ONLY that platform's prefix (`filter=prefix:10.64898 / 10.26434,type:posted-content`) — platform scoping happens server-side, not by post-filtering a global result set. bioRxiv and medRxiv share the openRxiv prefix `10.64898`, so those two are then told apart locally by DOI-accession digit count (6 = bioRxiv, 8 = medRxiv).
|
|
351
|
+
>
|
|
352
|
+
> How the relevance step behaves: `query.bibliographic` is a fuzzy, OR-like ranking (a two-term query returns more than either single term — e.g. chemRxiv "base editing" ≈ the union of "base" and "editing"), i.e. a **superset** of the strict matches. The fetcher cursor-paginates the whole result set (not a capped top-N), then keeps only records in which **every** query term is actually present in the metadata (local boolean AND over title/abstract/…). Because strict matches ⊆ relevance superset, ranking never drops a metadata-level exact match — it only changes the order.
|
|
353
|
+
>
|
|
354
|
+
> **Limitations of the relevance search:**
|
|
355
|
+
>
|
|
356
|
+
> ① **Deposit lag** — a preprint posted minutes ago may not be indexed in Crossref yet.
|
|
357
|
+
>
|
|
358
|
+
> ② **Metadata-only matching** — Crossref scores deposited metadata (title/abstract/…), so query terms that appear only in the paper body are invisible to it. Only the bioRxiv/medRxiv Europe PMC leg indexes full text; **ChemRxiv has no full-text leg at all**, so body-only-term misses are expected there.
|
|
359
|
+
>
|
|
360
|
+
> ③ **Version duplication** — every revision is its own DOI work, so `.../v1` and `.../v2` both match a search and may need manual dedup.
|
|
361
|
+
>
|
|
362
|
+
> **Difference vs. exhaustive full-corpus enumeration:** a relevance search is a heuristic over the deposited metadata. The "no-omission-by-construction" alternative is to list the *whole* platform corpus (`filter=prefix…` with no `query`, cursor-paging every record — ≈ 55k ChemRxiv / 436k openRxiv) and run the boolean AND locally, with no relevance engine in the loop; recall is then exactly "all records whose metadata fully matches the query" (a `--start/--end-date` window shrinks the pull). The cost is downloading the full corpus per search, and it still inherits the source-level boundaries above (deposit lag, metadata-only, version duplication). This tool's `search()` path is relevance-based today; the exhaustive mode is not currently exposed as a flag.
|
|
363
|
+
|
|
326
364
|
We recommend that you proactively learn and master the search syntax of these databases, as our built‑in search module functions similarly to the search bar on official web portals.
|
|
327
365
|
|
|
328
366
|
For instance, here is a typical complex query example tailored for PubMed:
|
|
@@ -599,6 +637,8 @@ examples:
|
|
|
599
637
|
|
|
600
638
|
We acknowledge the work of [paper-fetch](https://github.com/Agents365-ai/paper-fetch)!We have modified, refactored, and encapsulated one of its core scripts for tailored integration into our pipeline.
|
|
601
639
|
|
|
640
|
+
> 🔙 Rollback boundary for the paper-fetch module: commit `bc8394c` (`update paper-fetch module according to upstream repo`) contains the **original upstream script**. Commit `89eda06bac1f853254b04aee9e8916109c7771a1` is the first local **modification** to it. To restore the original module, use `89eda06` as the boundary — e.g. `git show 89eda06^:src/pyPaperFlow/integrations/pdf_fetch.py` (identical to `bc8394c`).
|
|
641
|
+
|
|
602
642
|
The workflow of our paper acquisition module is outlined below:
|
|
603
643
|
|
|
604
644
|
```bash
|
|
@@ -624,6 +664,8 @@ The workflow of our paper acquisition module is outlined below:
|
|
|
624
664
|
┌─────────────────────────────────────────┐
|
|
625
665
|
│ 3. arXiv (via S2 externalIds.ArXiv) │
|
|
626
666
|
│ 4. Europe PMC → PMC (via PMCID) │
|
|
667
|
+
│ No PMCID: DOI→PMCID recovery │
|
|
668
|
+
│ (Europe PMC hasPDF=Y / OpenAIRE) │
|
|
627
669
|
│ 5. bioRxiv / medRxiv (DOI prefix: 10.1101/)
|
|
628
670
|
└─────────────────────────────────────────┘
|
|
629
671
|
Total Failure ↓
|
|
@@ -634,7 +676,12 @@ The workflow of our paper acquisition module is outlined below:
|
|
|
634
676
|
└─────────────────────────────────────────┘
|
|
635
677
|
Persistent Failure ↓
|
|
636
678
|
┌─────────────────────────────────────────┐
|
|
637
|
-
│ 7.
|
|
679
|
+
│ 7. CORE Repository Aggregator (optional, requires CORE_API_KEY)
|
|
680
|
+
│ → core.ac.uk aggregates OA full-text downloadUrl
|
|
681
|
+
└─────────────────────────────────────────┘
|
|
682
|
+
Persistent Failure ↓
|
|
683
|
+
┌─────────────────────────────────────────┐
|
|
684
|
+
│ 8. Sci‑Hub Mirror Fallback (enabled by default, configurable)
|
|
638
685
|
│ → 1 request‑per‑second rate‑limiting to prevent CAPTCHA triggers
|
|
639
686
|
│ → Automatic discovery of active new mirrors
|
|
640
687
|
└─────────────────────────────────────────┘
|
|
@@ -647,9 +694,10 @@ Resolution Priority Sequence
|
|
|
647
694
|
Unpaywall: The optimal open‑access source covering the broadest range of publishers with the highest hit rate.
|
|
648
695
|
Semantic Scholar: Retrieves OA PDF links and cross‑platform external identifiers.
|
|
649
696
|
arXiv: Activated when an arXiv identifier is available for the target paper.
|
|
650
|
-
PubMed Central (PMC) OA Subset: Activated when a PMCID is associated with the paper.
|
|
697
|
+
PubMed Central (PMC) OA Subset: Activated when a PMCID is associated with the paper; when no PMCID is known, a DOI→PMCID recovery is attempted first (Europe PMC search hasPDF=Y / OpenAIRE originalId).
|
|
651
698
|
bioRxiv / medRxiv: Triggered for preprints with the DOI prefix 10.1101/.
|
|
652
699
|
Publisher Direct Links: Enabled only under institutional mode (PAPER_FETCH_INSTITUTIONAL=1), authorized via the caller’s institutional subscription IP, cookies, or EZproxy access.
|
|
700
|
+
CORE Repository Aggregator: Optional, requires CORE_API_KEY; aggregates full texts from many repositories, attempted only when all other OA sources miss (free tier ~5 req/10s).
|
|
653
701
|
Sci‑Hub Mirror Fallback: Enabled by default as the final retrieval backup.
|
|
654
702
|
Mirrors are attempted in the order specified by the environment variable PAPER_FETCH_SCIHUB_MIRRORS (default list: sci‑hub.ru, sci‑hub.st, sci‑hub.su, sci‑hub.box, sci‑hub.red, sci‑hub.al, sci‑hub.mk, sci‑hub.ee).
|
|
655
703
|
If all predefined mirrors fail, the module fetches the latest live mirror list from https://www.sci‑hub.pub/ and retries.
|
|
@@ -665,6 +713,120 @@ export UNPAYWALL_EMAIL=you@example.com
|
|
|
665
713
|
```
|
|
666
714
|
|
|
667
715
|
|
|
716
|
+
**Cloudflare-blocked PDFs (optional)**
|
|
717
|
+
|
|
718
|
+
Some publishers (e.g. `science.org`) sit behind Cloudflare and return `403`/`429` or a "Just a moment…" JS challenge page instead of the PDF. Set `PAPER_FETCH_CLOAK=1` to retry those URLs through [CloakBrowser](https://github.com/CloakHQ/CloakBrowser) (a stealth Chromium that can pass the challenge). This fallback lives at the download layer (covers all sources), fails silently when CloakBrowser is unavailable, is operator-controlled (agents cannot enable it), and re-validates returned bytes through the same `%PDF` + 50 MB checks. Successful cloak downloads carry `via:"cloak"`.
|
|
719
|
+
|
|
720
|
+
Setup — install once, then treat `PAPER_FETCH_CLOAK` as an always-on safety net:
|
|
721
|
+
|
|
722
|
+
```bash
|
|
723
|
+
# One-time install: put cloakbrowser into the same Python that runs paperflow
|
|
724
|
+
# (auto-detected), or into a separate venv and point CLOAKBROWSER_PYTHON at it.
|
|
725
|
+
pip install cloakbrowser
|
|
726
|
+
|
|
727
|
+
# Recommended: keep as a safety net (fires ONLY when a download is blocked;
|
|
728
|
+
# normal OA downloads are unaffected).
|
|
729
|
+
export PAPER_FETCH_CLOAK=1
|
|
730
|
+
|
|
731
|
+
# Cleaner per-command alternative, when you only occasionally hit a blocked URL:
|
|
732
|
+
PAPER_FETCH_CLOAK=1 paperflow paper-fetch 10.1126/sciadv.aee6105 --out ./pdfs
|
|
733
|
+
|
|
734
|
+
# ⚠️ PAPER_FETCH_CLOAK_HEADED=1 is NOT a default. Set it only for strong
|
|
735
|
+
# challenges (e.g. science.org) AND only on a machine with a display:
|
|
736
|
+
# export PAPER_FETCH_CLOAK_HEADED=1
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
> **Practical notes (from testing)**
|
|
740
|
+
> - Cloak is **not** a paywall bypass. It only fires when an *OA* download is Cloudflare-blocked; a paywalled paper (no OA copy, e.g. `10.1016/j.cels.2025.101486`) never reaches the download layer, so Cloak is never invoked.
|
|
741
|
+
> - `science.org` is a "strong" challenge that **headless cannot pass** (it stalls on "Just a moment…") — it requires `PAPER_FETCH_CLOAK_HEADED=1` on a real display (a desktop, or a headless server wrapped with `xvfb-run`).
|
|
742
|
+
> - Cloak only has a URL to retry when a source returned a direct `url_for_pdf`. Papers whose only OA copy is in PMC (Unpaywall reports a landing page with no `url_for_pdf`) are **not** attempted by the stock script.
|
|
743
|
+
> - Keeping `PAPER_FETCH_CLOAK=1` always on has no effect on normal downloads, but once `cloakbrowser` is installed, each blocked URL adds a ~30–90 s browser attempt before falling through; use the inline form if you'd rather not wait.
|
|
744
|
+
> - Sci-Hub discovery contacts `www.sci-hub.pub` — on networks where that DNS is blocked you'll see `scihub_discover_failed`, which removes the last fallback. For genuinely unavailable papers, use institutional mode (`PAPER_FETCH_INSTITUTIONAL=1`) or download via a browser / interlibrary loan.
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
**Institutional access (optional)**
|
|
748
|
+
|
|
749
|
+
Some paywalled papers are exactly what your institution's subscription covers — a generic OA source just can't see them. Set `PAPER_FETCH_INSTITUTIONAL=1` to enable the publisher-direct-link source (step 6 of the chain): the script builds a direct PDF URL for the DOI's publisher and downloads it.
|
|
750
|
+
|
|
751
|
+
```bash
|
|
752
|
+
export PAPER_FETCH_INSTITUTIONAL=1 # only effective while on the institutional network
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
> **Key requirement (verified by testing):** authorization comes from the *caller's network*, not the script. Publisher-direct downloads succeed only when the machine runs **on-campus or on the institutional VPN** — the publisher recognizes your institution's IP range (or cookies / EZproxy). From an off-network IP (a datacenter or home machine) the URL is still built correctly but the publisher answers `HTTP 403 Forbidden`, and the run ends with `download_network_error` (retryable) instead of `not_found` — that error-type change is how you can tell institutional mode actually fired.
|
|
756
|
+
> - The result envelope's `auth_mode` field reports `"institutional"` (vs `"public"`).
|
|
757
|
+
> - Direct-link templates are matched by DOI prefix; Elsevier (`10.1016/`) needs an extra PII lookup via Crossref and `sciencedirect.com/.../pdfft` — verified working. Supported publishers: Nature, Science, Wiley, Springer, ACS, PNAS, NEJM, SAGE, Taylor & Francis, Elsevier, MDPI.
|
|
758
|
+
> - Auto rate-limits to **1 req/s** to respect publisher ToS (protects your institution's IP from throttling).
|
|
759
|
+
> - In public mode, when a paper looks paywalled the error payload sets `suggest_institutional: true` and hints to set this variable and re-run from on-campus / VPN.
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
**CORE repository-aggregator fallback (optional)**
|
|
763
|
+
|
|
764
|
+
When a paper misses across all OA sources (Unpaywall / Semantic Scholar / arXiv / PMC / bioRxiv) but an institutional or subject repository may still hold a copy, set `CORE_API_KEY` to enable the [CORE](https://core.ac.uk) (core.ac.uk) aggregator fallback. CORE aggregates full-text metadata from thousands of OA repositories and journals worldwide; its v3 search API queries by DOI and the `downloadUrl` field of a matching record is the directly downloadable OA full-text link (paywalled records leave this field empty and are skipped automatically).
|
|
765
|
+
|
|
766
|
+
```bash
|
|
767
|
+
export CORE_API_KEY=your_core_api_key # free signup: https://core.ac.uk/services/api
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
> **Principle & notes**
|
|
771
|
+
> - CORE is a *repository aggregator*, not a single publisher: it pools full texts from institutional and subject repositories, covering repository copies that other sources miss.
|
|
772
|
+
> - This source fires **only** when all earlier OA sources (Unpaywall / Semantic Scholar / arXiv / PMC / bioRxiv) have missed — it never interferes with the normal OA download path, so keeping it on is harmless.
|
|
773
|
+
> - Requires a free API key (Bearer auth); the source is silently skipped when `CORE_API_KEY` is unset.
|
|
774
|
+
> - The free tier rate-limits to roughly **5 requests / 10 seconds** and returns `403` when exceeded — imperceptible for single papers, and batch fetching is serialized/throttled.
|
|
775
|
+
> - Returned links pass the same `%PDF` magic-byte + 50 MB checks; successful hits carry `source:"core"`.
|
|
776
|
+
> - Only records with a non-empty `downloadUrl` are used, naturally filtering out paywalled entries with no OA copy.
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
**Recommended setup (best practice)**
|
|
780
|
+
|
|
781
|
+
For a mixed workload — OA papers, Cloudflare-gated OA papers, and the occasional paywalled paper your institution subscribes to — keep three things on:
|
|
782
|
+
|
|
783
|
+
```bash
|
|
784
|
+
export UNPAYWALL_EMAIL=you@example.com # fastest / broadest OA source
|
|
785
|
+
export PAPER_FETCH_CLOAK=1 # safety net for Cloudflare-gated OA PDFs (harmless otherwise)
|
|
786
|
+
# Run the line below only while on campus / the institutional VPN:
|
|
787
|
+
export PAPER_FETCH_INSTITUTIONAL=1 # publisher-direct links for paywalled papers
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
Decision logic for a single paper:
|
|
791
|
+
|
|
792
|
+
- **OA paper** → Unpaywall / Semantic Scholar / arXiv / PMC handle it; `PAPER_FETCH_CLOAK` only adds a retry when the download is Cloudflare-blocked.
|
|
793
|
+
- **Cloudflare-blocked OA** (e.g. `science.org`) → Cloak retries it (headless may stall; use `PAPER_FETCH_CLOAK_HEADED=1` on a machine with a display).
|
|
794
|
+
- **Paywalled paper** (e.g. `10.1016/j.cels.2025.101486`) → only the institutional chain can fetch it, and only from on-campus / VPN: Unpaywall → Semantic Scholar → publisher-direct (Elsevier via PII lookup → `sciencedirect.com/.../pdfft`) → Sci-Hub fallback. From an off-network IP the publisher answers `403` and no automated path remains — use your library portal / EZproxy or interlibrary loan.
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
**Notes & Environment Variables**
|
|
798
|
+
|
|
799
|
+
All settings are read from environment variables when the process starts — there is no config file. Every var above can be combined freely.
|
|
800
|
+
|
|
801
|
+
| Env var | Effect | Default | When to set |
|
|
802
|
+
| --- | --- | --- | --- |
|
|
803
|
+
| `UNPAYWALL_EMAIL` | Contact email for the Unpaywall API (sent in the User-Agent); without it the Unpaywall source is skipped. | empty | Recommended — Unpaywall is the fastest / broadest source |
|
|
804
|
+
| `CORE_API_KEY` | API key for the CORE (core.ac.uk) aggregator; without it the `core` repository source is skipped. | empty | When you need coverage for institutional / subject repository OA copies |
|
|
805
|
+
| `PAPER_FETCH_NO_SCIHUB` | Set to `1` to disable the Sci-Hub mirror fallback. | Sci-Hub ON | If your institution / compliance forbids Sci-Hub |
|
|
806
|
+
| `PAPER_FETCH_SCIHUB_MIRRORS` | Comma-separated mirror list, tried in priority order (hostnames only). | built-in default list | When the default mirrors stop working |
|
|
807
|
+
| `PAPER_FETCH_INSTITUTIONAL` | Set to `1` to enable publisher direct links (authorized by your institutional IP / cookies / EZproxy). Auto rate-limits to 1 req/s to respect publisher ToS. | off | If you have an institutional subscription |
|
|
808
|
+
| `PAPER_FETCH_CLOAK` | Set to `1` to retry Cloudflare-blocked PDFs through CloakBrowser. | off | For publishers behind Cloudflare (e.g. `science.org`) |
|
|
809
|
+
| `CLOAKBROWSER_PYTHON` | Python interpreter that can `import cloakbrowser`. | auto-detected | Only if not auto-detected |
|
|
810
|
+
| `PAPER_FETCH_CLOAK_HEADED` | Set to `1` for a headed browser (needs a display). | headless | For strong challenges that fail headless (e.g. `science.org`) |
|
|
811
|
+
|
|
812
|
+
> ⚠️ **Boolean flags are presence-based, not value-based.** The code checks `os.environ.get(...)`, so *any* non-empty value enables the feature. Setting `PAPER_FETCH_CLOAK=0` or `=false` still **enables** Cloak; setting `PAPER_FETCH_NO_SCIHUB=0` still **disables** Sci-Hub. To turn a feature off, `unset` the variable — never write `=0`/`=false`.
|
|
813
|
+
|
|
814
|
+
**Usage notes**
|
|
815
|
+
|
|
816
|
+
- The output directory flag is `--out` — there is **no `-o` short option** (the `paperflow paper-fetch` passthrough does not rewrite args).
|
|
817
|
+
- One DOI as a positional arg; `-` reads a single DOI from stdin; `--batch FILE` (or `--batch -`) reads DOIs line-by-line.
|
|
818
|
+
- Files already downloaded are skipped by default; pass `--overwrite` to force a re-download.
|
|
819
|
+
- stdout carries the machine-readable JSON envelope, stderr carries progress; `--format json|text` plus TTY auto-detection control the shape. Exit codes: `0` all resolved, `1` some unresolved, `3` bad arguments, `4` transport error (retryable).
|
|
820
|
+
- `paperflow paper-fetch schema` prints the machine-readable CLI schema (no network).
|
|
821
|
+
- `--idempotency-key KEY` replays the original result envelope on retry, with no network I/O.
|
|
822
|
+
|
|
823
|
+
**Known limitations**
|
|
824
|
+
|
|
825
|
+
- Some publisher redirects land on HTML pages instead of PDFs — the `%PDF` magic-byte check rejects them.
|
|
826
|
+
- No browser automation by default (no CAPTCHA solving) — only the optional `PAPER_FETCH_CLOAK` CloakBrowser fallback.
|
|
827
|
+
- SSRF protection rejects private IPs, non-`http(s)` schemes, non-80/443 ports, and cloud metadata hosts.
|
|
828
|
+
- Each PDF is capped at 50 MB.
|
|
829
|
+
|
|
668
830
|
Unlike PMC parsing, non‑PubMed papers can only be obtained as PDF files via the paper‑fetch module.
|
|
669
831
|
|
|
670
832
|
We recommend standardizing all paper information into Markdown or JSON formats.
|
|
@@ -1289,6 +1451,31 @@ In theory, all DOI‑driven literature workflows can be standardised following t
|
|
|
1289
1451
|
|
|
1290
1452
|
> Modules dedicated to the aforementioned preprint platforms are still under development and refinement. Preprint‑related subcommands are provided for testing purposes only. For detailed test cases, refer to [Cases](./docs/Cases.md)
|
|
1291
1453
|
|
|
1454
|
+
#### Preprint full-text fetch (Python API)
|
|
1455
|
+
|
|
1456
|
+
For preprints without an open-access PDF, each fetcher exposes a `fetch_full_text()` method that returns clean section-headed text without any PDF parsing:
|
|
1457
|
+
|
|
1458
|
+
```python
|
|
1459
|
+
from pyPaperFlow.preprint.arxiv_fetcher import ArxivFetcher
|
|
1460
|
+
from pyPaperFlow.preprint.biorxiv_fetcher import BioRxivFetcher
|
|
1461
|
+
from pyPaperFlow.preprint.europepmc_fetcher import EuropePMCFullText
|
|
1462
|
+
|
|
1463
|
+
# arXiv → ar5iv rendered HTML (LaTeX → HTML)
|
|
1464
|
+
arxiv = ArxivFetcher(root_dir="./papers")
|
|
1465
|
+
text = arxiv.fetch_full_text("1706.03762") # "" on failure
|
|
1466
|
+
|
|
1467
|
+
# bioRxiv / medRxiv → Europe PMC fullTextXML
|
|
1468
|
+
biorxiv = BioRxivFetcher(root_dir="./papers", platform="biorxiv")
|
|
1469
|
+
text = biorxiv.fetch_full_text("10.1101/2023.06.22.546069")
|
|
1470
|
+
|
|
1471
|
+
# Any DOI-indexed preprint → Europe PMC fullTextXML directly
|
|
1472
|
+
epmc = EuropePMCFullText()
|
|
1473
|
+
xml = epmc.full_text_xml("10.1101/2023.06.22.546069")
|
|
1474
|
+
epmc.close()
|
|
1475
|
+
```
|
|
1476
|
+
|
|
1477
|
+
All three return an empty string `""` on failure, so callers can gracefully fall back to the abstract. The returned text is section-headed (`## Section`) plain text ready for LLM input.
|
|
1478
|
+
|
|
1292
1479
|
### 6. Critical Reading and Knowledge Graph Analysis: Downstream End‑Use
|
|
1293
1480
|
|
|
1294
1481
|
Upon completing literature retrieval, parsing, and structured processing as outlined above, users obtain chapter‑organised Markdown files and structured JSON files, which serve as the fundamental inputs for subsequent critical reading and knowledge graph analysis.
|
|
@@ -1328,8 +1515,8 @@ You may directly run the test scripts to verify the correctness and completeness
|
|
|
1328
1515
|
<details>
|
|
1329
1516
|
<summary><b>3. Literature Acquisition (and Full‑Text Download)</b></summary>
|
|
1330
1517
|
|
|
1331
|
-
> - [
|
|
1332
|
-
> - [
|
|
1518
|
+
> - [x] Refine and encapsulate the `paper‑fetch` module. Refer to [2026‑05‑08 paper‑fetch Encapsulation](https://github.com/Agents365‑ai/paper‑fetch); evaluate integration or replacement with more robust modules offering higher hit rates.
|
|
1519
|
+
> - [x] The `pdf‑parse` module currently wraps basic MinerU parsing commands with the CPU backend (`‑b pipeline`). Future integration of GPU‑accelerated features; see [MinerU Repository](https://github.com/opendatalab/MinerU) for details.
|
|
1333
1520
|
|
|
1334
1521
|
</details>
|
|
1335
1522
|
|
|
@@ -1348,7 +1535,10 @@ You may directly run the test scripts to verify the correctness and completeness
|
|
|
1348
1535
|
<details>
|
|
1349
1536
|
<summary><b>5. Processing for Other Literature Databases</b></summary>
|
|
1350
1537
|
|
|
1351
|
-
> - [
|
|
1538
|
+
> - [x] Develop a unified `search‑fetch‑parse` pipeline for non‑PubMed databases and complete corresponding modules. Refer to open‑source implementations such as [paperscraper](https://github.com/jannisborn/paperscraper) and [paper‑tracker](https://github.com/RainerSeventeen/paper‑tracker).
|
|
1539
|
+
> - [ ] Multi‑source retrieval merge (primitive ready, orchestration pending): `preprint/source_merge.py` already provides `merge_papers` (backfill missing DOIs → dedupe by DOI, key cascade DOI → title+authors → source_id). The cross‑source orchestration command is not yet implemented; when adding a unified `search --sources arxiv,biorxiv,medrxiv,chemrxiv` that merges results into a single corpus, call `merge_papers` directly.
|
|
1540
|
+
> - [ ] Optional connectors (add on demand): skip a standalone Semantic Scholar metadata connector — it overlaps with the S2 usage inside `pdf_fetch.py` (`openAccessPdf`/`externalIds`), avoiding dual maintenance. Introduce an OpenAlex connector (`api.openalex.org/works`, inverted‑index abstract reconstruction + authors + citations/references) only when there is a concrete need for batch DOI‑based metadata completion or citation‑graph harvesting; emit `SourcePaper`.
|
|
1541
|
+
> - [ ] Infrastructure alignment (partially done): `extract_doi` unified into `source_merge.py`; `safe_filename` already present (`source_utils.py`); `get_env` deferred (mismatches the existing flat `os.environ.get` style); OAI‑PMH base class deferred until a generic OAI repository is actually integrated.
|
|
1352
1542
|
|
|
1353
1543
|
</details>
|
|
1354
1544
|
|