CrawlSage 0.2.0

dotnet add package CrawlSage --version 0.2.0
                    
NuGet\Install-Package CrawlSage -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CrawlSage" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CrawlSage" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="CrawlSage" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CrawlSage --version 0.2.0
                    
#r "nuget: CrawlSage, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CrawlSage@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CrawlSage&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=CrawlSage&version=0.2.0
                    
Install as a Cake Tool

CrawlSage

An F#-first web crawling & scraping framework for .NET.

CI Docs NuGet License: MIT Status .NET

CrawlSage — scrape a list and write a CSV in one command


What it is

CrawlSage is a web crawling and scraping framework designed around F# idioms — records and discriminated unions for data, option over null, and |> pipelines for behaviour. It pairs a full crawl engine (request queue, dedup, scheduler, item pipelines) with a resilient downloader, a concise HTML selector DSL, and first-class politeness.

Two principles shape it:

  • Don't render — extract. Most "dynamic" pages ship their data as embedded JSON. CrawlSage lifts that state directly, so the core needs no browser.
  • Polite by default. robots.txt, per-host pacing, retries and back-off are built into the engine, not bolted on.

Features

  • Resilient downloader — retry with back-off + jitter, per-request timeout, concurrency throttling, gzip/brotli decompression, and correct text encoding (honours a page's <meta> charset, so EUC-KR / Shift_JIS / GBK pages don't turn into mojibake) — composed as wrappers around one HttpClient.
  • Parsing & links — forgiving, option-returning CSS and XPath selectors, plus a link extractor and URL canonicalisation for dedup and same-host filtering.
  • Spider engine — a frontier-driven scheduler with dedup, depth bounding, an item pipeline, per-page fault tolerance, and a CrawlEvent hook for stats / logging.
  • Resumable & bounded crawls — swap the frontier for a disk-backed one (resume after a stop or crash) or a memory-capped one, with zero engine changes.
  • Dynamic data, no browser — pull __NEXT_DATA__, JSON-LD and object/array globals out of the page, or replay the JSON API; an opt-in CrawlSage.Browser (Playwright) adapter renders the rest.
  • Politeness & rotationrobots.txt (per-host cache + Crawl-delay), per-host pacing, honest User-Agent / proxy rotation, and sitemap.xml discovery.
  • SSRF guard (opt-in)Safety.publicOnly refuses links that resolve to loopback, private or link-local addresses (incl. cloud-metadata 169.254.169.254), so crawling an untrusted link graph can't be steered into your internal network.
  • Sessions — a cookie-jar session for form login, saved and restored across runs.
  • Output — JSON / JSON Lines / CSV / data-frame sinks for items, plus binary file downloads.
  • Declarative & host-ready — describe a crawl with the spider { } computation expression, and embed CrawlSage in a .NET host via the opt-in CrawlSage.Extensions package (Microsoft.Extensions.Logging + dependency injection, IHttpClientFactory-backed).

Status

v0.1.2 — beta. Feature-complete for everyday crawling: resilient downloader, parsing DSL, spider engine, embedded-JSON extraction, export sinks, politeness, sessions, sitemaps, and an opt-in browser renderer. Targets .NET 8 and .NET 10.


Install

dotnet add package CrawlSage

Targets .NET 8 and .NET 10. For pages that truly render client-side, add the opt-in CrawlSage.Browser (Playwright) package; to host CrawlSage in a .NET app (logging + DI), add CrawlSage.Extensions.


Quick start

# Build from source with the .NET 10 SDK (the package itself targets net8.0 and net10.0)
dotnet build CrawlSage.slnx
dotnet test  CrawlSage.slnx

A minimal fetch:

open CrawlSage

let body =
    Request.create "https://example.com"
    |> Request.withHeader "Accept-Language" "en"
    |> Http.fetch
    |> Async.RunSynchronously

printfn "%d — %d bytes" body.StatusCode body.Body.Length

Pull a list of fields with the selector DSL:

open CrawlSage

let authors =
    Http.getString "https://quotes.toscrape.com/"
    |> Async.RunSynchronously
    |> Html.parse
    |> Html.selectAll ".quote .author"
    |> List.map Html.text

Or describe a whole crawl declaratively with the spider { } builder:

open CrawlSage

let crawler =
    spider {
        seed "https://quotes.toscrape.com/"
        parse parseQuotes
        pipeline (Export.appendJsonLine "data/quotes.jsonl")
        maxDepth 3
    }

Spider.crawl crawler |> Async.RunSynchronously

Full crawlers — extract a list, follow pagination, lift embedded JSON, rotate User-Agents — are runnable under samples/, each polite by default.

Detailed usage: the Guide documents the full API, module by module — Http, Html, Extract, Spider, Session, Frontier, and the rest.


Project layout

CrawlSage/
├── src/CrawlSage/            # the framework library (browser-free core)
│   ├── Types.fs              #   Request / Response / Renderer / Sink
│   ├── Url.fs                #   resolve · canonicalise · same-host
│   ├── Http.fs               #   the downloader (shared HttpClient, gzip, bytes/download)
│   ├── Resilience.fs         #   retry · back-off · timeout · throttle
│   ├── Rotation.fs           #   honest UA & proxy rotation
│   ├── Session.fs            #   cookie-jar session (login, save/load)
│   ├── Html.fs               #   CSS selector DSL + link extraction
│   ├── Extract.fs            #   embedded-state / JSON extraction (no browser)
│   ├── Robots.fs             #   robots.txt parse · per-host cache · per-host pacing
│   ├── Sitemap.fs            #   sitemap.xml / sitemapindex discovery
│   ├── Frontier.fs           #   in-memory · bounded · persistent (resumable) frontier
│   ├── Spider.fs             #   crawl engine (frontier · dedup · depth · pipeline · stats)
│   ├── SpiderBuilder.fs      #   the spider { } computation expression
│   └── Export.fs             #   sinks: JSON / JSONL / CSV / data frames + saveBytes
├── src/CrawlSage.Browser/    # opt-in JS renderer (Playwright) — not a core dependency
├── src/CrawlSage.Extensions/ # opt-in Microsoft.Extensions logging + DI integration
├── tests/                    # xUnit test projects (core · browser · extensions)
├── samples/                  # runnable, self-contained crawlers
└── docs/                     # documentation site

License

MIT.

Please crawl responsibly. Respect robots.txt, rate limits, a site's Terms of Service, and applicable law. CrawlSage is a tool; how you use it is your responsibility.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on CrawlSage:

Package Downloads
CrawlSage.Browser

Opt-in Playwright-backed browser renderer for CrawlSage — renders client-side pages the browser-free core can't, behind the same Renderer seam.

CrawlSage.Extensions

Opt-in Microsoft.Extensions integration for CrawlSage — bridge crawl events to ILogger and resolve an IHttpClientFactory-backed renderer via dependency injection (services.AddCrawlSage()).

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 134 6/26/2026
0.1.2 122 6/23/2026
0.1.1 98 6/21/2026
0.1.0 116 6/20/2026 0.1.0 is deprecated because it is no longer maintained.

0.2.0 adds the spider { } computation expression, the opt-in CrawlSage.Extensions package (Microsoft.Extensions.Logging + dependency injection, IHttpClientFactory), correct text encoding (honours a page's <meta> charset for EUC-KR/Shift_JIS/GBK), an opt-in SSRF guard (Safety.publicOnly), and XPath selectors. Multi-targets .NET 8 and .NET 10. Core: resilient downloader (retry/back-off/timeout/throttle, gzip/brotli, binary downloads), HTML CSS + XPath selectors + link extraction, URL canonicalisation, embedded-JSON extraction, frontier-driven spider engine (dedup, depth, resumable/bounded frontiers, crawl stats, per-page fault tolerance), robots.txt + per-host pacing, UA/proxy rotation, sitemap discovery, cookie-jar sessions, and JSON/JSONL/CSV/data-frame export. Opt-in Playwright rendering via the separate CrawlSage.Browser package.