Files

108 lines
4.0 KiB
Markdown
Raw Permalink Normal View History

# Huginn
Huginn builds a local, searchable index of websites sourced from
[Common Crawl](https://commoncrawl.org/) — a public archive of billions of
web pages. It's the data layer for a competitor-discovery tool: point it at
a product and a market (e.g. "who sells honey with a `.es` domain?") and it
should be able to answer from the indexed data, without live-scraping the
web yourself.
## How it works
Common Crawl publishes a monthly URL index ("CDX") that maps every page it
captured to metadata (status, mime type, timestamp) and a location inside
one of its WARC archive files. Huginn pulls from that index two ways:
1. **`index.commoncrawl.org` — the query API.** Good for targeted lookups:
a specific URL, host, domain, or an entire TLD, paginated.
2. **`data.commoncrawl.org` — the raw index files.** The same data as
static, downloadable shard files (`cdx-*.gz`), listed per collection in
`cc-index.paths.gz`. Good for bulk ingestion, and doesn't depend on the
query API being up.
Either way, matching captures are grouped into `Site`s (one per domain) and
`SitePage`s (one per unique URL within that site), and optionally enriched
with the page's title/description/keywords/body text — fetched straight out
of the relevant WARC file via an HTTP range request, so only the bytes for
that one page are downloaded.
### Data model
- **Site** — a domain (e.g. `example.com`) within a given Common Crawl
collection, with its homepage's title/description/keywords.
- **SitePage** — one captured URL belonging to a Site: its CDX metadata
(status, mime, timestamp, WARC filename/offset/length) plus, if fetched,
its title/description/keywords/body text.
### Artisan commands
**`crawlindex:fetch`** — query the CDX API for a specific URL/host/domain,
or browse a whole TLD, and save the results.
```bash
# A specific domain
php artisan crawlindex:fetch example.com
# Every page under example.com (prefix match)
php artisan crawlindex:fetch "example.com/*" --match-type=prefix
# Browse an entire TLD, walking every index page, enriching each page
php artisan crawlindex:fetch --tld=es --all-pages --with-metadata
```
Key options: `--collection` (defaults to the latest), `--match-type`
(`exact|prefix|host|domain`), `--page`/`--pages`/`--all-pages` for
pagination, `--with-metadata` to fetch page content (slower — one extra
request per page).
**`crawlindex:bulk-fetch`** — walk Common Crawl's CDX shard files directly
from `data.commoncrawl.org`, bypassing the query API entirely. Useful for
bulk backfill/refresh of the database, or as a fallback when the query API
is offline.
```bash
# One shard, filtered locally to .es domains
php artisan crawlindex:bulk-fetch --collection=CC-MAIN-2026-25 --tld=es --shard-count=1
# Every shard in the collection (large — see caveat below)
php artisan crawlindex:bulk-fetch --collection=CC-MAIN-2026-25 --all-shards
```
Key options: `--collection`, `--tld` (filters locally, not via the API),
`--shard-start`/`--shard-count`/`--all-shards` to bound how many of a
collection's ~300 CDX shard files get processed in one run.
> **Scale caveat:** a monthly collection's CDX index is spread across
> ~300 shard files, each downloaded and decompressed in full. Running
> `--all-shards` (or `crawlindex:fetch --all-pages` without a `--tld`) over
> a whole collection means processing on the order of billions of records —
> pair broad runs with `--tld` (or a specific URL) to keep them bounded,
> and be especially careful combining `--with-metadata` with a broad run,
> since it adds one extra WARC request per page.
## Setup
Requirements: PHP 8.3+, Composer, Node/npm, and a MySQL database.
```bash
composer install
npm install
cp .env.example .env
php artisan key:generate
```
Edit `.env` and point `DB_*` at your MySQL instance, then run migrations:
```bash
php artisan migrate
```
Start the app (server, queue worker, and Vite dev server together):
```bash
composer run dev
```
Then populate the database with one of the `crawlindex:*` commands above.