← All samples

Polite Web Scraper

PythonScraping

Collects 100 book listings (title, price, rating, stock) from books.toscrape.com, a sandbox site made for scraping practice, with a delay between requests.

Run it

cd samples/book-scraper
python scrape_books.py 5   # pages; needs requests, beautifulsoup4

Files: books.csv · scrape_books.py

Output (first 10 of 100 rows)

titleprice_gbpratingin_stockurl
A Light in the Attic51.773Truehttps://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html
Tipping the Velvet53.741Truehttps://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html
Soumission50.11Truehttps://books.toscrape.com/catalogue/soumission_998/index.html
Sharp Objects47.824Truehttps://books.toscrape.com/catalogue/sharp-objects_997/index.html
Sapiens: A Brief History of Humankind54.235Truehttps://books.toscrape.com/catalogue/sapiens-a-brief-history-of-humankind_996/index.html
The Requiem Red22.651Truehttps://books.toscrape.com/catalogue/the-requiem-red_995/index.html
The Dirty Little Secrets of Getting Your Dream Job33.344Truehttps://books.toscrape.com/catalogue/the-dirty-little-secrets-of-getting-your-dream-job_994/index.html
The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull17.933Truehttps://books.toscrape.com/catalogue/the-coming-woman-a-novel-based-on-the-life-of-the-infamous-feminist-victoria-woodhull_993/index.html
The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics22.64Truehttps://books.toscrape.com/catalogue/the-boys-in-the-boat-nine-americans-and-their-epic-quest-for-gold-at-the-1936-berlin-olympics_992/index.html
The Black Maria52.151Truehttps://books.toscrape.com/catalogue/the-black-maria_991/index.html

Code

"""Scrape books.toscrape.com (a sandbox site built for scraping practice) politely: title, price, rating, stock, URL."""
import csv, time, sys
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup

BASE = "https://books.toscrape.com/catalogue/page-{}.html"
RATING = {"One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5}

def scrape(pages=5, out="books.csv"):
    s = requests.Session(); s.headers["User-Agent"] = "KirkDaviesStudio-sample-scraper/1.0"
    rows = []
    for n in range(1, pages + 1):
        url = BASE.format(n)
        r = s.get(url, timeout=20); r.raise_for_status(); r.encoding = "utf-8"
        soup = BeautifulSoup(r.text, "html.parser")
        for b in soup.select("article.product_pod"):
            a = b.h3.a
            rows.append({
                "title": a["title"],
                "price_gbp": float(b.select_one(".price_color").text.strip().lstrip("£Â")),
                "rating": RATING[b.select_one(".star-rating")["class"][1]],
                "in_stock": "In stock" in b.select_one(".availability").text,
                "url": urljoin(url, a["href"]),
            })
        print(f"page {n}: {len(rows)} books so far"); time.sleep(1)
    with open(out, "w", newline="", encoding="utf-8") as f:
        w = csv.DictWriter(f, fieldnames=rows[0].keys()); w.writeheader(); w.writerows(rows)
    print(f"saved {len(rows)} rows to {out}")

if __name__ == "__main__":
    scrape(int(sys.argv[1]) if len(sys.argv) > 1 else 5)