Download the PHP package commently/crawler without Composer
On this page you can find all versions of the php package commently/crawler. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download commently/crawler
More information about commently/crawler
Files in commently/crawler
Package crawler
Short Description Polite URL crawler. Transport + politeness only (robots.txt, per-host rate limits, conditional requests). Parsing and consuming content is the caller's job.
License MIT
Informations about the package crawler
Laravel Polite Crawler
A minimal, polite URL crawler for Laravel. Give it a URL and it brings you the raw document — respecting robots.txt, per-host rate limits and conditional requests. It does not know (or care) what it crawls. Parsing and consuming the content is entirely your job, so the package plugs into any project without dictating a schema.
Why this package
Most "crawler" packages are opinionated about what you crawl: they discover
links, follow HTML, render JavaScript, or ship their own database schema.
laravel-polite-crawler deliberately does none of that. It is just the
polite transport layer:
- what it does — fetch a URL (or a batch of URLs) over HTTP, politely and concurrently, and hand you the raw body plus transport metadata;
- what it doesn't do — parse feeds, scrape HTML, store rows, decide when to fetch again.
The collection pipeline stays in your application:
Features
- Polite by default — a single honest
User-Agent, no browser impersonation. - robots.txt — consulted (and cached) per host; a failure to fetch it never blocks.
- Per-host rate limiting — minimum delay between two requests to the same host and at most N concurrent requests per host, enforced across processes via the distributed cache.
- Global concurrency cap — simultaneous requests across all hosts, batched in waves.
- Conditional requests — sends
If-None-Match/If-Modified-Sinceand reports304 Not Modifiedinstead of re-downloading. - Outcome classification — every attempt ends in one of five explicit
outcomes (
success,not_modified,error,throttled,blocked), withRetry-Afterparsed for 429 responses. - Batch fetching —
fetchMany()crawls a list of URLs concurrently while respecting the same politeness rules, with apermithook for app-level idempotency. - Queued entry point — a ready
CrawlUrljob that hands fetched documents to aSinkimplementation you bind in the container. - Zero domain coupling — no Eloquent, no models, no schema.
Requirements
- PHP 8.3+
- Laravel 12 or 13
Installation
If you are developing against a local checkout (the recommended workflow for
this package), use a path repository in your composer.json:
The service provider is auto-discovered. Publish the configuration when you want to tune the defaults:
Usage
Fetch a single URL
CrawlRequest is a plain DTO:
| Property | Description |
|---|---|
url |
The URL to fetch. |
key |
Stable identifier used to key batch results; defaults to the URL. |
etag |
Sent as If-None-Match. |
lastModified |
Sent as If-Modified-Since. |
headers |
Extra request headers merged on top of the defaults. |
CrawlResponse carries the raw body and transport metadata:
| Property | Description |
|---|---|
outcome |
One of CrawlOutcome::Success/NotModified/Error/Throttled/Blocked. |
status |
HTTP status code (0 for transport errors / gated attempts). |
body |
Raw response body (empty for not_modified). |
headers |
Response headers (header(string $name) for case-insensitive lookup). |
effectiveUri |
Final URL after redirects. |
duration |
Request time in seconds, when available. |
etag / lastModified |
Validators returned by the server. |
retryAfterSeconds |
Parsed Retry-After for 429 responses. |
error |
Reason message for error outcomes. |
Fetch many URLs concurrently
fetchMany() crawls a list of requests in waves, applying the same
politeness rules, and returns only the attempts that were actually fired:
The permit hook
Pass a permit callable to refuse individual requests right before they are
fired — useful for app-level idempotency (e.g. "has this feed already been
fetched by another worker?"):
Sink + queued job
The package ships a CrawlUrl queued job and a Sink contract. The job
fetches the URL (enforcing politeness) and hands the document to whatever
Sink is bound in the container:
Bind it in a service provider:
Then dispatch crawls anywhere:
Note: the job only calls the sink for
success/not_modifiedoutcomes.error,throttledandblockedattempts are dropped (log or requeue them yourself if you care).
Configuration
All settings are optional; sensible defaults apply.
How politeness works
- Per-host delay. After a request to a host, a timestamp is written to the cache; further requests to that host are skipped until the delay has passed. A redirect to another host applies the same spacing to the target host.
- Per-host concurrency. A distributed lock per host guarantees at most
max_concurrent_per_hostin-flight requests, even across multiple queue workers or processes. - Global concurrency.
fetchMany()builds waves of at mostmax_concurrencyrequests at a time. - robots.txt. Fetched once per host (cached for
cache_ttl) and only the matchingUser-agentgroup (the crawler's own UA or*) is honoured. Unreachable robots.txt never blocks fetching.
Honest headers
The crawler sends a fixed, honest User-Agent, an XML-capable Accept list
and Accept-Encoding: gzip. It never impersonates a browser, rotates user
agents, or sends Sec-Fetch-* headers.
Testing
The package ships no tests of its own; it is covered by the consuming application's test suite (see the HTTP-fake based tests for rate limiting, robots.txt and conditional-request behaviour).
License
MIT
All versions of crawler with dependencies
illuminate/cache Version ^12.0|^13.0
illuminate/contracts Version ^12.0|^13.0
illuminate/http Version ^12.0|^13.0
illuminate/support Version ^12.0|^13.0