Add MAGIC scraper - #14
Open
MrKoga wants to merge 2 commits into
Open
Conversation
Scrapes MAGICapp (app.magicapp.org), the GRADE publishing platform, into normalized corpus documents: 45 publishers, 225 English guidelines, 35.5M characters. Discovery and rendering go through MAGICapp's public JSON API; recommendations and evidence questions render with their strength, certainty and effect estimates; front and back matter, rosters, and personal data are removed, with per-guideline exceptions recorded beside the rule that decided each one.
MrKoga
force-pushed
the
add-magic-scraper
branch
from
August 11, 2026 11:09
3e28147 to
bcd3093
Compare
MrKoga
marked this pull request as ready for review
August 11, 2026 11:10
…ipeline stage The scraper now ships as two files: magic.py holds the logic, laid out in the order the pipeline runs (catalogue access, HTML repair, conversion and cleanup, keep/drop policy, recommendation and PICO rendering, assembly, API), and magic_rules.py holds the per-guideline and per-publisher keep/drop tables - data, not logic, keys and entries sorted for lookup. Comments and docstrings pared to what the code cannot say itself. Tests reorganized into the same sections. Renames for self-explanation: _https -> _force_https, _number -> _plain_number, _render_scripts -> _render_super_subscripts. Zero behavior change: all 225 rendered documents byte-identical before and after, content and metadata; 233 tests pass; ruff clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Adds a MAGICapp scraper to the datasets scraping pipeline. Same shape as the NICE scraper — everything outputs a normalized
ScrapedDocument, every network-touching function takesclient: httpx.Clientfirst, and the CLI gains amagicsource.MAGICapp is the GRADE-methodology publishing platform: 45 organizations publish through it — WHO, Stroke Foundation of Australia, Cancer Council Australia, the European Stroke Organisation, BMJ Rapid Recommendations and others — each with its own formats and nuances. The full catalogue holds 461 guidelines; after dropping non-English entries and training accounts, 233 remain, of which 225 render into the corpus.
Meditron lists MAGIC as a source; its scraper drives the single-page app with Selenium and is marked
UNTESTEDin the source. MAGICapp has a public unauthenticated JSON API, so this replaces that approach rather than porting it.How discovery works
Unlike the HTML sources there is no listing page to parse: one catalogue request returns every published guideline with its metadata, and each entry links the full guideline as structured JSON — a section tree with recommendation and PICO objects. Eight catalogue entries are excluded as the result of the publisher's own words: consultation drafts, a demonstration guideline whose text disclaims clinical use, archived modules, and sub-400-character placeholders.
How extraction works
The guideline JSON renders to one markdown document per guideline. Recommendation objects render as headings carrying the publisher's own label plus GRADE strength and certainty, with the panel's rationale and evidence-to-decision judgments as labelled blocks beneath; evidence questions render with their population/intervention/comparator and one line per outcome (effect measure, 95% CI, participants, studies, certainty) — numbers that exist only as data fields and would otherwise be lost. Section bodies are HTML fragments and go through the shared
html_to_markdownhelper.Because the corpus feeds a claim verifier, the test for every span is whether a medical claim could rest on it.
Section-level drops are decided by heading rules backed by body-reading guards — a section whose subtree holds a recommendation object, a GRADE evidence table, a scope statement, or a finding of absence is kept whatever its heading says. Where a general rule would be wrong for one specific guideline, that guideline gets an exception entry keyed to its ID in
magic_rules.py— a data module holding all the per-guideline and per-publisher tables, kept apart from the scraper logic so each can be reviewed on its own terms.The rendered corpus is 35.5M characters across the 225 documents (median 83k, largest 1.8M — WHO's task-shifting guideline).
Open question: Useful data threshold
Each organization that drafts guidelines in this corpus enters information into the MAGIC database in slightly different ways. Some use recommendation blocks while others use plain prose; some tables include useful clinical information, others mix clinical data with process information. The result is that individual guidelines end up needing many specific organization and document level fixes which are difficult to process at scale and brittle in the event of future changes. I've tried to remove much of the non-clinical information but in some cases I've erred on the side of keeping some non-clinical information in order to keep verification worthy information. Admittedly, some clinical data is also lost, but by and large the error is the other way around. If it's found that too much noise has been entered into the database or conversely if certain verification worthy text has been omitted I am happy to refine further.
CLI
--documentsis an upper bound on a catalogue run: unreadable or placeholder guidelines are logged and skipped.--documents allscrapes the whole catalogue and takes roughly 30-45 minutes — a politeness delay of 5 seconds sits between document requests.--include-draftskeeps guidelines whose own title marks them a draft for consultation; they are dropped by default.--urlaccepts anyapp.magicapp.orglink containing/guideline/<code>; the code is resolved against the catalogue.Files
datasets/amfv_datasets/scraping/magic.py— the scraper, laid out as the pipeline runs: catalogue access, HTML repair, conversion and cleanup, keep/drop policy, recommendation and PICO rendering, assembly, APIdatasets/amfv_datasets/scraping/magic_rules.py— the per-guideline and per-publisher keep/drop tables (data, not logic; keys and entries sorted for lookup)datasets/amfv_datasets/scraping/cli.py—--source magicdispatch and--include-draftsdatasets/amfv_datasets/scraping/__init__.py— public namesdatasets/test/test_scraping_magic.py— offline tests,MockTransport, no fixture files; sections mirror magic.py's layoutdatasets/test/test_scraping_cli.py— the new flagTest plan
uv run pytest datasets/test— 233 passed, no regressionsuv run ruff check datasets/ && uv run ruff format --check datasets/magic.py+magic_rules.pyand the accompanying cleanup were verified the same way: all 225 documents byte-identical before and after, content and metadata--urlrun, and a 3-document run, including a guideline published after the rules were writtenTo reproduce quickly:
uv run amfv-scrape --source magic --documents 3 -f markdown -o /tmp/magic-out/Known limitations
languages=parameter exists; the 218 non-English guidelines are skipped).html.py.