Skip to content

Add WikiDoc scraper - #12

Open
zndr27 wants to merge 3 commits into
MedARC-AI:mainfrom
zndr27:scraper/wikidoc
Open

Add WikiDoc scraper#12
zndr27 wants to merge 3 commits into
MedARC-AI:mainfrom
zndr27:scraper/wikidoc

Conversation

@zndr27

@zndr27 zndr27 commented Jul 26, 2026

Copy link
Copy Markdown

What this does

Adds a WikiDoc scraper to the datasets scraping pipeline. Same shape as the NICE scraper: discovery and extraction are separate, and everything outputs a normalized ScrapedDocument. WikiDoc is a MediaWiki instance, roughly 141k mainspace articles, so both discovery and extraction go through api.php rather than the rendered pages. list=allpages and action=parse are documented contracts that will not break when the site restyles.

Open question: should a document be a page or a topic?

WikiDoc splits some topics across a hub page plus roughly 30 sub-pages it calls microchapters. It is opt-in per topic, and the content sits in different places depending:

  • Sepsis: nav-only hub, content in the sub-pages
  • Hypertension: whole article on the hub (119k chars), stub sub-pages

One document per page, which is what this PR does, pulls in a lot of noise. About 17% of pages are under 500 characters, including placeholders like Meningitis MRI, whose entire body is "Please help WikiDoc by adding content here."

nice.py already handles the equivalent problem by merging chapters in build_guideline_text, so one document per page is arguably the deviation here.

I prototyped merging. WikiDoc declares the grouping itself: every page of a topic transcludes the same <Topic> Microchapters nav table, the one we already strip.

Topic NICE WikiDoc
Hypertension 97,167 (NG136) 119,099 (single page)
Tuberculosis 179,927 (NG33) 756,543 (merged, 31 pages)

Suggest merging to match nice.py, accepting that this source wants chunking at retrieval either way. Can implement it here. Did not want to decide the corpus shape unilaterally.

How discovery works

action=query&list=allpages, namespace 0, apfilterredir=nonredirects, 500 titles per request. MediaWiki paginates by an opaque apcontinue token rather than a page number, so list_page keeps the token in a closure and ignores the page argument it is handed.

About 1.5% of mainspace is user sandboxes and malformed titles, filtered on title. A few percent of pages are corrupt on WikiDoc's side and return HTTP 200 with {"error": {"info": "There is no revision with ID 388595"}} (also fails by pageid, so not a client issue). These are logged and skipped rather than aborting the run.

How extraction works

action=parse&prop=text|revid|categories|sections returns body, revision id, categories and sections in one request. disableeditsection=1 drops the [edit | edit source] markers.

WikiDoc's navigation templates ("WikiDoc Resources for X", "X Microchapters") are transcluded into the article, so the API returns them. All carry class="infobox" while content tables are wikitable or unclassed, so they are removed on that selector. Hypertension has 20 tables and exactly one infobox.

Editor bylines move to metadata.editors rather than heading every document. Metadata also records revid, categories and content_length_chars.

CLI

uv run amfv-scrape --source wikidoc --documents 1
uv run amfv-scrape --source wikidoc --url https://www.wikidoc.org/index.php/Sepsis_causes
uv run amfv-scrape --source wikidoc --documents 3 -f markdown -o ./wikidoc-out/

--source all now includes WikiDoc alongside NICE.

Licensing

CC BY-SA 3.0, confirmed from the API via meta=siteinfo&siprop=rightsinfo rather than a page footer. Recorded per document in metadata.license and metadata.editors.

Tests

uv run ruff check datasets
uv run ruff format --check datasets
uv run pytest datasets/test

37 tests, offline via httpx.MockTransport. Also scraped and read output for 10 pages across Sepsis, Hypertension, Endocarditis and Tuberculosis.

Notes for review

@CLAassistant

CLAassistant commented Jul 26, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

zndr27 added 2 commits July 25, 2026 18:32
WikiDoc is a MediaWiki instance, so discovery and extraction go through
api.php rather than the rendered pages: list=allpages is a documented
contract for enumerating articles, and action=parse returns the body,
revision id, categories and section list in one request.

Content is CC BY-SA 3.0, reported by the API itself via
action=query&meta=siteinfo&siprop=rightsinfo.

Notes on the source:

- The API does not remove WikiDoc's navigation templates ("WikiDoc
  Resources for X", "X Microchapters", "Resident Survival Guide") because
  they are transcluded into the article wikitext. They are consistently
  marked class="infobox" while real content tables are "wikitable" or
  unclassed, so they are stripped on that selector.
- "[edit | edit source]" markers are dropped with disableeditsection=1
  rather than post-processing.
- Mainspace contains ~1.5% non-articles (user sandboxes, titles with
  leading quote characters), filtered on title.
- Pagination is by opaque apcontinue token rather than page number, so
  list_page keeps the token in a closure and ignores the page argument.

Also cherry-picks the scrape_item -> ScrapedDocument | None change from
PR MedARC-AI#10 (RCH) verbatim, so identical changes merge cleanly whichever lands
first. WikiDoc needs it: a handful of pages are corrupt (Hypertelorism
reports "There is no revision with ID 388595") and one of them would
otherwise abort a run over 141k articles.
Every article opens with an "Editor-In-Chief: ...; Associate Editor(s)-In-Chief:
..." paragraph. It is authorship rather than clinical content, and it sits at the
top of the document where retrieval weights most heavily.

Keep it as metadata.editors so CC BY-SA attribution survives, but out of the
content body.
@zndr27
zndr27 force-pushed the scraper/wikidoc branch from a0b4121 to ae3c9ad Compare July 26, 2026 01:32
@zndr27
zndr27 marked this pull request as ready for review July 26, 2026 02:41
@zndr27 zndr27 changed the title Add WikiDoc scraper (draft — open question on document granularity) Add WikiDoc scraper Jul 28, 2026
WikiDoc articles are frequently a decade old - a random sample of 369
mainspace pages shows a median last edit around 2017 and only 4.6% edited
2021 or later - and the recorded revid is an opaque integer that cannot
tell you which. Recording the revision timestamp lets a corpus build
filter on recency later without re-scraping, the same reason
content_length_chars is already recorded.

Discovery switches from list=allpages to the same query as a generator
with prop=revisions, so the timestamp arrives in the request the listing
already makes. Pages whose latest revision is unreadable come back
without one; those are the corrupt pages _scrape_or_skip already drops.
A generator returns its pages unordered, so each batch is resorted by
title to keep --documents N reproducible.

The --url path builds a ref with no timestamp and looks one up; a full
listing run adds no requests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants