DEV Community

Cover image for Come trovare il PDF gratuito di un articolo scientifico partendo dal DOI

Come trovare il PDF gratuito di un articolo scientifico partendo dal DOI

Hai un DOI, la pagina dell'editore chiede il login e a te serve solo leggere la sezione dei metodi. Molto spesso esiste da qualche parte una copia legale e gratuita: il repository dell'università dell'autore, un preprint, PubMed Central. A mano bisogna provare quattro o cinque siti. In codice bastano poche API pubbliche chiamate in un ordine sensato.

L'ordine qui sotto è quello del pulsante View nello spazio di lavoro Paper dell'app desktop osFoundry, il cui backend prova ogni fonte a turno finché una restituisce un vero PDF (la pagina dello spazio di lavoro per scrivere e ricercare articoli mostra la schermata intorno). Gli esempi usano due DOI reali sulla stessa domanda: un telefono appoggiato sulla scrivania danneggia la concentrazione?

  • 10.1037/tmb0000123, una meta-analisi del 2024 (Hartanto et al.)
  • 10.1086/691462, il molto citato studio «Brain Drain» del 2017 (Ward et al.)

View su un risultato di ricerca apre il testo della meta-analisi dentro l'app

Chiedi a OpenAlex tutte le posizioni, non solo il flag open access

OpenAlex elenca ogni posto in cui un articolo è ospitato e, per ciascuno, se c'è un PDF diretto:

curl -s "https://api.openalex.org/works/doi:10.1037/tmb0000123?select=open_access,best_oa_location,locations"
Enter fullscreen mode Exit fullscreen mode

Per la meta-analisi restituisce tre posizioni: il link al PDF dell'editore, un PDF nel repository della James Cook University e una landing page nella biblioteca della Singapore Management University.

Per l'articolo Brain Drain la stessa richiesta mostra "is_oa": true e "oa_status": "green", ma ogni pdf_url è null. L'unica copia aperta è la landing page di un repository. Quindi is_oa dice che una versione gratuita esiste da qualche parte, non che puoi scaricarla. Leggi pdf_url su ogni posizione.

Senza chiave API, le richieste a OpenAlex condividono un piccolo budget giornaliero gratuito con tutti quelli che usano il tuo indirizzo IP, e meta.notice nella risposta lo segnala. Una chiave gratuita (api_key= nella query) ti dà un budget tuo, e l'app ne legge una da OPENALEX_API_KEY se la imposti.

Controlla i primi cinque byte

Anche un pdf_url è solo una promessa. Gli editori restituiscono muri di cookie, controlli anti-bot e pagine di login con stato 200 e corpo HTML. Il codice Rust dell'app accetta un download solo se il corpo inizia con il magic number del PDF:

if !fetched.bytes.starts_with(b"%PDF-") {
    self.tried.push(format!("{source}: link was a web page, not a PDF"));
    return None;
}
Enter fullscreen mode Exit fullscreen mode

La stessa idea in Python, con la sola libreria standard:

import json
import urllib.error
import urllib.request

UA = {"User-Agent": "paper-finder/1.0"}

def get(url):
    with urllib.request.urlopen(urllib.request.Request(url, headers=UA), timeout=30) as r:
        return r.read()

def pdf_links(doi):
    try:
        work = json.loads(get(f"https://api.openalex.org/works/doi:{doi}"
                              "?select=best_oa_location,locations"))
    except urllib.error.HTTPError as e:
        if e.code == 404:
            return []
        raise
    links = []
    for loc in [work.get("best_oa_location")] + work.get("locations", []):
        url = (loc or {}).get("pdf_url")
        if url and url not in links:
            links.append(url)
    return links

def first_real_pdf(doi):
    tried = []
    for url in pdf_links(doi)[:4]:
        try:
            body = get(url)
        except (urllib.error.URLError, TimeoutError) as e:
            tried.append(f"{url}: {e}")
            continue
        if body[:5] == b"%PDF-":
            return url, body
        tried.append(f"{url}: a web page, not a PDF")
    raise LookupError("no free PDF; tried: " + "; ".join(tried or ["no pdf_url at all"]))
Enter fullscreen mode Exit fullscreen mode

Sulla meta-analisi il link dell'editore ha rifiutato lo script e la copia del repository è arrivata come PDF da 1,6 MB. Su Brain Drain fallisce subito con «no pdf_url at all». Tenere l'elenco di cosa è stato provato e perché è fallito vale le righe in più; un semplice «nessun testo completo» ti rimanda a fare tutto a mano.

Anche il limite di quattro link per ricerca e la deduplicazione degli URL vengono dall'app. Alcuni articoli hanno una dozzina di posizioni che puntano tutte allo stesso file.

Il resto della catena

La ricerca su OpenAlex è solo un passo. L'ordine completo dell'app:

  1. Il link al PDF arrivato con il risultato di ricerca, se c'era.
  2. arXiv. Un DOI del tipo 10.48550/arXiv.<id> è un articolo arXiv, e https://arxiv.org/pdf/<id> è sempre gratuito.
  3. Le copie aperte del DOI, da Unpaywall o da OpenAlex. Unpaywall (https://api.unpaywall.org/v2/<doi>?email=<your email>) restituisce best_oa_location.url_for_pdf e un elenco oa_locations, e rifiuta le richieste senza un indirizzo e-mail vero. I due servizi sono della stessa organizzazione non profit, OurResearch, quindi l'app interroga Unpaywall quando UNPAYWALL_EMAIL è impostata e altrimenti legge le posizioni di OpenAlex, mai entrambi.
  4. CORE. La sua API v3 (/v3/search/works?q=doi:"<doi>", con una chiave bearer) aggrega copie dai repository e spesso restituisce direttamente il testo estratto in fullText. L'app usa quel testo se supera i 500 caratteri, altrimenti prova il downloadUrl.
  5. PubMed Central. Con un PMCID, Europe PMC serve l'articolo intero come XML JATS all'indirizzo https://www.ebi.ac.uk/europepmc/webservices/rest/<PMCID>/fullTextXML. Non è un PDF, ma ha sezioni, figure e riferimenti in una struttura che si converte bene in HTML.

Gli abstract arrivano come indice invertito

Un ultimo dettaglio di OpenAlex su cui si inciampa spesso: non esiste un campo abstract. Si riceve abstract_inverted_index, una mappa da ogni parola alle posizioni in cui compare, e il testo va ricostruito da soli:

words = {pos: w for w, positions in idx.items() for pos in positions}
abstract = " ".join(words[i] for i in sorted(words))
Enter fullscreen mode Exit fullscreen mode

Basta per i risultati di ricerca e per una prima selezione. Per l'articolo Brain Drain, la cui unica copia aperta è una pagina di repository, l'abstract più il testo completo della meta-analisi è circa il massimo a cui arriva la via gratuita, ed è di solito il momento di controllare se la tua biblioteca ha accesso.

Top comments (0)