Skip to main content
To crawl and read pages in memory, see Crawl a website from a start URL. This recipe saves them to disk: every product, article or docs page of a section as its own .html file, named from its URL path, ready to archive, parse offline or load into another tool. Uses: Crawl with output_format, the download and contents endpoints, and Batch with response_type=markdown for markdown copies

Ask your AI agent

With the Zenrows MCP server connected to Claude, Cursor or any MCP client, paste this prompt. Your agent picks the right Zenrows tools and settings on its own.

Save the pages with the API

The download endpoint returns every page, HTML included, in one NDJSON file. The script writes each page to pages/, turning /ecommerce/product/aeon-capri/ into ecommerce_product_aeon-capri.html, so every file name is unique within the section.
Download once the crawl has ended, when every kept page reads content_status: fetched.

Save the pages from the CLI

--output-format html stores each kept page and --follow waits until the crawl ends. zenrows crawl content then writes each page to its own file. The script uses jq to read the results:
CLI
Output
To keep the whole section in one file instead, run zenrows crawl download <crawl_id> --out section.jsonl: each line holds a page’s url, content_status and HTML in content. See the CLI guide.

Example output

The Python (Requests) run:
The pages folder afterwards, with each file’s size in bytes:
The Node.js version saved the same five pages. File sizes can vary slightly from run to run.

Save markdown copies too

For an LLM, a search index or plain reading, save each page as markdown as well. Send the saved URLs to one Batch job with response_type=markdown:
Python (SDK)
Output
Each .md file holds the whole page as markdown, starting with the site’s navigation links. Batch saves the files in the order its tasks finish. To split the markdown into chunks for retrieval, see Build a RAG knowledge base from a website.

Customize it

Troubleshooting

  • Fewer files than pages in the section: include_patterns also decides which links Crawl opens. Add the path of the listing or pagination pages, such as /page/, and raise max_pages.
  • A result reads content_status: pending: the crawl is still fetching that page. Read the results after the crawl ends.
  • stop_reason is max_pages: each kept page’s HTML counts toward max_pages. Set max_pages to at least max_items plus the pages the crawl walks.
  • Two URLs save to the same file name: they differ only in their query string. Add the query to the name, for example urlparse(url).query, or exclude those URLs with exclude_patterns.
  • 429 with too_many_crawls: other Crawl and Batch jobs on your account are still running. Wait the number of seconds in the Retry-After header, then start the crawl again.

Crawl a website from a start URL

Crawl a site and read each page in memory, with the SDKs.

Build a RAG knowledge base from a website

Turn a crawled site into markdown chunks.

Map every URL on a website

List a site’s URLs before you save them.

Extract data with CSS selectors

Parse the saved HTML with BeautifulSoup or Cheerio.