The brief
Toko Kita is a small Indonesian online shop. It started with coffee and kitchen equipment, and this year it began selling phones and audio gear too. That puts it up against Nusantara Gadget, a bigger shop that sells nothing but electronics. When Nusantara Gadget drops a price, Toko Kita's customers notice before the owner does.
The owner wants a price watch: a small set of scripts that collect Nusantara Gadget's prices and stock levels, so the team can see each morning where Toko Kita is too expensive. You'll build it in three tasks against the practice copy of their site at https://nusantara-gadget.test, the same site the scraping track uses.
Scraping someone else's site comes with responsibilities, and this project takes them seriously. Their robots.txt asks for a Crawl-delay of 1 second, and their product pages answer 429 Too Many Requests to anyone who asks for more than four pages a second. Where a site offers a JSON API, it's usually kinder (and more reliable) to use it instead of the HTML.
How the tasks work
Each task is checked automatically, like the module questions. The practice site runs inside the page with a virtual clock, so waiting a second costs no real time. Waiting still matters, though: the site counts the requests, and if you go too fast it starts refusing them, exactly as a real one would. The tickets say what to collect and in what shape. There are hints if you get stuck, but try each task without opening the solution first.
The tasks
| # | Task | Main skills |
|---|---|---|
| 1 | The whole catalogue | Locators, attributes, following "Next" across pages |
| 2 | Stock checks, politely | Detail pages, status codes, honouring Crawl-delay |
| 3 | Our prices against theirs | Calling a JSON API with requests, comparing, saving CSV |
The site
These are the parts of Nusantara Gadget the tasks use:
/productslists 12 products per page. Each product is anarticle.product-cardwith adata-idattribute, and inside it.title(the name, as a link),.brand,.price(with the number indata-price),.rating(with the number indata-rating) and a.stockelement that has the classin-stockorsold-out. While there's another page, there's ana.nextlink to it. On the last page, "Next" is aspan.next.disabledinstead, so there's noa.nextto click./product/<id>is one product's detail page. It has.product-title,.pricewithdata-price, and a.stockparagraph that reads likeIn stock: 18 leftorSold out. An id that doesn't exist answers 404./api/productsanswers JSON:{"page": ..., "per_page": ..., "total": ..., "total_pages": ..., "items": [...]}. It takescategory,pageandper_page(at most 50) as query parameters, and each item hasid,name,brand,category,price,rating,stockand more.
When you're ready, open Task 1.