Comparison7 min read

Scrapy vs BeautifulSoup vs Selenium vs Playwright

Short answer

Beautiful Soup is a parser, Scrapy is a crawling framework, and Selenium and Playwright are browsers you drive from code, so they solve different parts of a scraping job. Use Requests with Beautiful Soup for a few pages, Scrapy for thousands of pages with concurrency, retries and exports built in, and Playwright or Selenium only when JavaScript builds the content. Any of them sends its requests through ProxyField residential proxies 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 8 sections
  1. The four tools at a glance
  2. Scrapy vs BeautifulSoup: the same job in both
  3. When Beautiful Soup is enough
  4. When Scrapy pays off
  5. When you need Selenium or Playwright
  6. Which scraping tool should you choose?
  7. Proxies for all four
  8. Scrapy vs BeautifulSoup vs Selenium vs Playwright FAQ

The four tools at a glance

All four are open source. Current Scrapy, Selenium and Playwright releases need Python 3.10 or later, and Beautiful Soup 4.15.0 needs Python 3.7 or later. Versions are from PyPI.

FeatureBeautiful SoupScrapySeleniumPlaywright
What it isHTML and XML parserCrawling and scraping frameworkBrowser automation (W3C WebDriver)Browser automation (own protocol)
Version, license4.15.0, MIT2.19.0, BSD-3-Clause4.51.0, Apache-2.01.64.1, Apache-2.0
Downloads pagesNo; pair it with Requests or httpxYes, asynchronouslyYes, through a real browserYes, through a real browser
Runs JavaScriptNoNo (add scrapy-playwright)YesYes
ConcurrencyYour own codeBuilt in (CONCURRENT_REQUESTS)One browser per session; Selenium Grid to scaleMany contexts per browser
Retries, throttling, exportsYour own codeBuilt in (retry middleware, AutoThrottle, feed exports to JSON, CSV, XML)Your own codeYour own code
Learning curve (our estimate)An afternoonA few daysA day or twoA day or two
Best forSmall jobs, one-off scripts, parsing HTML you already haveLarge crawls of static pagesExisting Selenium teams, real SafariJavaScript-heavy pages, new projects

Beautiful Soup describes itself as "a Python library for pulling data out of HTML and XML files" (docs); Scrapy as "a high-level Web Crawling and Web Scraping framework" (PyPI). That one line explains most of the comparison: a parser reads pages, a framework runs the whole crawl.

Scrapy vs BeautifulSoup: the same job in both

The task: collect the title and price of all 1,000 books on Books to Scrape, a practice site with 50 pages of 20 books.

With Requests and Beautiful Soup, you write the loop, the pagination and the pause yourself:

Python
# pip install requests beautifulsoup4
import time
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

url = "https://books.toscrape.com/catalogue/page-1.html"
books = []
while url:
    soup = BeautifulSoup(requests.get(url, timeout=30).content, "html.parser")
    for card in soup.select("article.product_pod"):
        books.append({"title": card.h3.a["title"], "price": card.select_one(".price_color").text})
    nxt = soup.select_one("li.next a")
    url = urljoin(url, nxt["href"]) if nxt else None
    time.sleep(0.5)  # one page at a time, with a pause
print(len(books), books[0])

With Scrapy, you declare what to extract and which links to follow; the framework schedules the requests, runs several at once, retries failures and writes the file:

Python
# pip install scrapy, then: scrapy runspider books_spider.py
import scrapy

class BooksSpider(scrapy.Spider):
    name = "books"
    start_urls = ["https://books.toscrape.com/catalogue/page-1.html"]
    custom_settings = {"CONCURRENT_REQUESTS": 8, "AUTOTHROTTLE_ENABLED": True,
                       "FEEDS": {"books.json": {"format": "json"}}}

    def parse(self, response):
        for card in response.css("article.product_pod"):
            yield {"title": card.css("h3 a::attr(title)").get(),
                   "price": card.css(".price_color::text").get()}
        yield from response.follow_all(css="li.next a", callback=self.parse)

We ran both on October 23, 2026 (Requests 2.34.2, Beautiful Soup 4.15.0, Scrapy 2.19.0). Both saved all 1,000 books. The sequential script with a 0.5 s pause took about 61 s; the Scrapy spider, with 8 concurrent requests and AutoThrottle adjusting the pace, took about 19 s. That is one run on one small site, not a benchmark: what you should take from it is that Scrapy's gain comes from running requests in parallel, which you would otherwise have to build yourself.

One detail the test caught: pass response.content (bytes) to Beautiful Soup, not response.text. Requests guessed the wrong encoding for this site and turned "£" into "£"; with bytes, Beautiful Soup reads the charset from the page.

When Beautiful Soup is enough

  • You scrape tens or hundreds of pages, once or on a schedule.
  • You already have the HTML, from a file, an email, an API field or a browser.
  • The script lives inside a larger program, a notebook or a data pipeline, and you do not want a framework's project layout.

Beautiful Soup is forgiving with broken HTML and easy to read. For speed on large documents, use it with the lxml parser, or move to lxml or parsel directly; more in Beautiful Soup web scraping.

When Scrapy pays off

  • Thousands to millions of pages, where concurrency, retries and deduplication of URLs matter.
  • Crawls that follow links across a site, with rules for what to follow (CrawlSpider).
  • Recurring jobs that need clean exports, item pipelines, logging and stats.
  • Scrapy also parses: its CSS and XPath selectors (parsel) replace Beautiful Soup inside a spider, though you can still call Beautiful Soup from a callback if you prefer its API.

Scrapy has a learning curve: spiders, callbacks, settings and middlewares. What Scrapy is explains the parts, and the Scrapy tutorial builds a project step by step. For runs across several servers, see large-scale web scraping.

When you need Selenium or Playwright

Neither Beautiful Soup nor Scrapy runs JavaScript. If the data you want is missing from the page source, you have two routes:

  1. Find the data source

    Scrapy's docs advise this first: use the browser's network tool to find the request that carries the data and reproduce it (Scrapy: dynamic content). Often it is a JSON API, which is faster to scrape than any page; see how to scrape hidden APIs and embedded JSON.

  2. Render the page

    Use Playwright or Selenium to run the page in a browser. Inside Scrapy, the scrapy-playwright plugin (0.0.48 on PyPI) renders selected requests with Playwright while Scrapy keeps scheduling, retries and exports.

Between the two browsers, Playwright is the easier start for new Python scrapers, with auto-waiting and request blocking built in; Selenium suits teams that already run it. The full comparison is in Playwright vs Selenium vs Puppeteer, and the same parser-or-browser question for Node.js in Cheerio vs Puppeteer.

Which scraping tool should you choose?

Your jobPick
Under a few hundred static pagesRequests + Beautiful Soup
Thousands of static pages, recurring crawlsScrapy
Data in a JSON API behind the pageRequests or httpx, no parser needed
JavaScript-built pages, a few hundredPlaywright
JavaScript-built pages at scaleScrapy + scrapy-playwright, or Playwright with a job queue
Existing Selenium code or real SafariSelenium

More Python options, including httpx, lxml and selectolax, are in our guide to Python scraping libraries.

Proxies for all four

Beautiful Soup has no network code, so the proxy goes into Requests (proxies={"https": "http://<login>:<password>@gate.proxyfield.io:7000"}). Scrapy takes it per request in meta["proxy"] or through its HttpProxyMiddleware (Scrapy proxy setup). Playwright and Selenium take it at browser launch (Playwright, Selenium). With the username <login>-country-us-city-new_york, the ProxyField gateway picks an exit IP in New York. 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.

ProxyField gives every request a new IP, or a sticky session from 30 s to 36 h, over HTTP, HTTPS or SOCKS5, with targeting by country, region (state) and city and unlimited concurrent threads, which suits Scrapy's parallel requests. Residential proxies cost $2.95/GB for 1 GB and fall to $1.95/GB from 1,000 GB, with no subscription; traffic never expires, and all purchases are final. Start with residential proxies and the Easy Trial: 1 GB for $2.95.

Scrapy vs BeautifulSoup vs Selenium vs Playwright FAQ

Is Scrapy better than BeautifulSoup?

ProxyField residential proxies from $1.95/GB work with both, and Scrapy is better than Beautiful Soup for crawls of thousands of pages, while Beautiful Soup suits small jobs. In one run on a practice site with 1,000 books, Scrapy with 8 concurrent requests finished in about 19 s against about 61 s for a sequential Requests and Beautiful Soup script, because Scrapy runs requests in parallel and adds retries and exports.

Can I use Scrapy with BeautifulSoup?

Yes. Inside a spider callback, pass response.text to BeautifulSoup() and parse as usual (Scrapy decodes response.text from the page's declared encoding itself), while Scrapy keeps scheduling, retries and exports. Most spiders skip this, because Scrapy's own CSS and XPath selectors do the same job without the extra parsing step.

Is Scrapy or Selenium better for scraping?

Scrapy, for static pages: it fetches many pages at once with little CPU and memory. Selenium is for pages that need a real browser to run JavaScript, log in or scroll. Many teams use Scrapy for the crawl and a browser only for the pages that need one.

Should I use Scrapy or Playwright?

Use Scrapy when the data is in the HTML or a JSON API and you need many pages; use Playwright when JavaScript builds the page or you must click and scroll. For JavaScript-heavy sites at scale, combine them with scrapy-playwright.

What is the difference between Selenium, Playwright and BeautifulSoup?

Beautiful Soup parses HTML you already downloaded and runs no JavaScript. Selenium and Playwright drive a real browser that loads the page, runs its scripts and lets you click, type and scroll; Playwright adds auto-waiting and a test runner, Selenium adds real Safari and Selenium Grid.

Which scraping framework should I choose?

In Python, Scrapy is the main full framework: scheduling, concurrency, retries, pipelines and exports in one package. Pick it when you crawl many pages regularly; for small scripts, Requests with Beautiful Soup is simpler, and for JavaScript pages add Playwright.

When should I choose Requests with BeautifulSoup over Scrapy?

When the job is small, runs inside another program or a notebook, or parses HTML you already have. A 15-line script is easier to read and change than a Scrapy project, and for a few hundred pages the speed difference rarely matters.

Is Scrapy faster than Selenium?

Yes, for pages that do not need JavaScript: Scrapy downloads only the HTML and fetches many pages concurrently, while Selenium loads every page in a full browser with its scripts, images and fonts. Selenium's speed comes from parallel browsers, which cost far more CPU and memory.

How much does it cost to operate a Selenium farm at scale vs a Scrapy crawler?

A browser farm costs much more to run, because each browser needs CPU and memory and downloads whole pages, which also raises per-GB proxy traffic. A Scrapy crawler fetches HTML only and runs hundreds of requests from one process. Measure your own pages, since page weight decides most of the difference.

Scrapy vs Puppeteer: which is best?

They do different jobs: Scrapy is a Python crawling framework for many static pages, Puppeteer a Node.js library that drives Chrome or Firefox for JavaScript-built pages. Pick Scrapy for volume and Puppeteer, or Playwright from Python, for rendering.

Easy Trial: 1 GB for $2.95.

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