the-3labs-team/laravel-ads-post-parser
A Laravel package for parsing advertising posts, extracting structured data from ad content so your application can normalize listings, import campaigns, and work with parsed ad fields more easily.
This package parses ad/classified posts into structured data, so the first thing to establish is which sources (formats, feeds, HTML dumps, API payloads) you actually need and what your downstream model looks like. Do that before installing anything.
Minimal path:
composer require the-3labs-team/laravel-ads-post-parser and confirm the constraint resolves to ^5.1.php artisan tinker and dump the result object. Do this before writing a controller, a job, or a migration.Where to look first, in order: the README's quick-start example, the config file, the parser/DTO classes it returns, and the existing tests (they double as executable documentation of supported edge cases).
First use case: take one saved ad post as a fixture file, parse it, and assert on the resulting structure in a test. If the parsed output already matches the shape your domain needs, the integration is mostly wiring. If it does not, you have found your first extension point early rather than halfway through a feature branch.
On v5.1.0 specifically: the release notes are a bare changelog link with no described features, fixes or breaking changes. Treat it as a minor bump under semver — expected to be additive and non-breaking — but read the v5.0.5...v5.1.0 compare diff before upgrading. Pinning ^5.0.5 vs ^5.1.0 is a one-line decision; the diff review is the part that actually de-risks it.
Wrap the parser, don't sprinkle it. Put the package behind a small application-level service (AdPostImporter or similar) that takes a raw payload and returns your own DTO or model. Every call site then depends on your interface, not the package's. When v6 arrives, you change one class.
Fixture-driven development. Keep a directory of real ad posts — messy ones: missing price, currency symbols in odd places, non-breaking spaces, RTL text, multi-line descriptions, HTML entities, truncated descriptions. Parse each in a test. This is the highest-value thing you can do with a parsing package, because the failure mode is always "worked on my three samples."
Pipeline shape for bulk ingestion. Fetch → persist raw → dispatch job → parse → normalise → upsert. Persist the raw payload before parsing. When a parser change or an upstream format change breaks things, you can re-run against stored input instead of re-crawling.
Normalise at the boundary. Convert the package's output into your canonical schema once, in one place: prices to integer minor units plus a currency code, dates to CarbonImmutable in UTC, free-text categories mapped through your own enum or taxonomy table. Do not let package-shaped arrays leak into Blade templates or API resources.
Idempotency and deduplication. Ads get re-posted and re-crawled constantly. Derive a stable identity (source + external ID when available, otherwise a hash of normalised title/price/location) and upsert on it. Store a raw_hash so you can skip unchanged posts.
Queue the work. Parsing is CPU-bound and often happens in batches; run it in jobs with a sensible tries/backoff and per-source rate limiting. Keep a per-source failure counter — if one source's parse failure rate spikes from 0% to 40%, that is your early-warning signal that the upstream format changed.
Isolate per-source configuration. If the package supports multiple parsers or source definitions, register them in config rather than if/else chains. Add new sources by adding config plus a fixture, nothing else.
Test doubles for the outside world. Fake HTTP with Http::fake() and feed fixtures through the importer. Never let a test hit a live ad site.
, smart quotes and emoji. Normalise early and assert on byte-exact expectations in tests; encoding bugs surface as "why is the price null" three layers downstream.(float) on a scraped string.php artisan config:clear in local dev. A stale cached config is a classic 30-minute debugging detour.v5.0.5...v5.1.0 before bumping — a minor version can still change behaviour in a parser without declaring a break. Run your fixture suite against the new version on a branch. If you keep the package behind your own importer service, this stays cheap.chunkById rather than get() when iterating stored raw posts for re-parsing.How can I help you explore Laravel packages today?