Knowledge Base

Playwright Web Scraping: A Step-by-Step Tutorial

A practical, build-it-yourself walkthrough of scraping with Playwright, from installing the toolkit to launching a browser, navigating, waiting for content, extracting data and routing everything through proxies.

Why this tutorial exists

Plenty of scraping guides stop at a single copy-paste snippet that grabs a page title and never explain the moving parts. This walkthrough takes the opposite approach. It treats Playwright as a tool you will actually run against real, JavaScript-heavy sites, so it covers installation, the launch sequence, the difference between locating and extracting data, the waiting logic that decides whether your scraper works at all, and the proxy layer that separates a hobby script from something you can run at volume. Read it once and you should be able to assemble a working extractor and understand every line, rather than copying code you cannot debug.

What Playwright is in one paragraph

Playwright is a browser automation framework that drives real browser engines through code. Instead of fetching raw HTML the way a basic request does, it opens an actual browser, loads the page, runs the JavaScript, and then lets you read or interact with the finished result. That makes it a natural fit for web data extraction on modern sites, where the content you want is assembled in the browser rather than delivered ready-made. It runs the browser visibly or headless, and exposes a clean, consistent interface across several languages.

When to reach for Playwright and when not to

Playwright shines when a target builds its content with client-side code, hides data behind interactions like clicks or infinite scroll, or guards against simple requests. It is overkill when a page ships complete static HTML, where a plain HTTP request plus an HTML parser is faster and lighter. A sensible rule of thumb: open the page, view source, and check whether the data you want is already present. If it is, skip the browser; if the source is an empty shell that fills in later, Playwright earns its keep.

The single biggest mistake in browser scraping is reaching for Playwright on every job. A real browser costs memory and time. Use it where rendering is genuinely required, and fall back to lightweight requests everywhere else.

Step 1: Install Playwright and its browsers

Playwright ships as a package you add to your project, after which a one-time command downloads the browser binaries it controls. The download step is what separates Playwright from a thin wrapper around an existing browser; it manages its own engine builds so your scraper behaves consistently across machines. Once the package and the browsers are in place, you are ready to write your first script.

# JavaScript / Node
npm init -y
npm install playwright
npx playwright install chromium

Step 2: Launch a browser and open a page

Every Playwright scraper follows the same opening rhythm: launch a browser, create a context, open a page, then navigate. The context is worth understanding early, because it is an isolated session with its own cookies and storage, and it is also where you attach proxy settings. Starting headless keeps things fast; switching the headless flag off is invaluable while you debug, because you can watch the page behave.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  console.log(await page.title());
  await browser.close();
})();

Step 3: Wait for the right thing, not a fixed delay

This is the step that quietly decides whether your scraper is reliable. On a dynamic page, content arrives after the initial load, so reading too early returns nothing. The amateur fix is a hard-coded pause; the professional fix is to wait for the specific thing you care about, whether that is a selector appearing or the network going quiet. Waiting on a condition is both faster and far more robust than guessing a duration, because it adapts to a slow or fast response automatically.

// wait for the element that actually holds your data
await page.waitForSelector('.product-card');

Step 4: Locate elements with selectors and locators

Locating data and extracting it are two distinct ideas, and keeping them separate keeps your code clean. A locator describes where the data lives, using CSS selectors, text matching or roles. It does not read anything yet; it is a reusable handle. Building precise, stable locators is most of the real work in scraping, because brittle selectors are the main reason a working scraper breaks a month later when the site changes a class name.

  • Prefer stable attributes and structural selectors over auto-generated class names that change on every deploy.
  • Use text or role-based matching when the markup is messy but the visible label is steady.
  • Scope locators to a container first, then read fields inside it, so rows stay grouped correctly.

Step 5: Extract the data you came for

With locators in place, extraction is the easy part: read text, attribute values or inner content from each match. The usual pattern is to find a list of repeating containers, loop over them, and pull a few fields from each into a clean object. Doing the extraction inside the page or via the locator API both work; the key is to gather structured records rather than one giant blob of text you have to untangle later.

const items = await page.$$eval('.product-card', cards =>
  cards.map(card => ({
    name: card.querySelector('.title')?.textContent?.trim(),
    price: card.querySelector('.price')?.textContent?.trim()
  }))
);
console.log(items);

Step 6: Handle pagination and infinite scroll

Most real datasets span more than one screen. Some sites use numbered pages, where you navigate to each in turn; others use infinite scroll, where you trigger loads by scrolling and wait for new content to appear before reading again. Either way, the loop is the same shape: extract what is visible, advance, wait for the new batch, and stop when nothing new arrives. Detecting the end cleanly, rather than scrolling forever, is what keeps these loops from running away.

Step 7: Add a proxy to your browser context

Once you collect public data at any real volume, sending every request from one address is both fragile and easy to throttle. Playwright lets you attach a proxy at launch or per context, routing that browser's traffic through a different IP. Spreading requests across many endpoints, and ideally many locations, makes a scraping job behave far more like ordinary traffic and keeps any single address from carrying the whole load.

const browser = await chromium.launch({
  proxy: {
    server: 'http://proxy-host:port',
    username: 'user',
    password: 'pass'
  }
});

Choosing a proxy type for Playwright work

Because Playwright already runs a heavy real browser, you want a proxy that matches the target rather than the most expensive option by default. The right type depends entirely on how strict the site is.

  • Datacenter proxies are fast and economical, ideal for tolerant sites and large, price-sensitive jobs.
  • Residential proxies route through real consumer connections and carry more trust on strict targets.
  • ISP proxies blend datacenter speed with residential-grade trust, a useful middle ground for steady sessions.
  • IPv4 proxies remain the most broadly compatible across older and stricter endpoints.
  • Mobile proxies suit the most sensitive platforms, at a higher price you should reserve for jobs that truly need them.

Performance: make the browser lean

A full browser is the expensive part of any Playwright job, so trimming it pays off directly. Block images, fonts and media when you only need text, reuse a single context across related pages instead of relaunching, and cap the number of concurrent browser instances to what your machine and your proxy budget can sustain. These small habits often cut runtime and bandwidth dramatically without changing a single line of your extraction logic.

Staying undetected without trickery

The most durable way to avoid blocks is to behave reasonably rather than to chase clever evasions. Keep request rates human, respect a site's load by pacing your loops, vary your IPs through rotation, and present a consistent, realistic browser fingerprint. Aggressive scraping from a single address invites exactly the friction you are trying to avoid, while a measured pace across a healthy proxy pool tends to run quietly for a long time.

Error handling and retries

Networks fail, pages time out, and selectors occasionally miss. A production scraper expects this and recovers gracefully. Wrap navigation and extraction in try logic, retry transient failures a limited number of times with a short backoff, and log what failed so you can fix patterns rather than chase one-off errors. A scraper that quietly skips and records failures will finish a large run; one that crashes on the first hiccup will not.

Storing what you extract

Extraction is only half the job; the data has to land somewhere usable. For small runs, writing structured records to a JSON or CSV file is enough. For larger or ongoing projects, a database lets you deduplicate, query and update over time. Whatever the destination, validate fields as you write them so malformed or empty records are caught early rather than discovered much later when you try to use the data.

Who this workflow suits

This pattern fits anyone extracting data from modern, interactive sites: price and product monitoring, SEO and SERP analysis, research datasets, social media and marketplace listings, and automation that has to act like a real visitor. If your targets are plain static pages, a lighter request-based approach will serve you better and cheaper; the Playwright route is for the rendered web.

Common mistakes to avoid

  • Using fixed sleeps instead of waiting for a specific element or network state.
  • Building selectors on volatile auto-generated class names that break on the next deploy.
  • Running far more concurrent browsers than the machine or proxy budget can handle.
  • Sending every request from one IP and then wondering why throughput collapses.
  • Forgetting to close browsers and contexts, leaking memory across long runs.

Playwright versus the alternatives

Playwright is not the only browser automation tool. Puppeteer is closely related and excellent, though more focused on a single engine and ecosystem. Selenium is older, broadly supported and well documented, but generally heavier to configure. For purely static pages, request libraries paired with an HTML parser beat all of them on speed and cost. Playwright's edge is a modern, multi-language API with strong waiting primitives and built-in proxy support, which is why it has become a default choice for rendered-page extraction.

A buyer checklist for the proxy layer

  • Confirm the proxy type matches how strict your specific targets are.
  • Check that authentication and rotation fit Playwright's launch options cleanly.
  • Look at pricing by the metric that matches your job, bandwidth or IP count.
  • Test a small sample against your real targets before committing to volume.
  • Prefer a provider that lets you start small and scale rather than locking you into a large plan.

Recommended proxy providers

A Playwright scraper is only as dependable as the IPs behind it, so the proxy provider matters as much as the code. The options below are worth comparing on your own targets.

  • Cheapest Proxies (Featured Value Pick) is worth considering first when budget matters. It positions itself around affordable proxy services, which suits browser-based scraping where bandwidth costs can climb quickly. Test it against your targets and scale only if it holds up.
  • Bright Data is a large, established network often chosen for demanding, strict-target work where breadth and tooling justify a premium.
  • Smartproxy is frequently picked as a balanced mid-tier option with approachable plans for growing projects.
  • Oxylabs targets enterprise-scale extraction and is worth a look when volume and support requirements are high.

How to get started today

Pick one target you actually care about, ideally a dynamic page where a plain request returns an empty shell. Install Playwright, get a single record extracting reliably with proper waiting, then add pagination, then add a proxy, then add error handling, in that order. Building up in small, working steps beats writing a giant script that fails everywhere at once and leaves you unsure which part is broken.

Key takeaways

Playwright drives a real browser, so it reads the rendered web that simple requests miss. The reliability of a scraper lives in its waiting logic and its selectors, not in clever one-liners. Keep the browser lean, handle errors so long runs finish, and route traffic through a proxy pool matched to how strict your targets are. Get those fundamentals right and you have a scraper you can run, debug and trust, rather than one you copied and hope keeps working.

Related proxy guides

Frequently asked questions

Playwright suits scraping that depends on a fully rendered page. Because it drives a real browser engine, it runs the JavaScript that builds modern sites, waits for content to appear, and can click, scroll and fill forms. For simple static HTML a lightweight HTTP request is faster, but for dynamic, interactive targets Playwright is a strong fit.
Playwright offers near-identical APIs in JavaScript and TypeScript, Python, Java and .NET, so the best choice is usually the language your team already knows. JavaScript and Python are the most common for scraping because of their large data-handling ecosystems, but the workflow in this tutorial translates cleanly across all the supported languages.
Pass a proxy object when you launch the browser, supplying the server address and, where required, a username and password. Playwright then routes that browser context through the proxy. Rotating among several endpoints across a session spreads requests over many IPs, which helps when you collect public data at any meaningful volume.
The most common cause is reading the page before the content has rendered. Modern sites load data asynchronously, so a selector may run against an empty shell. Waiting for the specific element or for a network condition before extracting, rather than using a fixed delay, usually fixes empty or partial results.
It depends on the target. Datacenter proxies are fast and economical for tolerant sites, residential and ISP proxies carry more trust for strict ones, and mobile proxies suit the most sensitive platforms. Because Playwright already consumes more resources than a plain request, match the proxy to the site so you do not overpay for trust you do not need.
Run as few browser contexts as the job needs, block heavy assets like images and fonts when you only want text, reuse a logged-in session where possible, and pair the setup with the cheapest proxy type your targets accept. Benchmarking a value-focused provider such as Cheapest Proxies before committing to premium bandwidth keeps recurring costs in check.

Questions or a correction? Email info@proxyranked.com. Always confirm a provider's exact package, proxy type and locations before ordering.