Scrape in Python, analyse in rakoon-ds
rakoon-ds does not scrape, and says so. Write the scraper yourself, produce a CSV, and do everything after that with clicks
Objectives
By the end of this session you will be able to:
- Read a page's HTML before writing a single line of scraper
- Write a paginated scraper with requests and BeautifulSoup, with a stop condition
- Be polite: rate limit, timeout, and know what robots.txt does and does not say
- Produce a CSV whose types survive the import
- Profile, clean and model the scraped data without writing more code
- Write the ethical section of a report about data you collected yourself
Prerequisites
- A rakoon-ds account on https://rakoon-ds.apps.way-up.io (free, browser only, nothing to install), and the group join code your instructor gives you
- A recent Chrome, Edge or Firefox. Computation runs either in your own tab (browser engine) or on the server; the header pill tells you which
- The mission for this session, assigned to your group. Open a project, then the Mission button in the workshop header: the panel opens next to Report. Click Check after each step
- Python 3 with
requestsandbeautifulsoup4:pip install requests beautifulsoup4 - Practical work 3 finished (you know what a structured source looks like)
- Transformation, chart and algorithm names come from the rakoon-ds registry and are served in French even when the interface is in English. Every step below gives you the French label you will click and, in
code font, the registry key the mission checks against.
Data
books.toscrape.com, a sandbox built for this exercise. Checked on 2026-09-09: 50 pages of 20 books, 1 000 books in total; catalogue/page-51.html answers 404, which is your stop condition; there is no robots.txt (it answers 404 as well).
rakoon-ds has no scraping feature, and it will not get one: fetching a URL is one thing (Session 3 does it), driving a browser through paginated HTML is another. This session is the one place in the course where you write code, and the boundary is deliberate. Anyone who tells you a no-code tool scrapes is selling you something.
Timing
The steps below add up to the announced duration. If you fall behind, Step 1 to Step 3 are the ones that must be finished.
| # | What you do | Time |
|---|---|---|
| Step 1 | Look before you scrape | 10 min |
| Step 2 | Write the scraper | 20 min |
| Step 3 | Run it, and check the CSV | 10 min |
| Step 4 | Import and profile | 10 min |
| Step 5 | Clean and enrich, with clicks only | 15 min |
| Step 6 | The ethics section, and it is not optional | 10 min |
| Total | 75 min | |
Instructions
Step 1: Look before you scrape10 min
- Open catalogue/page-1.html in your browser and use the element inspector on one book.
- Find the container:
article.product_pod. Twenty per page. - Inside it, find where each field lives:
| Field | Selector | Note |
|---|---|---|
| title | h3 a, attribute title | the visible text is truncated with an ellipsis, the attribute is not |
| price | p.price_color | text is £51.77 |
| rating | p.star-rating, second CSS class | One to Five, as a word |
| availability | p.instock | text, with whitespace |
| link | h3 a, attribute href | relative, starts with ../ on some pages |
Check robots.txt: http://books.toscrape.com/robots.txt returns 404. No file means no stated rules, which is not the same thing as permission. On this site, permission is explicit: it exists to be scraped. On any other site, read the terms of use.
Step 2: Write the scraper20 min
Type it, do not paste it. Every line of this script is a decision you will have to defend.
"""Scrape books.toscrape.com into a CSV that rakoon-ds can import.
Le site existe pour cela : c'est un bac a sable public, sans robots.txt.
Sur un vrai site, on lit d'abord robots.txt et les conditions d'utilisation.
"""
import csv
import re
import time
import requests
from bs4 import BeautifulSoup
BASE = "http://books.toscrape.com/catalogue/"
STARS = {"One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5}
rows = []
for page in range(1, 100): # borne haute : on s'arrete sur un 404
r = requests.get(f"{BASE}page-{page}.html", timeout=20)
if r.status_code == 404: # la page 51 n'existe pas : 50 pages, 1000 livres
break
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
pods = soup.select("article.product_pod")
if not pods:
break
for pod in pods:
link = pod.select_one("h3 a")
price = pod.select_one("p.price_color").get_text(strip=True)
stars = pod.select_one("p.star-rating")["class"][1] # ex. ["star-rating", "Three"]
rows.append({
"title": link["title"],
"price_gbp": float(re.sub(r"[^0-9.]", "", price)), # "£51.77" -> 51.77
"rating": STARS.get(stars, 0),
"availability": pod.select_one("p.instock").get_text(strip=True),
"url": BASE + link["href"].replace("../", ""),
})
print(f"page {page} : {len(pods)} livres, total {len(rows)}")
time.sleep(0.5) # politesse : on ne martele pas le serveur
with open("books.csv", "w", newline="", encoding="utf-8") as fh:
writer = csv.DictWriter(fh, fieldnames=list(rows[0]))
writer.writeheader()
writer.writerows(rows)
print(f"{len(rows)} livres ecrits dans books.csv")
The four decisions worth naming:
- Stop condition: a 404 on the next page, not a hard-coded 50. The site may grow.
- Timeout: 20 seconds. Without it, one hung request hangs the whole run.
- Rate limit: half a second between pages. Fifty pages, twenty-five seconds. A scraper without a sleep is a small denial of service.
- Type conversion at the source:
£51.77becomes51.77,Threebecomes3. Doing it in Python is one line; doing it later in the studio costs two transformations.
Step 3: Run it, and check the CSV10 min
- Run the script. Expect 50 lines of progress and
1000 livres ecrits dans books.csv. - Open the CSV in a text editor, not in a spreadsheet. Check the header, the first row, the last row.
- Count the lines:
wc -l books.csvshould give 1001 (1 000 books plus the header). If a title contained a newline, this count would lie, exactly as it does on the California fire file of Practical work 2.
If you get fewer than 1 000 rows, do not fix it by widening the page range. Find out which page failed and why. A scraper that silently returns 940 rows is worse than one that crashes.
Step 4: Import and profile10 min
- New project
PW10 Books. - Add a dataset → ...or import a file →
books.csv. - Check the node: 1 000 x 5.
- Explore → Statistics: is
price_gbpread as a number? Israting? - Quality tab: any duplicates? any missing values? Is
titleflagged as an identifier?
If a numeric column arrived as text, that is what Convertir en nombre (to_number) is for, with a decimal separator selector for files written with commas. Fixing it in the scraper is better; fixing it here is possible.
Step 5: Clean and enrich, with clicks only15 min
- Catégoriser (seuils) (
categorize) onprice_gbp, thresholds20, 40, labelscheap, mid, expensive. - Discrétiser (bins) (
bin_numeric) onprice_gbp,quantile, 4 buckets. Compare the two results: the thresholds you chose against the thresholds the data chose. - Pin a Histogramme (
histogram) ofprice_gbp, and a Comptage / moyenne (barres) (bar) with column =rating, value =price_gbp, aggregationmean. - Answer, from the chart: do five-star books cost more? Would you have bet on that before looking?
Then a model, because you can: train a Forêt aléatoire (rf_clf) to predict your price category from rating and availability, with a Modèle de référence (classe majoritaire) (dummy_clf) beside it.
You will find that it barely beats the baseline, and that is the correct result: on a generated catalogue, price and rating are independent. A negative result you can defend is worth more than a positive one you cannot explain.
Step 6: The ethics section, and it is not optional10 min
You collected this data. Write the Données and Conclusion et limites sections of the report and answer all of these in writing:
- Where does the data come from, when did you collect it, and would you get the same thing tomorrow?
- Did the site allow it? How do you know? What would you have checked on a commercial site?
- What load did you put on the server, and how did you limit it?
- Does the data contain anything personal? What would change if it did?
- What can you legitimately publish: the numbers, the aggregates, the raw file?
- What is this dataset not evidence of? (a generated catalogue is not a book market)
Then insert the automatic Journal into the report: it rebuilds everything you did in the studio. Combined with your script, you have a reproducible pipeline from the web page to the model.
What you should have
- A working scraper with a stop condition, a timeout and a rate limit
books.csvwith exactly 1 000 rows and typed columns- The file imported, profiled and quality-checked in the studio
- One categorisation, one binning, two pinned charts, two models
- An ethics section that answers six questions, not one
- The
dep-10mission at 5 / 5
Deliverables
- Mission:
dep-10validated - The script (
.py) and the CSV it produced - Report: Données and Conclusion et limites sections, with the journal inserted
Bonus
- Follow the link of each book and scrape its category and description from the detail page. That is 1 000 extra requests: recompute your rate limit before you start.
- Rewrite the price parsing to handle a currency symbol you have not seen. What breaks first, your regex or your assumption?
- Compare the effort: this session took a script and twenty minutes; Session 3 imported 295 countries from an API in eighteen minutes with no code. When a structured source exists, scraping is the wrong tool.
- Read the View code tab on one of your trainings and the Notebook export of the branch: your click-only chain comes back out as Python. The boundary between the two worlds is thinner than it looks.
Resources
- Session 10 slides (the lecture this practical work follows)
- Course page: both programmes, all fifteen sessions
- rakoon-ds studio
- The Orange version of this exercise: same site, same script, and then Orange instead of rakoon-ds
- BeautifulSoup documentation
missions/dep-10.json