Guide series · 55 guides

How to Scrape a Website: Methods, Languages and Libraries

To scrape a website, you request its pages over HTTP, parse the HTML (or the JSON the page loads) to pull out the fields you need, and save them, repeating across pages with pauses and, at volume, through rotating proxies. Pick the tool by the job: a no-code tool for a few pages, a Python or JavaScript script for server-rendered pages at any volume, a headless browser only when the data is built by JavaScript, and a scraping API when targets are hard or layouts vary. Most publicly viewable pages can be collected, but no tool guarantees every site: login-only, paid, never-sent and challenge-protected content cannot be reliably scraped. ProxyField supplies the IPs for the request step, 412M+ residential IPs from $1.95/GB; start with the Easy Trial: 1 GB for $2.95.

residential IPs
412M+
from, traffic never expires
$1.95/GB
Easy Trial
1 GB for $2.95
On this page 13 sections
  1. How to scrape a website in 6 steps
  2. Code, a no-code tool or a scraping API: how to choose
  3. Methods of scraping a website
  4. Languages and libraries for web scraping
  5. Static and dynamic pages
  6. Scraping pages vs pulling records from a site's search
  7. Can you scrape any website?
  8. Scraping many pages: crawling, speed and scheduling
  9. Avoid getting blocked
  10. Store the data
  11. Is scraping a website legal?
  12. Guides on how to scrape a website
  13. How to scrape a website FAQ

Three answers up front

  • Can you scrape any website? No. Most publicly viewable pages can be collected, but login-only pages (a 401 Unauthorized answer), paid content, data the site never sends and pages behind challenges cannot be reliably scraped by any tool. Details
  • What is database scraping? Collecting a site's records automatically into a spreadsheet, CSV file or database. It can read the pages (HTML, one detail URL per record) or the search requests behind them (usually JSON, many records per request). Details
  • Code, no-code or an API? A no-code tool (Octoparse, ParseHub) for a few pages, a Python or JavaScript script for server-rendered pages at any volume, a headless browser only when JavaScript builds the data, and a scraping API for hard targets or many layouts. Details

How to scrape a website in 6 steps

Every scraper, from a 10-line script to a crawler of millions of pages, follows the same 6 steps.

  1. Check what you may collect

    Use the site's official API or data export if it has one. Otherwise read its robots.txt and terms, and stay with public data: how to check if a website allows scraping. Public does not mean outside privacy law: the GDPR still applies to personal data a page shows to everyone, and France's regulator CNIL notes that "web scraping is not, in itself, prohibited under the GDPR" while it recommends excluding sites that oppose scraping "through technical or legal means" (CNIL, AI system development recommendations, January 2026).

  2. Find where the data lives

    Open the page, right-click the data and choose Inspect. If the value is in the page source (View page source), plain HTTP will do. If it appears only in the live page, look in the developer tools' Network tab for the JSON request that delivers it.

  3. Fetch the page

    Send a GET request, or load it in a headless browser if it needs JavaScript. Set a User-Agent: an honest one that names your tool and a contact (my-price-bot/1.0 (+mailto:[email protected])) for research crawls and sites that welcome declared bots; a current browser's string when the site serves browsers different HTML from scripts. Python's default (python-requests/2.x) is the one most often refused.

  4. Parse the fields

    Select each value with a CSS selector or XPath, or read it from the JSON, and expect some fields to be missing: HTML scraping with CSS selectors and XPath.

  5. Repeat across pages

    Follow the "next" link or the page number, or crawl from a list of URLs, with a pause between requests.

  6. Save and schedule

    Write rows to CSV, a spreadsheet or a database, and rerun on a schedule: schedule and deploy web scrapers.

A complete example in Python on Books to Scrape, a site built for practice, through a ProxyField proxy:

Python
import csv
import time
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

PROXY = "http://<login>-country-us-city-new_york:<password>@gate.proxyfield.io:7000"
# copy the User-Agent string of your own, current browser
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                         "(KHTML, like Gecko) Chrome/<version>.0.0.0 Safari/537.36"}

url = "https://books.toscrape.com/"
rows = []
while url:
    resp = requests.get(url, headers=HEADERS, proxies={"http": PROXY, "https": PROXY}, timeout=30)
    resp.raise_for_status()
    soup = BeautifulSoup(resp.text, "html.parser")
    for book in soup.select("article.product_pod"):
        rows.append({
            "title": book.select_one("h3 a")["title"],
            "price": book.select_one("p.price_color").get_text(strip=True),
            "url": urljoin(url, book.select_one("h3 a")["href"]),
        })
    next_link = soup.select_one("li.next a")
    url = urljoin(url, next_link["href"]) if next_link else None
    time.sleep(2)  # be gentle

with open("books.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "price", "url"])
    writer.writeheader()
    writer.writerows(rows)
print(len(rows), "books saved")

Region, session and session time go in the same username: -region-<region>, -session-<id> and -ttl-<seconds> (30 to 129,600 seconds, 20 minutes by default), as in <login>-country-us-region-new_york-city-new_york-session-he9f2qga-ttl-600; every part after the login is optional. The same scraper in more detail, with error handling and other libraries: web scraping with Python.

Selectors that do not crash. A selector that matches nothing returns nothing, and the next line fails. Test before you read:

Python
el = book.select_one("p.price_color")          # BeautifulSoup: None when nothing matches
price = el.get_text(strip=True) if el else ""

# Scrapy: .get() returns None (or your default) instead of raising
price = response.css("p.price_color::text").get(default="")
link = response.css("h3 a::attr(href)").get()

In Scrapy, css() and xpath() return a SelectorList, ::text and ::attr(name) pick text and attributes, and //li[1] (the first li of each parent) is not (//li)[1] (the first li on the page): see the Scrapy selectors documentation.

Code, a no-code tool or a scraping API: how to choose

Choose by how the page is built and how often you need the data, not by habit.

Your jobUseWhy
A few pages, once, no programmingA no-code tool (Octoparse, ParseHub) or a browser extensionPoint and click; nothing to install or maintain
Server-rendered pages, any volumeA script: Python requests + BeautifulSoup, or Node.js + CheerioFast, cheap per page, full control
The data appears only after JavaScript runsThe page's JSON request first, a headless browser (Playwright) if there is noneA browser costs several times the traffic and CPU of a plain request
Hard targets, or many sites with different layoutsA scraping APISomeone else runs the browsers, retries and IPs

Test in that order: if curl (below) returns the data, write a script; move up to a browser or an API only when the cheaper step fails. Guides: no-code web scrapers, what is a web scraping API, scraper API vs proxies.

Methods of scraping a website

There are 8 common ways to scrape a website; pick by how the page is built and how much data you need.

MethodWhen it fitsTypical toolsGuide
No-code tool or browser extensionA few pages, no programmingOctoparse, ParseHub, point-and-click extensionsNo-code web scrapers
Spreadsheet functionsSmall tables into a sheetGoogle Sheets IMPORTXML, Excel Power QueryWeb scraping into Excel
HTTP request + HTML parserServer-rendered pages, any volumePython requests + BeautifulSoup, Node.js + CheerioBeautifulSoup tutorial
The page's own JSON APIPages that load data in the backgroundAny HTTP clientWeb scraping vs API
Headless browserPages built by JavaScript, clicks and scrollingPlaywright, Puppeteer, SeleniumScrape dynamic web pages, what is a headless browser
Crawler frameworkWhole sites, many pages, retries and pipelinesScrapy, Crawlee, CollyHow to crawl a website, Scrapy tutorial
Command lineQuick checks, one page, shell scriptscurl, wgetcURL
Scraping API or AI extractionHard targets, or many different layoutsA web scraping API, an LLMScraper API vs proxies, AI web scraping

Why curl? curl is on almost every machine, shows you exactly what the server returns to a plain request, and lets you test headers, cookies and a proxy in one line before you write a scraper:

Shell
curl -s -x gate.proxyfield.io:7000 -U "<login>-country-us-city-new_york:<password>" -A "Mozilla/5.0" https://books.toscrape.com/ | head -c 500

If the data is in that output, a simple HTTP scraper will work; if not, the page needs JavaScript or a different request.

Languages and libraries for web scraping

Any language that can send HTTP requests and parse HTML can scrape; Python and JavaScript have the most tools and examples.

LanguageHTTP and parsingBrowser automation and frameworksGuide
Pythonrequests, httpx, BeautifulSoup, lxmlScrapy, Playwright, SeleniumPython, Python libraries
JavaScript / Node.jsfetch, Axios, CheerioPuppeteer, Playwright, CrawleeJavaScript and Node.js
JavaHttpClient, jsoupSelenium, Playwright for JavaJava
C#HttpClient, HtmlAgilityPack, AngleSharpPlaywright for .NET, SeleniumC#
PHPGuzzle, cURL, Symfony DomCrawlerSymfony PantherPHP
RubyHTTParty, NokogiriFerrum, SeleniumRuby
Gonet/http, goqueryColly, chromedpGo
Rhttr2, rvestchromoteR
Rustreqwest, scraperchromiumoxide, headless_chromeRust
C and C++libcurl, libxml2 or GumboRarely usedBelow

C and C++ work well for speed-critical fetching: libcurl sends the requests (with CURLOPT_PROXY for a proxy) and libxml2's HTML parser with XPath, or Google's Gumbo, reads the pages. The code is longer and memory handling is on you, so most teams use C or C++ only inside a larger system. The choice between languages: best language for web scraping.

Static and dynamic pages

A static (server-rendered) page carries its data in the HTML the server sends; a dynamic page builds it in the browser with JavaScript. The difference decides your tools.

  • Test it: if the value appears in View page source or in the curl output, the page is static for your purposes.
  • Dynamic pages: first look for the JSON request in the Network tab; calling it directly is faster and lighter than rendering. If there is none, use a headless browser. Guides: dynamic pages, dynamic JavaScript sites with Python, headless browser scraping in Python and Go.
  • Browsers cost more: a headless browser downloads scripts, images and fonts, so it uses several times the traffic and CPU of a plain request; block images and fonts when you do not need them.

Scraping pages vs pulling records from a site's search

"Database scraping" means collecting a site's records (products, listings, filings, people in a directory) automatically into a spreadsheet, CSV file or your own database; web scraping itself is "the process of programmatically and systematically collecting information on the web" (NNLM data glossary). There are two ways to get the records, and they are not the same job.

FeatureScraping pagesPulling search records
What you requestEach detail URL, one page at a timeThe request the site's search box sends, page by page
Example requestGET /products/acme-laptop-15GET /api/search?q=laptop&page=2&per_page=100
What comes backHTML you parse with selectorsUsually JSON, with a query, a page number and a sort parameter
How to find itThe page URLs, a sitemap or category listsDeveloper tools, Network tab, filter Fetch/XHR, then run a search
Example: 10,000 products10,000 requests100 requests of 100 records each
FieldsEverything the page showsOnly the fields the search results expose

A site's search results are not a complete copy of its database. The search route is lighter but has limits:

  • It is a view, not a copy. A search returns what matches and what the site chooses to show, ranked by relevance; records that are not indexed, or that sit past a result cap, never appear.
  • Fields are thinner. Results often carry the name, price and link, not the full description, so many jobs still fetch the detail pages for some fields.
  • It changes without notice. An internal search request is not a public API, and its parameters can change.

When the site offers an official API or a data export, use it: it beats both routes on stability. How to find and call a page's own requests: scrape hidden APIs, pagination.

Copying a database has its own legal angle. In the EU, the Database Directive (96/9/EC) gives a database's maker a right against extracting a substantial part of its contents, even when each record is public; the UK keeps its own database right on the same model, and a site's terms may forbid systematic extraction. robots.txt is a crawler request, not access control: RFC 9309 says its rules "are not a form of access authorization" (RFC 9309).

Can you scrape any website?

No. Most publicly viewable pages can be collected, including pages built by JavaScript, but no tool guarantees every site: login-only, paid, never-sent and challenge-protected content cannot be reliably scraped, and some content should not be scraped at all.

What stops a scraperExampleWhat it means for you
Login-only or paid contentAccount pages, paywalled articlesNot public data: stay out without the owner's permission
A 401 Unauthorized answerAn API or page that asks for credentialsThe request "lacks valid authentication credentials" and comes with a WWW-Authenticate header naming the scheme (MDN: 401): the data is not public
Data never sent to the browserA private backend, internal reportsNothing to scrape: the page never contains it
Challenge pages and CAPTCHAsCloudflare's Interstitial Challenge Page, Managed Challenge, Turnstile widget and JavaScript DetectionsThe site asks for proof of a human; a scraper that cannot pass it gets no data
Rate limits and IP reputationMany requests from one IP, datacenter rangesRequests slow down, fail or get blocked
Deliberately changing pagesRotating class names, tokens, layoutsScrapers break and need constant upkeep

Cloudflare's documentation lists which of its products issue which challenge: the WAF (custom rules, rate limiting rules, IP access rules) and Bot Fight Mode show the Interstitial Challenge Page, Bot Management runs JavaScript Detections, Under Attack Mode issues a Managed Challenge, and Turnstile is a widget embedded in a site's form. It also notes a limit that catches scrapers: a Managed Challenge solved from a different IP than the one it was issued to is not valid, and you may land in a challenge loop (how challenges work). Keep one IP for a whole session, a sticky session on a proxy, so a page you are allowed to read does not loop. The same page (last updated October 16, 2026) lists two more limits: challenges do not support "browser extensions that modify the browser's User-Agent value or Web APIs such as Canvas and WebGL", and "Challenge Pages cannot be embedded in cross-origin iframes". Why sites flag a visitor as a bot: why does Cloudflare think I'm a bot; the challenge types: types of CAPTCHA.

Many public pages that refuse a bare script load in a real browser on one consistent residential IP, but no tool, ours included, is guaranteed to reach every site. Where a site has put data behind a login or a deliberate barrier, the route is its official API, an export or the owner's permission, not a way around the barrier.

Scraping many pages: crawling, speed and scheduling

One page is a script; thousands of pages are a system with a queue, retries and a schedule.

  • Pagination and crawling: follow "next" links, page numbers or infinite-scroll API calls; for whole sites, crawl from the sitemap. How to crawl a website, build a web crawler, Python web crawler.
  • Speed: run requests concurrently with async clients or a framework, reuse connections, and fetch only what you need: make web scraping faster.
  • Scheduling: cron, a cloud function or a workflow tool such as n8n reruns the scraper and stores the results.

Avoid getting blocked

At volume, a website notices a scraper by its IP, its request rate, its headers and, in browsers, its fingerprint. Rotate residential IPs, send real browser headers, pause between requests and keep sessions consistent; the full checklist is in how to avoid getting blocked while scraping, and the habits that keep scrapers healthy in web scraping best practices.

ProxyField residential proxies cost $2.95/GB for 1 GB down to $1.95/GB from 1,000 GB, rotate on every request or hold a sticky IP for 30 seconds to 36 hours, and target country, region and city in 195+ countries; the traffic never expires. See proxies for web scraping.

Store the data

Pick storage by how you will use the data, not by habit.

StorageGood for
CSV or JSON Lines filesOne-off jobs and hand-offs
A spreadsheetSmall datasets that people read and filter
SQLite or PostgreSQLRecurring jobs, history, joins and deduplication
Object storage (raw HTML)Re-parsing later without re-downloading

Keep the raw HTML of each page for a while: when a selector breaks, you can fix it and re-parse without fetching the pages again.

Guides on how to scrape a website

How to scrape a website FAQ

How do I scrape data from a website, and how do I choose between writing code, a no-code tool or a scraping API?

ProxyField's guide uses 6 steps: check what you may collect (an official API first), find where the data sits (the HTML or a JSON request), fetch the page, parse the fields with CSS selectors, repeat across pages, and save to CSV or a database on a schedule. Use a no-code tool for a few pages once, a script (Python requests + BeautifulSoup) for server-rendered pages at any volume, a headless browser only when the data needs JavaScript, and a scraping API for hard targets or many layouts. At volume, rotating residential proxies carry the requests; ProxyField's 412M+ IPs start at $1.95/GB.

Can you really scrape any website, or are there sites that can't be scraped whatever tool you use?

No tool scrapes every site. Login-only pages (a 401 answer), paid content, data never sent to the browser, and pages behind challenges such as Cloudflare's Managed Challenge or Turnstile stop scrapers or put the data out of bounds; most other publicly viewable pages can be collected with plain requests or a headless browser. Technically possible is not the same as permitted: robots.txt is not access authorization (RFC 9309), and US law (Van Buren, the DOJ's CFAA policy) points at areas you are not entitled to enter, not at public pages, so where a site has put up a deliberate barrier, use its API or ask the owner.

How do I scrape data from a single web page?

Right-click the value and choose Inspect to find its element, copy a CSS selector for it, then fetch the page and select that element in your code, a spreadsheet function or a no-code tool. For a one-off, copying the table into a spreadsheet may be all you need.

What is the fastest web scraping technique?

Calling the site's JSON endpoint directly with an async HTTP client: no rendering, small responses and many requests in parallel. Parsing server-rendered HTML with a fast parser such as lxml comes next; headless browsers are the slowest and are worth it only for pages that need JavaScript.

What is the most reliable way to scrape a website?

Use the most stable source the site offers: an official API first, then the JSON the page loads, then the HTML. Add retries with backoff, rotating residential IPs, logging of status codes and a test that alerts you when a selector stops matching.

Why use curl for web scraping?

curl shows exactly what the server returns to a plain request, so it tells you in seconds whether the data is in the HTML and whether headers, cookies or a proxy change the answer. It also works in shell scripts for small jobs; for parsing and scale, move to a language with an HTML parser.

What does database scraping mean, and how is pulling records from a site's search database different from scraping its pages?

Database scraping means collecting a site's records automatically into a spreadsheet, CSV file or your own database. Scraping pages fetches each detail URL and parses its HTML (10,000 products, 10,000 requests); pulling search records calls the request the site's search box sends, usually JSON, and pages through it (100 requests of 100 records). The search route is lighter but returns only the fields and records the search exposes.

Can you scrape the whole internet?

Not as one person or company starting from zero: web-scale crawls take years of infrastructure. Public crawl archives such as Common Crawl publish billions of pages that you can download and process instead, and for specific sites a targeted crawler is the practical route.

What are the downsides of web scraping?

Scrapers break when layouts change, need upkeep and infrastructure such as proxies, can be blocked, and carry legal risk if they collect personal or copyrighted data or ignore a site's terms. The data can also be incomplete or stale if a run fails unnoticed, so monitoring matters.

Where should I store scraped data?

CSV or JSON Lines files for one-off jobs, a spreadsheet for small datasets people read, and SQLite or PostgreSQL for recurring jobs that need history and deduplication. Keep the raw HTML for a while, so you can re-parse when a selector breaks without fetching the pages again.

How to scrape a website

Every guide in this series

  1. What Is Puppeteer?
  2. Web Scraping With Python: Step-by-Step Tutorial
  3. What Is Scrapy?
  4. Web Scraping With Selenium and Python
  5. How to Crawl a Website
  6. What Is a Headless Browser?
  7. Web Scraping With Puppeteer
  8. Web Scraping With JavaScript and Node.js
  9. Web Scraping With Playwright
  10. Java Web Scraping
  11. Web Scraping Best Practices
  12. Python Web Crawler: From a Script to Scrapy
  13. PHP Web Scraping
  14. C# Web Scraping
  15. Puppeteer vs Playwright
  16. Web Scraping in R With rvest
  17. Scrapy Tutorial: Build Your First Spider
  18. How to Scrape Images From a Website
  19. BeautifulSoup Web Scraping Tutorial
  20. Web Scraping Projects With Code
  21. Web Scraping With Go: Colly and goquery
  22. Ruby Web Scraping
  23. How to Build a Web Scraper
  24. How to Scrape Dynamic JavaScript Websites With Python
  25. HTML Scraping With CSS Selectors and XPath
  26. How to Build a Web Crawler
  27. Python Libraries for Web Scraping
  28. Is Playwright Free? What It Is and What It Costs
  29. What Is Selenium?
  30. Puppeteer Alternatives: Playwright, Selenium, Python and Firefox Options
  31. Best Headless Browsers for Web Scraping
  32. Headless Browser Scraping in Python and Go
  33. Web Scraping in Rust
  34. Best Programming Language for Web Scraping
  35. How to Scrape Dynamic Web Pages
  36. Why Is My Web Scraper Slow? How to Make It Faster
  37. How to Schedule and Deploy Web Scrapers
  38. Puppeteer vs Selenium
  39. Web Scraping With Excel VBA and PowerShell
  40. Scraping JavaScript Pages With Scrapy
  41. Web Scraping Pagination
  42. Image Scraper in Python
  43. Scrapy vs BeautifulSoup vs Selenium vs Playwright
  44. Websites to Practice Web Scraping
  45. Cheerio Web Scraping Tutorial
  46. Asynchronous Web Scraping in Python
  47. Cheerio vs Puppeteer
  48. How to Scrape Hidden APIs and Embedded JSON
  49. What You Need to Start Web Scraping
  50. Scraping a Website Behind a Login With Python
  51. Python vs JavaScript for Web Scraping
  52. How to Scrape a Table From a Website
  53. Large-Scale Web Scraping
  54. Playwright vs Selenium vs Puppeteer
  55. Scraping Behind a Login: Cookies and Sessions

Easy Trial: 1 GB for $2.95.

Try for the price of 1 GB, no subscription, traffic never expires.