Scrapy工作原理图

Scrapy工作流程

  1. 爬虫(Spider)生成初始请求:爬虫通过start_requests()方法生成初始的Request对象,并将其发送给引擎(Engine)。

  2. 引擎将请求发送给调度器(Scheduler):引擎接收到爬虫发送的初始请求后,将其传递给调度器进行排队。

  3. 调度器返回请求给引擎:调度器按照一定的策略(如先进先出、优先级等)对请求进行排序,并将下一个待处理的请求返回给引擎。

  4. 引擎将请求发送给下载器(Downloader):引擎通过下载器中间件(Downloader Middlewares)将请求发送给下载器。

  5. 下载器返回响应给引擎:下载器根据请求从网络上获取数据,并生成一个响应(Response)对象,然后通过下载器中间件将其发送回引擎。

  6. 引擎将响应发送给爬虫:引擎通过爬虫中间件(Spider Middleware)将响应传递给爬虫进行处理。

  7. 爬虫解析响应并返回数据或新请求:爬虫解析响应,提取所需的数据(Item)或生成新的请求,并将它们返回给引擎。

  8. 引擎将数据发送给Item Pipeline,新请求发送给调度器:引擎将爬虫返回的数据项(Item)传递给Item Pipeline进行处理,将新的请求再次发送给调度器。

  9. Item Pipeline处理数据:Item Pipeline对数据进行清洗、验证、存储等操作。

  10. 重复上述过程:引擎不断从调度器获取新的请求,重复上述步骤,直到调度器中没有更多请求

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官方文档

        Scrapy英文官方文档

        Scrapy中文官方文档
 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐