Web Scraping
Web scraping means programmatically downloading a web page and extracting the data you need from its HTML, instead of copying it out by hand. It is useful whenever a site has information you want but does not expose through an API. The classic Python combo is requests to download the page and BeautifulSoup to parse the HTML and pull out the pieces you care about.
Installing BeautifulSoup
Install
pip install beautifulsoup4
The package is called beautifulsoup4 on PyPI but imported as bs4.
Downloading and parsing a page
The workflow has two steps: fetch the raw HTML with requests, then hand that HTML to BeautifulSoup to turn it into a navigable tree of elements.
fetch_and_parse.py
import requests
from bs4 import BeautifulSoup
response = requests.get("https://example.com", timeout=5)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
print(soup.title.text) # the page's <title> textSelecting elements
Once you have a soup object, BeautifulSoup gives you two main ways to find things: .find() / .find_all() for tag-and-attribute lookups, and .select() for CSS selectors if you already think in terms of div.class or #id.
Method | Returns | Example |
|---|---|---|
| First matching element or |
|
| List of all matching elements |
|
| List of elements matching a CSS selector |
|
| First element matching a CSS selector |
|
A full worked example
To keep this example self-contained and runnable without depending on a live website, the HTML is a hardcoded string representing a small product listing page.
scrape_products.py
from bs4 import BeautifulSoup
html = """
<html>
<body>
<div class="product-list">
<div class="product" data-id="101">
<h2 class="name">Wireless Mouse</h2>
<span class="price">$19.99</span>
</div>
<div class="product" data-id="102">
<h2 class="name">Mechanical Keyboard</h2>
<span class="price">$89.99</span>
</div>
<div class="product" data-id="103">
<h2 class="name">USB-C Hub</h2>
<span class="price">$34.50</span>
</div>
</div>
</body>
</html>
"""
soup = BeautifulSoup(html, "html.parser")
products = []
for card in soup.select("div.product"):
products.append({
"id": card["data-id"],
"name": card.find("h2", class_="name").text.strip(),
"price": card.find("span", class_="price").text.strip(),
})
for product in products:
print(product)
# {'id': '101', 'name': 'Wireless Mouse', 'price': '$19.99'}
# {'id': '102', 'name': 'Mechanical Keyboard', 'price': '$89.99'}
# {'id': '103', 'name': 'USB-C Hub', 'price': '$34.50'}card["data-id"] reads an HTML attribute like a dictionary key, .find() narrows to a specific child tag, and .text pulls out just the visible text, stripped of surrounding whitespace with .strip().
Respect the site you're scraping
When requests + BeautifulSoup isn't enough
Scrapy — a full scraping framework for crawling many pages at scale, with built-in concurrency, retries, and pipelines for storing results.
Selenium / Playwright — browser automation tools that actually render JavaScript. Use these when the data you need is injected into the page by client-side JavaScript after the initial HTML loads, so plain
requestsnever sees it.