Collect real web data with Zenrows, validate it, and format it into fine-tuning pairs for extraction, preference, and domain-continuation training.
- Fetches clean Markdown and structured JSON from web pages using the Zenrows API
- Validates extracted data against a JSON schema, dropping empty extractions, schema mismatches, and duplicates before they reach the training set
- Formats validated pairs into instruction-output (SFT) and domain-continuation fine-tuning formats
- Fetches and extracts text from PDF sources, including the
js_renderrequirement PDF mode needs - Chunks long PDF documents by page for use in fine-tuning pairs
- Tracks source URL, retrieval date, and license per record for auditability
- Python 3.9 or later
- A Zenrows API key
git clone https://github.com/ZenRows/web-data-for-llm-fine-tuning.git
cd web-data-for-llm-fine-tuningpython -m venv .venv# macOS/Linux
source .venv/bin/activate
# Windows
.venv\Scripts\activatepip install -r requirements.txtCreate a .env file in the project root:
ZENROWS_API_KEY=your_zenrows_api_key
.
├── validate.py # Collect + validate one HTML source into training_data.jsonl
├── domain.py # Same as validate.py, plus a domain-continuation example
├── pdf.py # Basic PDF fetch
├── pdf_2.py # PDF fetch with retry and timeout handling
├── pdf_chunking.py # PDF fetch + page-based chunking
├── pdf_metadata.py # PDF fetch + license lookup + provenance metadata
├── training_data.jsonl # Output: formatted fine-tuning pairs
├── requirements.txt
└── README.md
Source URL
↓
Zenrows Fetch (Markdown for pages, PDF for documents)
↓
Zenrows Extract (CSS schema, HTML sources only)
↓
Validation (schema check, length check, duplicate check)
↓
Formatted fine-tuning pair (JSONL)
For HTML sources, validate.py fetches the page twice: once for Markdown (the training input), once with a CSS extraction schema for structured JSON (the training label). Both are checked with keep() before being written out. For PDF sources, pdf.py and its variants fetch the raw file and extract text with pypdf as a separate step, since Zenrows returns the file, not its contents.
python3 validate.py # collect + validate a single HTML source
python3 domain.py # same, plus a domain-continuation example
python3 pdf.py # fetch a PDF source
python3 pdf_2.py # fetch a PDF source with retry/timeout handling
python3 pdf_chunking.py # fetch a PDF and split it into page-based chunks
python3 pdf_metadata.py # fetch a PDF plus its license from the source's landing pageEach script is standalone. Swap the urls list and css_schema in validate.py/domain.py for your own target site — selectors are site-specific and won't carry over as-is.
training_data.jsonl— one JSON object per line, each withmessages(system instruction, page content, extracted JSON)who-clinical-trials-guidance.pdf/public-health-references.pdf— PDF files saved locally by the PDF scripts- Console output reporting how many candidates were collected versus how many passed validation
- Python
- Zenrows
- jsonschema
- pypdf
- python-dotenv
- requests
- priceoye.pk — e-commerce product pages (HTML extraction example)
- WHO clinical trials guidance — CC BY-NC-SA 3.0 IGO (PDF example)
- CDC public health references — U.S. federal publication, public domain (PDF example)
This repository accompanies this blog: Web Data for LLM Fine-Tuning: A Practical 2026 Guide