ccrawl-cli

module
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: Apache-2.0

README

ccrawl

A fast, friendly command line for Common Crawl. One binary that finds pages in the URL index, fetches the exact bytes Common Crawl saw, streams WARC/WAT/WET archives, queries the columnar Parquet index, looks up domain ranks, and builds datasets.

ccrawl resolving the latest crawl, reading a page as text, searching the URL index, and generating columnar SQL

Full documentation: ccrawl-cli.tamnd.com.

What is Common Crawl

Common Crawl is a nonprofit that has been crawling the web since 2008 and publishes the result as a free, openly licensed dataset. Every month or so it releases a new crawl of billions of pages, hosted on data.commoncrawl.org and mirrored in Amazon S3. There are no API keys and nothing to pay for, you just need to know where to look.

That last part is the catch. Using the data by hand means juggling the CDX index API, S3 paths, multi-member gzip WARC files, and a pile of glue code. ccrawl puts all of it behind one tool with sane defaults, real output formats, and commands that pipe into each other.

[!IMPORTANT] This project is an independent client. It is not affiliated with or endorsed by the Common Crawl Foundation. Please read and follow the Common Crawl terms of use when you use the data.

Install

go install github.com/tamnd/ccrawl-cli/cmd/ccrawl@latest

Or grab a prebuilt binary from the releases page. The binary is pure Go with no runtime dependencies. DuckDB is optional and only needed to run the columnar index queries locally (see Bulk questions).

Build from source:

git clone https://github.com/tamnd/ccrawl-cli
cd ccrawl-cli
make build      # produces ./bin/ccrawl

Quick start

ccrawl crawls latest                  # newest crawl ID, for example CC-MAIN-2026-25
ccrawl get example.com --text         # the readable text of the latest capture
ccrawl get example.com --markdown     # the same page as Markdown
ccrawl search 'example.com/*'         # every capture under a path
ccrawl search 'example.com/*' -o url  # just the URLs, one per line

Run ccrawl <command> --help for the full flag list on any command. Every command speaks the same global flags, so -o, -c, -n, and --fields work everywhere.

[!TIP] ccrawl is built to compose. Any command that lists records can pipe into another, so search finds captures, fetch pulls their bytes, and a shell pipe (|) is the glue.

Find a page: get

get is curl for Common Crawl. It resolves the newest capture of a URL in the index, pulls that one record with an HTTP byte-range request, and prints what Common Crawl saw.

ccrawl get example.com                # the captured HTML
ccrawl get example.com --text         # readable plain text
ccrawl get example.com --markdown     # HTML converted to Markdown
ccrawl get example.com --headers      # the captured HTTP response headers
ccrawl get example.com --links -o url # outbound links, one per line
ccrawl get example.com --at 2023-06   # the capture nearest a date
ccrawl get example.com --all -o jsonl # every capture across crawls

The extract subcommands are shortcuts for a single transform:

ccrawl extract text example.com
ccrawl extract links example.com
ccrawl extract title example.com
ccrawl extract markdown example.com -O page.md

search queries the URL index (the CDX server) for captures of a URL or pattern. The match type is inferred from wildcards, and you can always override it with --match.

ccrawl search example.com                    # exact URL, every timestamp
ccrawl search 'example.com/*'                # every URL under a path (prefix)
ccrawl search '*.example.com'                # the domain and all its subdomains
ccrawl search '*.example.com' --status 200   # only successful captures
ccrawl search example.com --mime text/html   # filter by detected MIME type
ccrawl search example.com -c all -n 50        # across every crawl, newest first
ccrawl search example.com --at 2022-06        # the capture nearest a date, per URL
ccrawl search example.com --estimate          # approximate record count per crawl

Narrow the columns or shape each row:

ccrawl search example.com --fields url,status,timestamp
ccrawl search example.com --template '{{.URL}} {{.Status}}'

Fetch by location: fetch

fetch retrieves WARC records by their exact byte location. The point is composition: anything that emits location records (filename, offset, length) can pipe straight into it. search --locations and columnar locations both do.

# Every PDF Common Crawl saw on a domain, downloaded one file per record:
ccrawl search 'example.com/*' --mime application/pdf --locations \
  | ccrawl fetch - --dir --out-dir pdfs/

# Read text from records the columnar index found:
ccrawl columnar locations --domain example.com -o jsonl \
  | ccrawl fetch - --text

You can also fetch a single record by hand:

ccrawl fetch --file crawl-data/CC-MAIN-2026-25/.../x.warc.gz --offset 123456 --length 4567 --text

Bulk questions: the columnar index

The columnar (Parquet) index is the fastest way to answer crawl-wide questions like "every PDF on .gov domains" without touching a single WARC. ccrawl builds the SQL for you and runs it against the public Parquet files using a local duckdb binary if one is on your PATH.

ccrawl columnar urls --tld gov --mime application/pdf -o url
ccrawl columnar count --domain example.com
ccrawl columnar langs --tld jp
ccrawl columnar mimes --domain example.com

[!NOTE] DuckDB is optional. If it is not on your PATH, ccrawl prints ready-to-run SQL instead of running it, so nothing is required to get a useful answer.

Ask for the SQL directly with --print, then paste it into DuckDB, Athena, Spark, or Trino:

ccrawl columnar sql --tld gov --mime application/pdf --print
SELECT url, url_host_registered_domain, fetch_status, content_mime_detected, ...
FROM read_parquet('https://data.commoncrawl.org/cc-index/table/cc-main/warc/crawl=CC-MAIN-2026-25/subset=warc/*.parquet', hive_partitioning=1)
WHERE url_host_tld = 'gov'
  AND content_mime_detected = 'application/pdf'

Install DuckDB from duckdb.org to run the queries directly. The ccrawl binary never links DuckDB, so installs stay small and pure Go.

Raw archives: paths, download, parse, convert

Each crawl ships its data as three archive kinds, all on data.commoncrawl.org:

  • WARC holds the full HTTP request and response,
  • WAT holds extracted metadata and links,
  • WET holds plain text.

List the archive paths, download them, decode them, and convert them:

ccrawl paths warc -c 2026-25                   # every WARC path for a crawl
ccrawl paths wet -n 1 | ccrawl download -      # download the first WET file
ccrawl download warc -n 5                       # the first 5 WARC files of the latest crawl
ccrawl parse local.warc.gz --type response -o table -n 20
ccrawl convert local.warc.wet.gz --to parquet -O out.parquet

CC-NEWS

CC-NEWS is a separate, continuously updated dataset of news articles. It has no URL index, so a host search streams the month's WARC files and keeps matching records.

ccrawl news list --year 2026 --month 5
ccrawl news search bbc.co.uk --year 2026 --month 5 -n 50

Output formats

Every list command renders through the same formatter. Pick a format with -o, or let ccrawl choose: a table when writing to a terminal, JSONL when piped.

ccrawl search example.com -o table   # aligned columns for reading
ccrawl search example.com -o jsonl   # one JSON object per line, for piping
ccrawl search example.com -o json    # a single JSON array
ccrawl search example.com -o csv     # spreadsheet friendly
ccrawl search example.com -o url     # just the URL column
ccrawl search example.com -o parquet > out.parquet  # columnar, for analytics

Building a dataset library

For bulk work you want the archive files in one tidy place you can come back to, not scattered across ad-hoc download dirs. The --library flag gives the data files a home and extends the commands you already know to list, download, and process them in place. Everything lands under ~/notes/ccrawl by default (CCRAWL_LIBRARY or --library-dir to move it), keyed by crawl and kind:

ccrawl download wet -n 20 --library -c 2026-25    # pull 20 WET files into the library
ccrawl paths    wet --library -c 2026-25          # list the WET files you have locally
ccrawl parse    wet --library --lang eng -o jsonl # decode every local WET file, eng only
ccrawl convert  wet --library --to parquet         # write parquet beside the raw files

Raw archives go to <crawl>/<kind>/, processed output to <crawl>/<format>/<kind>/, so a directory listing tells you exactly what you have. Re-running download only fetches what is missing, so the corpus grows incrementally. The library is separate from the scratch data dir, so clearing scratch state never touches it.

How it works

ccrawl uses the index to find a capture, then fetches just that record with an HTTP byte-range request. A WARC file is a stream of gzip members, one per record, so a single record decompresses on its own without downloading the whole file. That is what makes ccrawl get feel instant even though the file it lives in may be a gigabyte.

ccrawl is also a polite client. It rate-limits itself and retries 403, 429, and 5xx responses with exponential backoff, honoring a Retry-After header when the CDN sends one.

[!TIP] If requests keep failing, check the Common Crawl status page to see whether the data service is having problems before digging into your own setup.

Configuration

ccrawl keeps all of its state under one tree, ~/data/ccrawl by default: the cache, downloaded archives, converted Parquet, and the local DuckDB file. Point it somewhere else with CCRAWL_DATA_DIR. The curated dataset library is a separate tree, ~/notes/ccrawl by default (CCRAWL_LIBRARY or --library-dir), so scratch state and the corpus you keep never mix.

See the resolved paths and settings any time:

ccrawl config show

Useful global flags (all have sensible defaults):

Flag Meaning
-c, --crawl Crawl ID, year, latest, all, an integer for the newest N, or a comma list (default latest)
-o, --output Output format, including parquet (default auto)
-n, --limit Maximum results (0 means unlimited)
-j, --workers Concurrency for downloads and scans
--source Bulk data source: https or s3
--rate Minimum delay between requests, to stay polite
--no-cache Bypass the on-disk cache

Commands

Command What it does
crawls List, resolve, and inspect the monthly crawls
search Query the URL index (CDX) for captures of a URL or pattern
get Fetch what Common Crawl captured for a URL (curl for Common Crawl)
fetch Retrieve WARC records by explicit location, or from stdin
extract Pull text, links, title, or Markdown from a captured page
export Write matching captures into WARC files with provenance
download Download whole archive files for a crawl
paths List the archive file paths for a crawl
parse Decode a local WARC/WAT/WET file into records
convert Convert WARC/WAT/WET archives to Parquet or JSONL
columnar Query the columnar Parquet index (alias table, athena)
news Work with the continuous CC-NEWS dataset
rank Look up host and domain ranks from the web graph
db Build and query a local DuckDB database
stats Show the shape of a crawl: file counts per archive kind
config Show resolved configuration and data paths
cache Inspect and clear the on-disk cache

Development

make test    # run the test suite
make vet     # go vet
make build   # build ./bin/ccrawl

The code is layered. cli/ is the command tree built on Cobra. ccrawl/ is the library it sits on: the collection list, the CDX index, the columnar index, downloads, ranks, and CC-NEWS. The archive format parsers live in their own small packages under pkg/, each importable on its own:

Package What it reads
pkg/warc WARC records, plus the HTTP header/body split helpers
pkg/wat WAT metadata: status, title, meta tags, and links
pkg/wet WET extracted plain text

pkg/wat and pkg/wet build on pkg/warc, and none of them depend on ccrawl/ or the CLI, so you can pull just the parser you need into your own program.

License

Apache 2.0.

Common Crawl data is provided by the Common Crawl Foundation under their terms of use. This project is an independent client and is not affiliated with the foundation.

Directories

Path Synopsis
Package ccrawl is a Go library for working with Common Crawl data: the collection list, the CDX URL index, WARC/WAT/WET archive files, the columnar Parquet index, CC-NEWS, and the host/domain ranks.
Package ccrawl is a Go library for working with Common Crawl data: the collection list, the CDX URL index, WARC/WAT/WET archive files, the columnar Parquet index, CC-NEWS, and the host/domain ranks.
Package cli builds the ccrawl command tree on top of the ccrawl library and the any-cli/kit framework.
Package cli builds the ccrawl command tree on top of the ccrawl library and the any-cli/kit framework.
cmd
ccrawl command
Command ccrawl is a single-binary command line for Common Crawl.
Command ccrawl is a single-binary command line for Common Crawl.
pkg
warc
Package warc reads WARC files the way Common Crawl stores them: a stream of gzip members, one record per member.
Package warc reads WARC files the way Common Crawl stores them: a stream of gzip members, one record per member.
wat
Package wat reads WAT files, the Common Crawl archive of per-page metadata: the response status and content type, the HTML title and meta tags, and the outbound links.
Package wat reads WAT files, the Common Crawl archive of per-page metadata: the response status and content type, the HTML title and meta tags, and the outbound links.
wet
Package wet reads WET files, the Common Crawl archive of extracted plain text.
Package wet reads WET files, the Common Crawl archive of extracted plain text.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL