CrawlSage 0.2.0
dotnet add package CrawlSage --version 0.2.0
NuGet\Install-Package CrawlSage -Version 0.2.0
<PackageReference Include="CrawlSage" Version="0.2.0" />
<PackageVersion Include="CrawlSage" Version="0.2.0" />
<PackageReference Include="CrawlSage" />
paket add CrawlSage --version 0.2.0
#r "nuget: CrawlSage, 0.2.0"
#:package CrawlSage@0.2.0
#addin nuget:?package=CrawlSage&version=0.2.0
#tool nuget:?package=CrawlSage&version=0.2.0
CrawlSage
An F#-first web crawling & scraping framework for .NET.
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 oneHttpClient. - 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
CrawlEventhook 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-inCrawlSage.Browser(Playwright) adapter renders the rest. - Politeness & rotation —
robots.txt(per-host cache +Crawl-delay), per-host pacing, honest User-Agent / proxy rotation, andsitemap.xmldiscovery. - SSRF guard (opt-in) —
Safety.publicOnlyrefuses links that resolve to loopback, private or link-local addresses (incl. cloud-metadata169.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-inCrawlSage.Extensionspackage (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 | Versions 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. |
-
net10.0
- AngleSharp (>= 1.5.1)
- AngleSharp.XPath (>= 2.0.6)
- CsvHelper (>= 33.1.0)
- Deedle (>= 3.0.0)
- FSharp.Core (>= 10.1.301)
- Polly (>= 8.7.0)
-
net8.0
- AngleSharp (>= 1.5.1)
- AngleSharp.XPath (>= 2.0.6)
- CsvHelper (>= 33.1.0)
- Deedle (>= 3.0.0)
- FSharp.Core (>= 10.1.301)
- Polly (>= 8.7.0)
- System.Text.Encoding.CodePages (>= 10.0.9)
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.
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.