Scrapes a URL to Markdown by climbing a ladder of Perplexed.Scrapers,
cheapest first.
The default ladder is [:direct, :impersonated, :firecrawl]: plain HTTP,
then a browser TLS fingerprint, both free, then Firecrawl's hosted scraper,
which renders JavaScript and gets past most bot challenges. Swap any rung
for another scraper, for example [:direct, :impersonated, :browser_run],
or for your own module implementing Perplexed.Scraper.
The URL is checked by Perplexed.UrlGuard once, before any rung, so a
private address never reaches a hosted scraper either. Each rung's text is
judged by Perplexed.Verdict. After a failure the climb skips rungs whose
Perplexed.Scraper.retries?/1 says they cannot help with that outcome;
impersonation, for one, does nothing for a JavaScript shell. A missing
page, a redirect into a private network, a scanned PDF needing OCR, an
encrypted PDF, an unsupported file type or an oversized body ends the climb.
A scrape has one deadline (:timeout). Each rung gets only the time left,
and once it has passed the next rung is recorded as :deadline and the
climb stops. Every rung's cost counts, including a paid rung whose page
then failed the readability check.
Summary
Functions
Scrapes urls concurrently and returns {url, result} pairs in input order.
USD cost of a scrape result, whether it succeeded or every rung failed.
The ladder run/2 uses when none is given: config :perplexed, ladder:,
else [:direct, :impersonated, :firecrawl].
Scrapes url, returning the first rung's readable Perplexed.Document.
Types
@type result() :: {:ok, Perplexed.Document.t()} | {:error, {:unreadable, %{attempts: attempts(), cost: float()}}} | {:error, Perplexed.error()}
Functions
Scrapes urls concurrently and returns {url, result} pairs in input order.
Each scrape runs in an unlinked task under Perplexed.TaskSupervisor, with
bounded concurrency and a per-URL timeout that kills the task, so a crash
or a hang becomes that URL's {:error, {:exit, %{reason: reason}}} instead
of taking the caller down.
Options
:max_concurrency- default 6.:timeout- each URL's scrape deadline (seerun/2); the task is killed 1000 ms after it.:task_supervisor- defaultPerplexed.TaskSupervisor.
Other options go to run/2.
USD cost of a scrape result, whether it succeeded or every rung failed.
@spec default_ladder() :: [Perplexed.Scraper.spec()]
The ladder run/2 uses when none is given: config :perplexed, ladder:,
else [:direct, :impersonated, :firecrawl].
Scrapes url, returning the first rung's readable Perplexed.Document.
When every rung fails, answers
{:error, {:unreadable, %{attempts: attempts, cost: cost}}}, where
attempts lists each rung tried with its outcome and cost is what those
rungs cost. A blank URL, one the URL guard refuses, or an unknown ladder
entry is {:error, {:invalid_request, %{reason: reason, ...}}}.
Options
:ladder- thePerplexed.Scraper.spec/0entries to try, in order, defaultdefault_ladder/0.:timeout- the whole scrape's deadline in milliseconds, default 60000.:url_validator- a{Module, :fun, args}URL check for this call, overriding the configured one (seePerplexed.UrlGuard).
Other options go to every scraper; per-scraper options ride on a
{Module, opts} ladder entry.