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
- How to scrape a website in 6 steps
- Code, a no-code tool or a scraping API: how to choose
- Methods of scraping a website
- Languages and libraries for web scraping
- Static and dynamic pages
- Scraping pages vs pulling records from a site's search
- Can you scrape any website?
- Scraping many pages: crawling, speed and scheduling
- Avoid getting blocked
- Store the data
- Is scraping a website legal?
- Guides on how to scrape a website
- 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 Unauthorizedanswer), 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
In this guide
- How to Build a Web Scraper In 8 steps: inspect, fetch, parse, paginate, save to CSV, add proxies. Python code.
- HTML Scraping With CSS Selectors and XPath CSS Selectors, XPath, Links and Text.
- Web Scraping Projects With Code 15 ideas by level, the skills each teaches, starter code, GitHub tips and when you need proxies.
- Web Scraping Best Practices Web scraping best practices come down to five habits: collect only public data you are allowed to use, keep the request rate low and steady, retry…
- Web Scraping With Python: Step-by-Step Tutorial Step-by-Step Tutorial (Requests, BS4).
- Python Libraries for Web Scraping The Python libraries for web scraping fall into four groups: HTTP clients that fetch pages (Requests, httpx, aiohttp), parsers that extract data from…
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.
-
Check what you may collect
Use the site's official API or data export if it has one. Otherwise read its
robots.txtand 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). -
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.
-
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. -
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.
-
Repeat across pages
Follow the "next" link or the page number, or crawl from a list of URLs, with a pause between requests.
-
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:
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:
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 job | Use | Why |
|---|---|---|
| A few pages, once, no programming | A no-code tool (Octoparse, ParseHub) or a browser extension | Point and click; nothing to install or maintain |
| Server-rendered pages, any volume | A script: Python requests + BeautifulSoup, or Node.js + Cheerio | Fast, cheap per page, full control |
| The data appears only after JavaScript runs | The page's JSON request first, a headless browser (Playwright) if there is none | A browser costs several times the traffic and CPU of a plain request |
| Hard targets, or many sites with different layouts | A scraping API | Someone 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.
| Method | When it fits | Typical tools | Guide |
|---|---|---|---|
| No-code tool or browser extension | A few pages, no programming | Octoparse, ParseHub, point-and-click extensions | No-code web scrapers |
| Spreadsheet functions | Small tables into a sheet | Google Sheets IMPORTXML, Excel Power Query | Web scraping into Excel |
| HTTP request + HTML parser | Server-rendered pages, any volume | Python requests + BeautifulSoup, Node.js + Cheerio | BeautifulSoup tutorial |
| The page's own JSON API | Pages that load data in the background | Any HTTP client | Web scraping vs API |
| Headless browser | Pages built by JavaScript, clicks and scrolling | Playwright, Puppeteer, Selenium | Scrape dynamic web pages, what is a headless browser |
| Crawler framework | Whole sites, many pages, retries and pipelines | Scrapy, Crawlee, Colly | How to crawl a website, Scrapy tutorial |
| Command line | Quick checks, one page, shell scripts | curl, wget | cURL |
| Scraping API or AI extraction | Hard targets, or many different layouts | A web scraping API, an LLM | Scraper 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:
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 500If 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.
| Language | HTTP and parsing | Browser automation and frameworks | Guide |
|---|---|---|---|
| Python | requests, httpx, BeautifulSoup, lxml | Scrapy, Playwright, Selenium | Python, Python libraries |
| JavaScript / Node.js | fetch, Axios, Cheerio | Puppeteer, Playwright, Crawlee | JavaScript and Node.js |
| Java | HttpClient, jsoup | Selenium, Playwright for Java | Java |
| C# | HttpClient, HtmlAgilityPack, AngleSharp | Playwright for .NET, Selenium | C# |
| PHP | Guzzle, cURL, Symfony DomCrawler | Symfony Panther | PHP |
| Ruby | HTTParty, Nokogiri | Ferrum, Selenium | Ruby |
| Go | net/http, goquery | Colly, chromedp | Go |
| R | httr2, rvest | chromote | R |
| Rust | reqwest, scraper | chromiumoxide, headless_chrome | Rust |
| C and C++ | libcurl, libxml2 or Gumbo | Rarely used | Below |
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.
| Feature | Scraping pages | Pulling search records |
|---|---|---|
| What you request | Each detail URL, one page at a time | The request the site's search box sends, page by page |
| Example request | GET / | GET / |
| What comes back | HTML you parse with selectors | Usually JSON, with a query, a page number and a sort parameter |
| How to find it | The page URLs, a sitemap or category lists | Developer tools, Network tab, filter Fetch/XHR, then run a search |
| Example: 10,000 products | 10,000 requests | 100 requests of 100 records each |
| Fields | Everything the page shows | Only 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 scraper | Example | What it means for you |
|---|---|---|
| Login-only or paid content | Account pages, paywalled articles | Not public data: stay out without the owner's permission |
A 401 Unauthorized answer | An API or page that asks for credentials | The 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 browser | A private backend, internal reports | Nothing to scrape: the page never contains it |
| Challenge pages and CAPTCHAs | Cloudflare's Interstitial Challenge Page, Managed Challenge, Turnstile widget and JavaScript Detections | The site asks for proof of a human; a scraper that cannot pass it gets no data |
| Rate limits and IP reputation | Many requests from one IP, datacenter ranges | Requests slow down, fail or get blocked |
| Deliberately changing pages | Rotating class names, tokens, layouts | Scrapers 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.
| Storage | Good for |
|---|---|
| CSV or JSON Lines files | One-off jobs and hand-offs |
| A spreadsheet | Small datasets that people read and filter |
| SQLite or PostgreSQL | Recurring 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.
Is scraping a website legal?
Scraping public data is lawful in many cases, but the answer depends on the data, the site's terms, the method and the country: personal data, copyrighted content and data behind logins carry the most risk.
What you cannot or should not scrape, with the sources:
robots.txtis a request, not a lock. RFC 9309, the Robots Exclusion Protocol, says its rules "are not a form of access authorization" (RFC 9309). Respecting it is good practice; ignoring it does not by itself unlock anything.- Logged-in and non-public areas are where US computer-fraud law bites. In Van Buren v. United States (2021) the Supreme Court read the Computer Fraud and Abuse Act as being about areas of a computer you are not entitled to access (opinion); the Department of Justice's charging policy says that breaking a public website's terms of service is not, by itself, grounds for a CFAA prosecution (Justice Manual 9-48.000). In hiQ Labs v. LinkedIn (9th Cir. 2022), a ruling on a preliminary injunction, the court found serious questions as to whether scraping public profiles is "without authorization" under the CFAA (opinion); the case later ended in LinkedIn's favor on its contract claims (November 2022 ruling, December 2022 consent judgment).
- A deliberate barrier means ask. When a site puts data behind a login, a paywall or a challenge, use its official API, an export or the owner's permission.
The overview is in is web scraping legal, and the series in what data is legal and safe to scrape. This is not legal advice.
Guides on how to scrape a website
- Start here: how to build a web scraper, HTML scraping with CSS selectors and XPath, web scraping projects with code, web scraping best practices.
- Python: web scraping with Python, Python libraries for web scraping, BeautifulSoup tutorial, what is Scrapy, Scrapy tutorial, Python web crawler, dynamic JavaScript sites with Python.
- Browsers: what is a headless browser, headless browsers compared, headless browser scraping in Python and Go, what is Puppeteer, scraping with Puppeteer, what is Playwright, scraping with Playwright, what is Selenium, Selenium with Python, Puppeteer vs Playwright, Puppeteer alternatives.
- Other languages: JavaScript and Node.js, Java, C#, PHP, Ruby, Go, R, Rust, which language to choose.
- Techniques: dynamic web pages, how to crawl a website, build a web crawler, scrape images from a website, make web scraping faster, schedule and deploy scrapers.
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.
Every guide in this series
- What Is Puppeteer?
- Web Scraping With Python: Step-by-Step Tutorial
- What Is Scrapy?
- Web Scraping With Selenium and Python
- How to Crawl a Website
- What Is a Headless Browser?
- Web Scraping With Puppeteer
- Web Scraping With JavaScript and Node.js
- Web Scraping With Playwright
- Java Web Scraping
- Web Scraping Best Practices
- Python Web Crawler: From a Script to Scrapy
- PHP Web Scraping
- C# Web Scraping
- Puppeteer vs Playwright
- Web Scraping in R With rvest
- Scrapy Tutorial: Build Your First Spider
- How to Scrape Images From a Website
- BeautifulSoup Web Scraping Tutorial
- Web Scraping Projects With Code
- Web Scraping With Go: Colly and goquery
- Ruby Web Scraping
- How to Build a Web Scraper
- How to Scrape Dynamic JavaScript Websites With Python
- HTML Scraping With CSS Selectors and XPath
- How to Build a Web Crawler
- Python Libraries for Web Scraping
- Is Playwright Free? What It Is and What It Costs
- What Is Selenium?
- Puppeteer Alternatives: Playwright, Selenium, Python and Firefox Options
- Best Headless Browsers for Web Scraping
- Headless Browser Scraping in Python and Go
- Web Scraping in Rust
- Best Programming Language for Web Scraping
- How to Scrape Dynamic Web Pages
- Why Is My Web Scraper Slow? How to Make It Faster
- How to Schedule and Deploy Web Scrapers
- Puppeteer vs Selenium
- Web Scraping With Excel VBA and PowerShell
- Scraping JavaScript Pages With Scrapy
- Web Scraping Pagination
- Image Scraper in Python
- Scrapy vs BeautifulSoup vs Selenium vs Playwright
- Websites to Practice Web Scraping
- Cheerio Web Scraping Tutorial
- Asynchronous Web Scraping in Python
- Cheerio vs Puppeteer
- How to Scrape Hidden APIs and Embedded JSON
- What You Need to Start Web Scraping
- Scraping a Website Behind a Login With Python
- Python vs JavaScript for Web Scraping
- How to Scrape a Table From a Website
- Large-Scale Web Scraping
- Playwright vs Selenium vs Puppeteer
- Scraping Behind a Login: Cookies and Sessions
Related pages
Easy Trial: 1 GB for $2.95.
Try for the price of 1 GB, no subscription, traffic never expires.