Web Scraping by Language

Web Scraping With curl

By the Scrappey Research Team

Web Scraping With curl — conceptual illustration
On this page

Web scraping with curl means fetching pages directly from the command line, setting headers, cookies, and proxies with curl's flags, then piping the output to a parser like pup (HTML) or jq (JSON). curl is perfect for quick scrapes, testing requests, and shell pipelines — no programming language required. Its limits are that it cannot run JavaScript and sends a non-browser fingerprint, so anti-bot systems can identify it as automated.

Quick facts

Fetch a pagecurl -sL --compressed -A "<user-agent>" URL
Custom headers-H "Header: value" (repeatable)
Cookies/session-c cookies.txt to save, -b cookies.txt to send
Proxy-x http://user:pass@host:port
Parse outputpipe to pup (HTML) or jq (JSON)

Fetching pages with curl

The basics: follow redirects with -L, stay quiet with -s, request gzip with --compressed, and always set a realistic User-Agent with -A (curl's default UA is instantly blocked).

# GET a page, follow redirects, set a browser User-Agent, save to file:
curl -sL --compressed \
  -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \
  https://books.toscrape.com/ -o page.html

# Send extra headers (repeat -H as needed):
curl -s \
  -H "Accept-Language: en-US,en;q=0.9" \
  -H "Referer: https://www.google.com/" \
  https://example.com/

# Show response headers and timing without the body:
curl -sI https://example.com/
curl -s -o /dev/null -w "time_total: %{time_total}s\n" https://example.com/

-o file saves the body; -I fetches headers only; -w prints timing and status metrics. These cover inspecting and downloading almost any page.

POST, cookies, and proxies

Real scraping needs logins, form posts, and proxies. curl handles all of them:

# POST a form (login) and save the session cookies:
curl -s -c cookies.txt \
  -d "username=jane&password=secret" \
  https://example.com/login

# Reuse those cookies on a protected page:
curl -s -b cookies.txt https://example.com/account

# POST JSON to an API endpoint:
curl -s -X POST \
  -H "Content-Type: application/json" \
  -d '{"query":"laptops","page":1}' \
  https://api.example.com/search

# Route the request through a proxy (rotate by changing -x):
curl -s -x http://user:[email protected]:8000 https://example.com/

-c writes a cookie jar, -b sends it back, so you can keep a session across requests. -x sends the request through an HTTP or SOCKS proxy, which is how you rotate IPs from the shell.

Parsing HTML and JSON in the terminal

Here is what most curl tutorials skip: you can extract data without leaving the shell. Pipe HTML to pup (CSS selectors) or htmlq, and JSON to jq.

# Extract every product link (CSS selector -> href attribute) with pup:
curl -sL https://books.toscrape.com/ | pup 'h3 a attr{href}'

# Pull the text of each price into a list:
curl -sL https://books.toscrape.com/ | pup '.price_color text{}'

# Parse a JSON API response with jq:
curl -s https://api.example.com/items | jq -r '.items[].name'

# Combine: titles + prices into a quick CSV with htmlq + paste:
curl -sL https://books.toscrape.com/ | htmlq -t 'article.product_pod h3 a' > /tmp/t.txt
curl -sL https://books.toscrape.com/ | htmlq -t '.price_color'        > /tmp/p.txt
paste -d',' /tmp/t.txt /tmp/p.txt

This terminal-native pipeline — curl | pup | ... — is fast, scriptable, and needs no programming language. Install pup, htmlq, and jq from your package manager.

What curl cannot do (and how to fix it)

curl has two hard limits. First, it cannot run JavaScript — on a client-side-rendered page it only sees the empty HTML shell, so the data is not there to extract. Second, curl sends a TLS fingerprint and header set that no real browser produces, so anti-bot systems (Cloudflare, DataDome, Akamai) flag it immediately — and no combination of flags changes that.

You can address part of this with curl-impersonate (a build that reproduces a browser's TLS handshake), but JavaScript rendering and CAPTCHA challenges are out of reach for curl alone. A scraping API keeps the simple curl workflow but renders JavaScript server-side — you still pipe the result to pup or jq:

Code example

bash
# Render JS + clear anti-bot in one curl call, then parse with jq/pup.
curl -s -X POST \
  'https://api.your-scraping-provider.com/v1?key=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"cmd":"request.get","url":"https://example.com/protected"}' \
  | jq -r '.solution.response' > rendered.html

# rendered.html now holds the fully rendered, unblocked page:
pup 'h3 a attr{title}' < rendered.html

Related terms

Concept map

How Web Scraping With curl: A Complete 2026 Guide connects

The terms most directly tied to this one. Hover a node to see its neighbours, click to preview, drag to rearrange.

0 terms · 0 connections
You are here · Web Scraping by Language
Building map…

Frequently asked questions

Can you use curl for web scraping?

Yes. curl fetches pages from the command line and supports custom headers, cookies, POST data, and proxies, so it is great for quick scrapes, testing requests, and shell pipelines. Pipe its output to pup or htmlq to extract HTML by CSS selector, or to jq to parse JSON APIs. Its limits are that it cannot run JavaScript and is easily fingerprinted and blocked.

How do I parse HTML from curl output?

Pipe curl to a command-line HTML parser. pup takes CSS selectors (e.g. curl -sL URL | pup "h3 a attr{href}"), and htmlq is a similar tool. For JSON API responses, pipe to jq instead. This keeps the whole scrape in the terminal with no programming language required.

Why does curl get blocked when scraping?

curl sends a TLS handshake and header set that no real browser produces, so anti-bot systems flag it as automated and return a 403 or CAPTCHA. Setting a browser User-Agent helps a little but does not change the TLS fingerprint. curl-impersonate reproduces a browser handshake; for JavaScript rendering you need a headless browser or a scraping API.

Can curl scrape JavaScript-rendered pages?

No. curl only downloads the raw HTML the server returns and cannot execute JavaScript, so on a client-side-rendered page the data simply is not present. You need a real browser (Playwright, Selenium) or a scraping API that renders the page server-side and returns the final HTML, which you can then pipe to pup or jq.

Last updated: 2026-06-08