forrtproject / forrtproject/flora-extractor

Full-text acquisition: five routes measured to work that the waterfall does not try

Open
#188 2 comments 0 reactions 0 assignees View on GitHub
stage-3
Dominant language
Python
Stars
2
Forks
1
Avg merge
1d 6h
Merged PRs (30d)
4

Description

Follow-up to the acquisition fixes of 2026-08-08 (commit a0ff034: the `row_url` tier, the two request identities, Word documents, the OSF preprint pattern).

Thirty works that Stage 3 acquired nothing for were investigated by hand against live servers. **25 of the 30 turned out to be obtainable**, 2 were genuinely paywalled, 1 was a dead link, and 2 were code/data deposits with no manuscript to code. The waterfall got essentially none of them.

Two of the routes found — DataCite metadata, and walking every OA location rather than the first — are basic enough that they are being implemented directly rather than tracked here. The five below are the remainder.

## 1. Crossref bibliographic title search → OA or preprint copy

The highest value per unit cost of anything found, and the only route that helps a row with **no DOI at all**.

https://api.crossref.org/works?rows=5&query.bibliographic=

Take any `10.31234/*` (PsyArXiv) or open-access container from the results, then read `citation_pdf_url` off its landing page. It beat Unpaywall on every row where both were tried, because Unpaywall knew only the publisher copy and the publisher was Cloudflare-walled.

It also repairs dead links: CiteSeerX is dead corpus-wide and several Ghent `biblio` ids in this data are stale, and in both cases the title search recovered a live DOI.

Free. Fixed 4 of the 30.

## 2. Legacy DSpace REST and OAI-PMH, which sit outside the bot walls

On EconStor the HTML site, the `/bitstream/` path and the DSpace 7 `/server/api` path were all walled, while these two answered plain curl:

https://<host>/rest/handle/<prefix>/<id>?expand=bitstreams -> retrieveLink
https://<host>/oai/request?verb=GetRecord&metadataPrefix=didl&identifier=oai:<host>:<prefix>/<id>

Generalises across the EconStor/RePEc economics segment, which is a substantial share of this corpus's repository rows. Free, no browser needed.

## 3. Unpaywall green locations must be scraped, not read

When a location has `url_for_pdf: null` but `host_type: "repository"`, the PDF is on the landing page, not in the API response. Fetch `url_for_landing_page`, take the on-page `/bitstream/handle/...?sequence=1&isAllowed=y` href — not the `citation_pdf_url` meta value, which 403'd — and send a `Referer` header. One extra request; these rows are currently dropped.

## 4. EPrints and Figshare landing patterns

- EPrints: landing page → the single `href` under `/<id>/<n>/*.pdf`, or the `citation_pdf_url` meta tag.
- Figshare: `https://api.figshare.com/v2/articles/<id>` where `<id>` is the numeric tail of the DataCite DOI → `files[].download_url`. Covers every Figshare-backed institutional repository.

## 5. A headless-browser document tier for JS-challenge hosts

Some repositories serve the file only after a JavaScript challenge completes — Anubis proof-of-work, AWS WAF. A real browser engine passes these by doing the work the page asks for; no CAPTCHA is solved and no credential is used. This is the only route to a whole class of DSpace 7 and Figshare repositories.

Costs ~15-30 s and ~200 MB RAM per document, so it belongs at the bottom of the waterfall, below every HTTP route.

Note for whoever implements it: the existing `playwright` tier is the natural home, but it must NOT present a browser User-Agent to Anubis-protected hosts, which is what caused the failures fixed in a0ff034.

## Two things worth knowing before implementing any of this

**A server can return the wrong paper for the right URL.** Two fetches of one PLOS printable URL returned two different papers. A document-identity check is being added separately; do not add a route without it.

**Some rows are not fixable by any route**, and the correct outcome is to record that: a Zenodo deposit of R code with no manuscript, a conference abstract with no full text in existence, a master's thesis whose file was never deposited. There are also corpus metadata errors — dead `url_r` values and at least one `journal_r` naming the wrong university.

## Measured summary of the 30

| outcome | n |
| ------- | -: |
| obtainable by a route above | 25 |
| genuinely paywalled (institutional access is the answer) | 2 |
| dead link, file never deposited | 1 |
| data/code deposit, no manuscript exists | 2 |

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading the existing acquisition waterfall and its Playwright tier, then review the separate document-identity check before adding any route. Implement and validate the Crossref, DSpace/OAI-PMH, Unpaywall, EPrints/Figshare, and browser routes in their stated order, with the browser tier last; done means the measured repository patterns are covered without accepting the wrong paper.

Written by the indexing model from the issue text.

Assessment

Tech stack
playwright, python
Domain
backend, data-engineering
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.