webscrape.dev

Deduplication

Deduplication is the machinery that stops a crawl from fetching the same thing twice and from storing the same record twice. Those are two different problems at two different layers, and a system that solves only one of them still ships duplicates.

URL-level dedup starts with normalization, because hashing raw URLs catches almost nothing. Strip tracking parameters such as utm_ and fbclid, sort the remaining query keys into a stable order, resolve relative and dot segments, lowercase the host while leaving the path case alone, and make one explicit decision about trailing slashes and default ports. Only then hash. Scrapy's default RFPDupeFilter works this way, filtering "based on the REQUEST_FINGERPRINTER_CLASS setting", which is the seam you override when a target puts meaningful state in a header or a POST body. The seen-set behind it is an in-memory structure at small scale and moves to a shared Redis set once several workers share a frontier, or to a Bloom filter once the entry count passes tens of millions.

Content-level dedup handles the same record arriving under different URLs, which normalization cannot reach: a product under two category paths, a listing syndicated across mirrors, a session id baked into a path segment. This needs a hash over the extracted record rather than over the page, computed on the fields you actually care about. Exact hashing then stops working the moment boilerplate is included, because a rotating ad slot or a "last updated 3 minutes ago" string changes the digest on every fetch. Near-duplicate detection is the answer: simhash or minhash over shingles gives a similarity score instead of a binary match, and you set a threshold.

Probabilistic structures trade memory for a controlled error, and the direction of that error matters. A Bloom filter answers "definitely not seen" or "probably seen", so its false positives are dropped URLs rather than duplicate ones. That is a silent coverage bug: pages never fetched, no error logged, a crawl that looks complete. At a 1 percent false-positive rate over 100 million URLs the expected loss is around a million pages. So the decision splits on volume and stakes. Under a few million URLs an exact Redis set costs little and removes the whole class of problem. Above that, size a Bloom filter to a rate you can defend, keep any high-value segment in an exact set anyway, and set the near-duplicate threshold empirically against a labeled sample, since a threshold tight enough to collapse genuine repeats will merge distinct records if you push it one notch further.

Tools that handle deduplication

4 tools in the webscrape.dev directory are commonly used for deduplication workflows, spanning crawling frameworks, no-code scrapers. Each is reviewed independently with pricing and editorial assessment.

Scrapy

Scrapy is a mature, widely-used Python framework for building crawlers. It handles request scheduling, concurrency, and data pipelines, leaving proxies and anti-bot handling to you or an add-on service.

Free
Crawlee

Crawlee is a crawling and scraping library for Node and Python from Apify. It ships with request queuing, session pooling, and anti-blocking helpers, so more of the hard parts are built in than with a bare framework.

Free
Apify

Apify is a cloud platform for web scraping, crawling, and browser automation, built around Actors: pre-built or custom programs distributed through a marketplace with thousands of listings. It handles headless-browser automation for JavaScript-heavy pages with Playwright, Puppeteer, or Selenium, and stores results in datasets or key-value stores that export as JSON, CSV, or Excel. It also has residential and datacenter proxies, scheduling, and API, webhook, and MCP access for programmatic or AI-agent use. Its open-source Crawlee library, with 23.7k GitHub stars, is used to build custom Actors in JavaScript/Node.js or Python, though the hosted Apify platform itself is closed-source and not self-hostable.

Freemium
Spider

Spider is a web crawling and scraping platform with a hosted REST API: /scrape, /crawl, /screenshot, /links, and /search endpoints. The core engine is written in Rust, MIT-licensed, open source, and self-hostable. The hosted service adds a real browser for JavaScript rendering and returns clean markdown or structured JSON. It integrates natively with LangChain, LlamaIndex, CrewAI, FlowiseAI, AutoGen, and Agno, and lists Dify.AI as a customer.

Freemium

Browse by category

Crawling Frameworks Self-hosted libraries for building crawlers you run and own, with no per-request pricing.
No-Code Scrapers Point-and-click and template tools that build scrapers without writing code.