基于Scrapy框架的爬虫项目实践
下载器根据请求从网络上获取数据,并生成一个响应(Response)对象,然后通过下载器中间件将其发送回引擎。:引擎将爬虫返回的数据项(Item)传递给Item Pipeline进行处理,将新的请求再次发送给调度器。:调度器按照一定的策略(如先进先出、优先级等)对请求进行排序,并将下一个待处理的请求返回给引擎。:爬虫解析响应,提取所需的数据(Item)或生成新的请求,并将它们返回给引擎。:引擎接收到
Scrapy工作原理图

Scrapy工作流程
-
爬虫(Spider)生成初始请求:爬虫通过
start_requests()方法生成初始的Request对象,并将其发送给引擎(Engine)。 -
引擎将请求发送给调度器(Scheduler):引擎接收到爬虫发送的初始请求后,将其传递给调度器进行排队。
-
调度器返回请求给引擎:调度器按照一定的策略(如先进先出、优先级等)对请求进行排序,并将下一个待处理的请求返回给引擎。
-
引擎将请求发送给下载器(Downloader):引擎通过下载器中间件(Downloader Middlewares)将请求发送给下载器。
-
下载器返回响应给引擎:下载器根据请求从网络上获取数据,并生成一个响应(Response)对象,然后通过下载器中间件将其发送回引擎。
-
引擎将响应发送给爬虫:引擎通过爬虫中间件(Spider Middleware)将响应传递给爬虫进行处理。
-
爬虫解析响应并返回数据或新请求:爬虫解析响应,提取所需的数据(Item)或生成新的请求,并将它们返回给引擎。
-
引擎将数据发送给Item Pipeline,新请求发送给调度器:引擎将爬虫返回的数据项(Item)传递给Item Pipeline进行处理,将新的请求再次发送给调度器。
-
Item Pipeline处理数据:Item Pipeline对数据进行清洗、验证、存储等操作。
-
重复上述过程:引擎不断从调度器获取新的请求,重复上述步骤,直到调度器中没有更多请求
Scrapy组件说明
-
Scrapy引擎(Engine):核心组件,负责控制数据流在各个组件之间的流动。
-
爬虫(Spider):用户编写的类,负责解析响应并提取数据或生成新的请求。
-
调度器(Scheduler):负责管理请求队列,按照一定策略对请求进行排序。
-
下载器(Downloader):负责发送HTTP请求并接收响应。
-
Item Pipeline:负责处理爬虫提取的数据,如清洗、验证、存储。
-
下载器中间件(Downloader Middlewares):在请求和响应的生命周期中插入自定义逻辑。
-
爬虫中间件(Spider Middleware):在爬虫输入和输出的生命周期中插入自定义逻辑。
Scrapy项目创建
采集目标网站:All products | Books to Scrape - Sandbox
1. 创建虚拟环境:
python -m venv .venv
2. 进入虚拟环境
.\.venv\Scripts\activate
(不使用虚拟环境可省略前两步)
3. 更新pip
python.exe -m pip install --upgrade pip
4. 安装scrapy
pip install scrapy
5. 创建名为books_toscrape的scrapy项目
scrapy startproject books_toscrape
6. 进入books_toscrape项目
cd .\books_toscrape\
7. 创建个名为books_spider的爬虫,并且限制抓取域名的范围
scrapy genspider books_spider books.toscrape.com
得到如下结构:
books_toscrape/
│
├── books_toscrape/
│ ├── __init__.py # 将当前目录标识为Python包
│ ├── items.py # 定义爬虫抽取的数据结构
│ ├── middlewares.py # 定义请求和响应的中间件
│ ├── pipelines.py # 定义数据管道,处理和存储爬取的数据
│ ├── settings.py # Scrapy项目配置文件,包括并发、延迟等设置
│ └── spiders/ # 存放爬虫文件的目录
│ ├── __init__.py # 将spiders目录标识为Python包
│ └── books_spider.py # 实现爬虫逻辑,包括起始URL、解析规则等
Scrapy项目运行
-
items.py:配置需要采集的字段。
import scrapy class BooksToscrapeItem(scrapy.Item): title = scrapy.Field() price = scrapy.Field() rating = scrapy.Field() availability = scrapy.Field() url = scrapy.Field() -
pipelines.py:将采集结果保存为csv。
import csv import os from scrapy.utils.project import get_project_settings class BooksToscrapePipeline: def __init__(self): self.file = None self.writer = None self.settings = get_project_settings() def open_spider(self, spider): data_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), self.settings.get('CSV_OUTPUT_DIR')) os.makedirs(data_dir, exist_ok=True) csv_path = os.path.join(data_dir, self.settings.get('CSV_FILENAME')) self.file = open(csv_path, 'w', newline='', encoding='utf-8') self.writer = csv.DictWriter(self.file, fieldnames=[ 'title', 'price', 'rating', 'availability', 'url' ]) self.writer.writeheader() def process_item(self, item, spider): self.writer.writerow(dict(item)) return item def close_spider(self, spider): if self.file: self.file.close() ''' open_spider(self, spider):当爬虫启动时自动调用。 process_item(self, item, spider):当爬虫采集到一个 item 时自动调用。 close_spider(self, spider):当爬虫关闭时自动调用。 ''' -
settings.py:添加CSV文件保存路径配置并启用管道。
BOT_NAME = "books_toscrape" SPIDER_MODULES = ["books_toscrape.spiders"] NEWSPIDER_MODULE = "books_toscrape.spiders" ADDONS = {} ROBOTSTXT_OBEY = True FEED_EXPORT_ENCODING = "utf-8" CSV_OUTPUT_DIR = 'data' CSV_FILENAME = 'books.csv' ITEM_PIPELINES = { "books_toscrape.pipelines.BooksToscrapePipeline": 300, } ''' robots.txt也就是robots协议,这个文件会告诉爬虫,哪些能爬,哪些不能爬,爬虫要遵守这个规则。 ROBOTSTXT_OBEY = True 表示遵守 robots.txt 协议。 大多网站在遵守robots协议的情况是采集不到数据的,所以多数情况设置为False才能采集到数据。 ''' -
books_spider.py:定义目标位置对应的爬虫逻辑和解析语法。
import scrapy class BooksSpiderSpider(scrapy.Spider): name = "books_spider" allowed_domains = ["books.toscrape.com"] start_urls = ["https://books.toscrape.com"] def parse(self, response): books = response.css('article.product_pod') for book in books: title = book.css('h3 a::attr(title)').get() price = book.css('p.price_color::text').get() rating = book.css('p.star-rating::attr(class)').get().split()[-1] availability = book.css('p.availability::text').getall() availability = ''.join(availability).strip() book_url = book.css('h3 a::attr(href)').get() if book_url: book_url = response.urljoin(book_url) yield { 'title': title, 'price': price, 'rating': rating, 'availability': availability, 'url': book_url } # 获取下一页链接 next_page = response.css('li.next a::attr(href)').get() if next_page: next_page_url = response.urljoin(next_page) yield scrapy.Request(next_page_url, callback=self.parse) ''' allowed_domains:限制爬虫只爬取指定域名下的网页。 start_urls:爬虫启动时访问的第一个网页。 parse:解析网页的回调函数, 解析语法支持css选择器、xpath、re。 ''' -
run.py:在spiders文件夹的同级目录下创建run文件用于项目的运行和调试。
from scrapy.crawler import CrawlerProcess from scrapy.utils.project import get_project_settings import os, sys sys.path.append(os.path.dirname((os.path.dirname(__file__)))) from spiders.books_spider import BooksSpiderSpider runner = CrawlerProcess(get_project_settings()) runner.crawl(BooksSpiderSpider) runner.start() ''' CrawlerProcess 是 Scrapy 提供的一个用于运行爬虫的类。 它负责管理爬虫的启动、停止、配置和执行。 get_project_settings() 是 Scrapy 提供的一个函数,用于获取项目配置。 它会从 settings.py 文件中读取配置,并返回一个 Settings 对象。 '''-
可以不使用run.py运行项目,直接通过终端输入指令运行项目。
scrapy crawl books_spider
-
遇到的问题
在pycharm中使用run运行项目时正常,但是使用debug调试会出现报错:TypeError: 'Task' object is not callable。
解决方法:帮助---查找操作---搜索registry---找到python.debug.asyncio.repl---取消勾选
Scrapy官方文档
更多推荐




所有评论(0)