#ExtractSummit2026 The world's largest web scraping conference returns. Austin Oct 7–8 · Dublin Nov 10–11.

Register now
Data Services
Pricing
Login
Try Zyte APIContact Sales
  • Unblocking and Extraction

    Zyte API

    The ultimate API for web scraping. Avoid website bans and access a headless browser or AI Parsing

    Ban Handling

    Headless Browser

    AI Extraction

    SERP

    Enterprise

    DocumentationSupport

    Hosting and Deployment

    Scrapy Cloud

    Run, monitor, and control your Scrapy spiders however you want to.

    Coding Agent Add-Ons

    Agentic Web Data

    Plugins that give coding agents the context to build production Scrapy projects. Starts with Claude Code.

  • Data Services
  • Pricing
  • Browse

    • BlogArticles, podcasts, videos
    • Case studiesCustomer outcomes
    • White papersIn-depth reports
    • DocumentationGuides & API reference
    • EventsConferences, webinars, recordings

    Subscribe

    • NewsletterSwiftly delivered
    • Join our community2,000+ web scraping engineers
  • Product and E-commerce

    From e-commerce and online marketplaces

    Data for AI

    Collect and structure web data to feed AI

    Job Posting

    From job boards and recruitment websites

    Real Estate

    From Listings portals and specialist websites

    News and Article

    From online publishers and news websites

    Search

    Search engine results page data (SERP)

    Social Media

    From social media platforms online

  • Meet Zyte

    Our story, people and values

    Contact us

    Get in touch

    Support

    Knowledge base and raise support tickets

    Terms and Policies

    Accept our terms and policies

    Open Source

    Our open source projects and contributions

    Web Data Compliance

    Guidelines and resources for compliant web data collection

    Join the team building the future of web data
    We're Hiring
    Trust Center
    Security, compliance & certifications
Login
Try Zyte APIContact Sales
All articles
AI71, 71 articles
Data quality15, 15 articles
Developer interest59, 59 articles
Integration2, 2 articles
Open-source50, 50 articles
Proxies35, 35 articles
Scraping practice35, 35 articles
Scraping strategy47, 47 articles
Search results4, 4 articles
Web data74, 74 articles
Web scraping APIs49, 49 articles
Scrapy47, 47 articles
Scrapy Cloud26, 26 articles
Web Scraping Copilot11, 11 articles
Zyte API65, 65 articles
AI & Machine Learning3, 3 articles
Automotive3, 3 articles
E-commerce & retail33, 33 articles
Entertainment & Streaming2, 2 articles
Financial Services8, 8 articles
Government2, 2 articles
Market Research & Intelligence7, 7 articles
Media & publishing11, 11 articles
Real Estate2, 2 articles
Recruitment & HR3, 3 articles
Transportation & Logistics2, 2 articles
Travel & hospitality3, 3 articles
iPaaS2, 2 articles
Large language model29, 29 articles
MCP3, 3 articles
Python110, 110 articles
Scraping at Scale7, 7 articles
Scraping Fundamentals11, 11 articles
Web Scraping Industry Report20, 20 articles

Appearance

Discord Community
BlogLearnThe Modern Scrapy Developer's Guide (Part 1): Building Your First Spider
LearnScraping practice

The Modern Scrapy Developer's Guide (Part 1): Building Your First Spider

J

John Rooney

·

4 min read · December 16, 2025

The Modern Scrapy Developer's Guide (Part 1): Building Your First Spider

Scrapy can feel daunting. It's a massive, powerful framework, and the documentation can be overwhelming for a newcomer. Where do you even begin?

In this definitive guide, we will walk you through, step-by-step, how to build a real, multi-page crawling spider. You will go from an empty folder to a clean JSON file of structured data in about 15 minutes. We'll use modern, async/await Python and cover project setup, finding selectors, following links (crawling), and saving your data.

What We'll Build

We will build a Scrapy spider that crawls the "Fantasy" category on books.toscrape.com, follows the "Next" button to crawl every page in that category, follows the link for every book, and scrapes the name, price, and URL from all 48 books, saving the result to a clean books.json file.

Here's a preview of our final spider code:

1# The final spider we'll build
2import scrapy
3
4class BooksSpider(scrapy.Spider):
5    name = "books"
6    allowed_domains = ["toscrape.com"]
7
8    url: str = "https://books.toscrape.com/catalogue/category/books/fantasy_19/index.html"
9
10    async def start(self):
11        yield scrapy.Request(self.url, callback=self.parse_listpage)
12
13    async def parse_listpage(self, response):
14        product_urls = response.css("article.product_pod h3 a::attr(href)").getall()
15        for url in product_urls:
16            yield response.follow(url, callback=self.parse_book)
17
18        next_page_url = response.css("li.next a::attr(href)").get()
19        if next_page_url:
20            yield response.follow(next_page_url, callback=self.parse_listpage)
21
22    async def parse_book(self, response):
23        yield {
24            "name": response.css("h1::text").get(),
25            "price": response.css("p.price_color::text").get(),
26            "url": response.url
27        }
Copy

On This Page (Table of Contents)

  • Prerequisites & Setup
  • Step 1: Initialize Your Project
  • Step 2: Configure Your Settings
  • Step 3: Finding Our Selectors (with scrapy shell)
  • Step 4: Building the Spider (Crawling & Parsing)
  • Step 5: Running The Spider & Saving Data
  • Conclusion & Next Steps

Prerequisites & Setup

Before we start, you'll need Python 3.x installed. We'll also be using a virtual environment to keep our dependencies clean. You can use standard pip or a modern package manager like uv.

First, let's create a project folder and activate a virtual environment.

1# Create a new folder
2mkdir scrapy_project
3cd scrapy_project
4
5# Option 1: Using standard pip + venv
6python -m venv .venv
7source .venv/bin/activate  # On Windows, use: .venv\Scripts\activate
8
9# Option 2: Using uv (a fast, modern alternative)
10uv init
Copy

Now, let's install Scrapy.

1# Option 1: Using pip
2pip install scrapy
3
4# Option 2: Using uv
5uv add scrapy
6source .venv/bin/activate
Copy

Step 1: Initialize Your Project

With Scrapy installed, we can use its built-in command-line tools to generate our project boilerplate.

First, create the project itself.

1# The 'scrapy startproject' command creates the project structure
2# The '.' tells it to use the current folder
3scrapy startproject tutorial .
Copy

You'll see a tutorial folder and a scrapy.cfg file appear. This folder contains all your project's logic.

Next, we'll generate our first spider.

1# The 'genspider' command creates a new spider file
2# Usage: scrapy genspider <spider_name> <allowed_domain>
3scrapy genspider books toscrape.com
Copy

If you look in tutorial/spiders/, you'll now see books.py. This is where we'll write our code.

Step 2: Configure Your Settings

Before we write our spider, let's quickly adjust two settings in tutorial/settings.py.

ROBOTSTXT_OBEY

By default, Scrapy respects robots.txt files. This is a good practice, but our test site (toscrape.com) doesn't have one, which can cause a 404 error in our logs. We'll turn it off for this tutorial.

1# tutorial/settings.py
2
3# Find this line and change it to False
4ROBOTSTXT_OBEY = False
Copy

Concurrency

Scrapy is polite by default and runs slowly. Since toscrape.com is a test site built for scraping, we can speed it up.

1# tutorial/settings.py
2
3# Uncomment or add these lines
4CONCURRENT_REQUESTS = 16
5DOWNLOAD_DELAY = 0
Copy

Warning: These settings are for this test site only. When scraping in the wild, you must be mindful of your target site and use respectful DOWNLOAD_DELAY and CONCURRENT_REQUESTS values.

Step 3: Finding Our Selectors (with scrapy shell)

To scrape a site, we need to tell Scrapy what data to get. We do this with CSS selectors. The scrapy shell is the best tool for this.

Let's launch the shell on our target category page:

1scrapy shell https://books.toscrape.com/catalogue/category/books/fantasy_19/index.html
Copy

This will download the page and give you an interactive shell with a response object.

Let's find the data we need:

Find all Book Links:

By inspecting the page, we see each book is in an article.product_pod. The link is inside an h3.

1# In scrapy shell:
2>>> response.css("article.product_pod h3 a::attr(href)").getall()
3[
4  '../../../../the-host_979/index.html',
5  '../../../../the-hunted_978/index.html',
6  ...
7]
Copy

Find the "Next" Page Link:

At the bottom, we find the "Next" button in an li.next.

1# In scrapy shell:
2>>> response.css("li.next a::attr(href)").get()
3'page-2.html'
Copy

Find the Book Data (on a product page):

Finally, let's open a shell on a product page to find the selectors for our data.

1# Exit the shell and open a new one:
2scrapy shell https://books.toscrape.com/catalogue/the-host_979/index.html
3
4# In scrapy shell:
5>>> response.css("h1::text").get()
6'The Host'
7
8>>> response.css("p.price_color::text").get()
9'£25.82'
Copy

Step 4: Building the Spider (Crawling & Parsing)

Now, let's open tutorial/spiders/books.py and write our spider. We'll use the user's provided code, as it's a clean, final version.

Delete the boilerplate in books.py and replace it with this:

1# tutorial/spiders/books.py
2
3import scrapy
4
5class BooksSpider(scrapy.Spider):
6    name = "books"
7    allowed_domains = ["toscrape.com"]
8
9    # This is our starting URL (the first page of the Fantasy category)
10    url: str = "https://books.toscrape.com/catalogue/category/books/fantasy_19/index.html"
11
12    # This is the modern, async version of 'start_requests'
13    async def start(self):
14        # We yield our first request, sending the response to 'parse_listpage'
15        yield scrapy.Request(self.url, callback=self.parse_listpage)
16
17    # This function handles the *category page*
18    async def parse_listpage(self, response):
19
20        # 1. Get all product URLs using the selector we found
21        product_urls = response.css("article.product_pod h3 a::attr(href)").getall()
22
23        # 2. For each product URL, follow it and send the response to 'parse_book'
24        for url in product_urls:
25            yield response.follow(url, callback=self.parse_book)
26
27        # 3. Find the 'Next' page URL
28        next_page_url = response.css("li.next a::attr(href)").get()
29
30        # 4. If a 'Next' page exists, follow it and send the response
31        if next_page_url:
32            yield response.follow(next_page_url, callback=self.parse_listpage)
33
34    # This function handles the *product page*
35    async def parse_book(self, response):
36
37        # We yield a dictionary of the data we want
38        yield {
39            "name": response.css("h1::text").get(),
40            "price": response.css("p.price_color::text").get(),
41            "url": response.url
42        }
Copy

Step 5: Running The Spider & Saving Data

We're ready to run. Go to your terminal (at the project root) and run:

1scrapy crawl books
Copy

You'll see Scrapy start up, and in the logs, you'll see all 48 items being scraped!

But we want to save this data. Scrapy has a built-in "Feed Exporter" that makes this easy. We just use the -o (output) flag.

1scrapy crawl books -o books.json
Copy

This will run the spider again, but this time, you'll see a new books.json file in your project root, containing all 48 items, perfectly structured.

Conclusion & Next Steps

Today you built a powerful, modern, async Scrapy crawler. You learned how to set up a project, find selectors, follow links, and handle pagination.

This is just the starting block.

What's Next? Join the Community.

  • 💬 TALK: Stuck on this Scrapy code? Ask the maintainers and 5k+ devs in our Discord.
  • ▶️ WATCH: This post was based on our video! Watch the full walkthrough on our YouTube channel.
  • 📩 READ: Want more? In Part 2, we'll cover Scrapy Items and Pipelines. Get the Extract newsletter so you don't miss it.

In this article

  • The Modern Scrapy Developer's Guide (Part 1): Building Your First Spider
  • What We'll Build
  • On This Page (Table of Contents)
  • Prerequisites & Setup
  • Step 1: Initialize Your Project
  • Step 2: Configure Your Settings
  • ROBOTSTXT_OBEY
  • Concurrency
  • Step 3: Finding Our Selectors (with scrapy shell)
  • Find all Book Links:
  • Find the "Next" Page Link:
  • Find the Book Data (on a product page):
  • Step 4: Building the Spider (Crawling & Parsing)
  • Step 5: Running The Spider & Saving Data
  • Conclusion & Next Steps
  • What's Next? Join the Community.

Selected chapter & lessons

Learn Scrapy

  • Scrapy Tutorial Part 1: First Spider
  • Scrapy Tutorial Part 2: Page Objects
  • Scrapy Tutorial Part 3: Web Scraping CoPilot

Other lessons

What is web scraping?

  • What Is Web Scraping?
  • What are the elements of a web scraping project?
  • Python Web Scaping Tools & Libraries
  • How to architect a web scraping solution: The step-by-step guide
  • Web crawling vs web scraping
  • Is Web & Data Scraping Legally Allowed?
  • Compliant Web Scraping Checklist
  • Best practices for web scraping
  • A Guide to Web Scraping With Java
  • Transition from Zenrows to Zyte API
  • Guide to Web Scraping APIs
  • Screen Scraping Explained
  • Large Scale Web Scraping with Python
  • Large Scale Web Scraping with Python
  • Building a Web Crawler in Python
  • A Practical Guide to XML Parsing with Python
  • Learn How to Scrape a Website
  • Advanced Use Cases for Session Management
  • Golang Web Scraping in 2025
  • Web Scraping Dynamic Websites With Zyte API
  • What is Data Parsing in Web Scraping?
  • Scrape Web Pages and Files Using Python, wget, and Zyte

Web Scraping How-to Videos

  • Web scraping videos

SERP Data Collection at Scale

  • SERP data collection at scale and why efficiency matters
  • Why Page One SERP data is no longer enough
  • Why pagination logic becomes operational debt
  • Why SERP data costs exploded

What is web scraping used for?

  • What is web scraping used for?
  • Pricing Intelligence Web Scraping
  • Web Scraping For Market Research
  • Use web scraping to build a data-driven product
  • Use web scraping for alternative data for finance
  • Use web scraping for brand monitoring
  • Use web scraping to automate MAP compliance
  • Web Scraping For Lead Generation
  • Web Scraping For Recruitment
  • Use web scraping for business automation
  • Using Data Extraction Tools for Efficient Website Scraping
  • Why Might a Business Use Web Scraping to Collect Data?
  • How to Scrape Images from Any Website: A Complete Guide
  • How to Scrape Search Engine Results

The New Guide to Web Scraping at Scale

  • Introduction
  • 1. A plan is a pathway to success
  • 2. Get serious about legal compliance
  • 3. The quality of your web data is of utmost importance
  • 4. Scaling and maintaining crawling and extracting solutions
  • 5. Adding AI to the web scraping stack
  • 6. The In-house vs outsourced question
  • 7. Questions to ask when scaling web scraping

Essential Web Scraping Techniques

  • TLS Fingerprint and how it blocks requests
  • How to scrape with a browser effectively
  • API First data extraction

More learn articles

Keep learning

All learn articles →
What are residential proxies bannerUse case

What is a residential proxy?

Learn what residential proxies are, how they compare to datacenter proxies, and why modern web scraping needs more than IP diversity.

10 min read

Zyte Case Studies — every customer story, in one placeUse case

How much do rotating proxies cost?

Learn how much rotating proxies cost, what affects pricing, and why total web scraping costs often go beyond proxy subscriptions.

10 min read

Zyte Case Studies — every customer story, in one placeUse case

How do rotating proxies work?

Learn how rotating proxies work, when to use them for web scraping, and why IP rotation alone is not enough for reliable data access.

10 min read

Services

Zyte Data

Coding tools & hacks straight to your inbox. Bi-weekly dosage of all things code.

Explore Zyte Data

Web Scraping API

Zyte API

Coding tools & hacks straight to your inbox. Bi-weekly dosage of all things code.

Sign Up

Developers

Zyte Developers

Coding tools & hacks straight to your inbox. Bi-weekly dosage of all things code.

Join Us
    • Zyte API
    • Ban Handling
    • AI Extraction
    • SERP
    • Enterprise
    • Scrapy Cloud
    • Agentic Web Data
    • Pricing
    • Product & E-commerce
    • Data for AI
    • Job Posting
    • Real Estate
    • News & Articles
    • Search
    • Social Media
    • Blog
    • Learn
    • Case Studies
    • Webinars
    • White Papers
    • Join our community
    • Documentation
    • Meet Zyte
    • Contact us
    • Jobs
    • Support
    • Terms and Policies
    • Trust Center
    • Do not sell
    • Cookie settings
    • Web Data Compliance
    • Open Source
    • What is Web Scraping
    • Web Scraping in Python: Ultimate Guide
    • Stop getting blocked, start scraping
  • EWDCI logoMost loved workplace certificateZyte rewardISO 27001 iconG2 rewardG2 rewardG2 reward
    XFacebookInstagramYouTubeLinkedInDiscord

    © Zyte Group Limited 2026