Scrapy is not just an HTML parser. It is a full crawling framework for request scheduling, downloading, parsing, pipelines, and middleware.
Core Components
Scrapy Engine coordinates everything.
Scheduler receives Requests, queues them, and returns them to the engine.
Downloader sends requests and returns Responses.
Spider parses Responses, extracts Items, and yields new URLs.
Item Pipeline cleans, filters, and stores data.
Middleware intercepts requests and responses, useful for proxies, User-Agent, cookies, or browser rendering.
Runtime Flow
- Spider provides initial URLs.
- Engine sends Requests to Scheduler.
- Scheduler queues them.
- Engine asks Scheduler for a Request.
- Downloader downloads the page.
- Response goes to Spider.
- Spider extracts Items and new Requests.
- Items go to Pipeline, new Requests go to Scheduler.
- The crawler stops when the queue is empty.
Selectors
Scrapy uses Selectors to parse HTML/XML.
def parse(self, response):
title = response.xpath("//title/text()").get()Common XPath:
//tag
//div[@class="content"]
//a/@href
//h1/text()
//ul/li[position()=1]CSS selectors:
title = response.css("title::text").get()
links = response.css("a::attr(href)").getall()get and getall
.get() returns the first match.
title = response.xpath("//title/text()").get().getall() returns all matches.
tags = response.css("a.tag::text").getall()Pagination
def parse(self, response):
for quote in response.css("div.quote"):
yield {
"text": quote.css("span.text::text").get(),
"author": quote.css("small.author::text").get(),
}
next_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, self.parse)Tool Selection
Typical priority:
- Static HTML: Scrapy XPath/CSS
- Embedded JSON: parse JSON directly
- Light JavaScript: scrapy-playwright
- Heavy interactions: Selenium
- Messy HTML: BeautifulSoup for cleanup
Scrapy's value is framework structure, scalability, and extensibility.
Deeper Notes
When reviewing this topic, do not memorize names only. Focus on Scrapy engine, scheduler, downloader, spider, item pipeline, selectors, and pagination. If this stays at the definition level, it becomes hard to explain in interviews or apply in projects. A stronger way to study it is to place it in a concrete scenario: who calls it, where the input comes from, what happens on failure, and whether data or state can be processed twice.
- Scraping is difficult because of page changes, wait strategy, deduplication, rate limiting, recovery, and data quality.
- Choose BeautifulSoup, Selenium, or Scrapy based on dynamic behavior, data volume, and downstream cleaning needs.
- Reliable crawlers need logs, resumability, retries, and field-level validation, not just one successful run.
In a real project, use it as a decision framework: identify inputs, constraints, failure modes, and observability before choosing a specific tool or pattern. If a solution looks simple, keep asking whether it still works when scale grows, permissions change, recovery matters, and more people collaborate on it.
Practical Checklist
- Identify where this concept sits in the system: development-time constraint, runtime behavior, infrastructure capability, or collaboration workflow.
- Write one minimal working example and one failure example; only knowing the happy path is usually not enough.
- Record common misuses: edge cases, permission assumptions, performance assumptions, sync/async differences, or environment differences.
- Connect the concept to a project experience so that an interview answer can be grounded in real tradeoffs.
- End with one sentence about tradeoff: what it gives up and what it buys.
Self-Check Questions
- What core problem does this topic solve?
- What alternatives exist, and what are their costs?
- Where are the most likely edge cases?
- How would code, tests, or monitoring prove that it is reliable?
Applied Scenario
A job or product crawler is a useful scenario. First decide whether the page is static HTML or dynamically rendered, then choose BeautifulSoup, Selenium, or Scrapy. After extraction, the system still needs cleaning, deduplication, retries, and persistence. A robust crawler is not one that succeeds once; it is one that can recover when page structure changes, the network times out, anti-bot rules appear, or some fields are missing.
Common Pitfalls:
- Hard-coding fragile selectors without fallback.
- Missing rate limits and retries, causing blocks or data loss.
- Saving raw data without field-level quality checks.