Vous avez un DOI, la page de l'éditeur demande une connexion, et vous voulez seulement lire la section méthodes. Très souvent, une copie légale et gratuite existe quelque part : le dépôt de l'université de l'auteur, un preprint, PubMed Central. À la main, il faut essayer quatre ou cinq sites. En code, il suffit de quelques API publiques appelées dans le bon ordre.
L'ordre ci-dessous est celui du bouton View de l'espace Paper de l'application de bureau osFoundry, dont le backend essaie chaque source tour à tour jusqu'à obtenir un vrai PDF (la page de l'espace de rédaction et de recherche d'articles montre l'écran autour). Les exemples utilisent deux vrais DOI sur la même question : un téléphone posé sur le bureau nuit-il à la concentration ?
-
10.1037/tmb0000123, une méta-analyse de 2024 (Hartanto et al.) -
10.1086/691462, l'étude « Brain Drain » de 2017, très citée (Ward et al.)
Demander à OpenAlex tous les emplacements, pas seulement l'indicateur open access
OpenAlex liste chaque endroit où un article est hébergé et indique, pour chacun, s'il y a un PDF direct :
curl -s "https://api.openalex.org/works/doi:10.1037/tmb0000123?select=open_access,best_oa_location,locations"
Pour la méta-analyse, la requête renvoie trois emplacements : le lien PDF de l'éditeur, un PDF dans le dépôt de la James Cook University et une page d'accueil dans la bibliothèque de la Singapore Management University.
Pour l'article Brain Drain, la même requête affiche "is_oa": true et "oa_status": "green", pourtant tous les pdf_url valent null. La seule copie ouverte est une page de dépôt. Donc is_oa indique qu'une version gratuite existe quelque part, pas qu'on peut la télécharger. Lisez pdf_url sur chaque emplacement.
Sans clé d'API, les requêtes OpenAlex se partagent un petit budget quotidien gratuit avec tous ceux qui utilisent votre adresse IP, et le champ meta.notice de la réponse le précise. Une clé gratuite (api_key= dans la requête) vous donne votre propre budget, et l'application en lit une dans OPENALEX_API_KEY si vous la définissez.
Vérifier les cinq premiers octets
Un pdf_url n'est encore qu'une promesse. Les éditeurs renvoient des murs de cookies, des contrôles anti-bot et des pages de connexion avec un statut 200 et un corps HTML. Le code Rust de l'application n'accepte un téléchargement que si le corps commence par le nombre magique du PDF :
if !fetched.bytes.starts_with(b"%PDF-") {
self.tried.push(format!("{source}: link was a web page, not a PDF"));
return None;
}
La même idée en Python, avec la seule bibliothèque 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"]))
Sur la méta-analyse, le lien de l'éditeur a refusé le script et la copie du dépôt est revenue sous forme d'un PDF de 1,6 Mo. Sur Brain Drain, le script échoue aussitôt avec « no pdf_url at all ». Garder la liste de ce qui a été essayé et de la raison de l'échec vaut les quelques lignes en plus ; un simple « pas de texte intégral » vous renvoie à la recherche manuelle.
La limite de quatre liens par recherche et la déduplication des URL viennent aussi de l'application. Certains articles ont une douzaine d'emplacements qui pointent tous vers le même fichier.
Le reste de la chaîne
La requête OpenAlex n'est qu'une étape. L'ordre complet de l'application :
- Le lien PDF fourni avec le résultat de recherche, s'il y en avait un.
- arXiv. Un DOI de la forme
10.48550/arXiv.<id>est un article arXiv, ethttps://arxiv.org/pdf/<id>est toujours gratuit. - Les copies ouvertes du DOI, via Unpaywall ou OpenAlex. Unpaywall (
https://api.unpaywall.org/v2/<doi>?email=<your email>) renvoiebest_oa_location.url_for_pdfet une listeoa_locations, et refuse les requêtes sans véritable adresse e-mail. Les deux services viennent de la même organisation à but non lucratif, OurResearch ; l'application interroge donc Unpaywall quandUNPAYWALL_EMAILest défini et lit sinon les emplacements d'OpenAlex, jamais les deux. - CORE. Son API v3 (
/v3/search/works?q=doi:"<doi>", avec une clé bearer) agrège des copies de dépôts et renvoie souvent le texte extrait directement dansfullText. L'application garde ce texte s'il dépasse 500 caractères, sinon elle essaie ledownloadUrl. - PubMed Central. Avec un PMCID, Europe PMC fournit l'article complet en XML JATS à l'adresse
https://www.ebi.ac.uk/europepmc/webservices/rest/<PMCID>/fullTextXML. Ce n'est pas un PDF, mais les sections, figures et références y sont structurées de façon à se convertir proprement en HTML.
Les résumés arrivent sous forme d'index inversé
Un dernier détail d'OpenAlex qui piège souvent : il n'y a pas de champ abstract. On reçoit abstract_inverted_index, une table qui associe chaque mot aux positions où il apparaît, et il faut reconstruire le texte soi-même :
words = {pos: w for w, positions in idx.items() for pos in positions}
abstract = " ".join(words[i] for i in sorted(words))
Cela suffit pour les résultats de recherche et le tri. Pour l'article Brain Drain, dont la seule copie ouverte est une page de dépôt, le résumé plus le texte intégral de la méta-analyse, c'est à peu près tout ce que permet la voie gratuite, et c'est généralement le moment de vérifier si votre bibliothèque a accès à l'article.

Top comments (0)