likes
comments
collection
share

嗨,Scrapy 捋一遍

作者站长头像
站长
· 阅读数 5

很久没有使用scrapy做爬虫了,突然写有点手生,所以捋一捋知识点,做一个博客,记录一下。

Scrapy 框架介绍

Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架。

相较于其他框架,scrapy的优势在于:

1、Scrapy 使用异步处理方式,能够同时处理多个请求,从而提高程序执行效率。

2、Scrapy 支持多种数据格式的解析和处理,包括HTML、XML、JSON等。

3、Scrapy 提供了一系列插件和组件,允许用户根据需要进行定制和扩展。

4、由于其异步处理和多线程的特性,Scrapy 特别适合于大规模网页抓取项目。

框架结构

嗨,Scrapy 捋一遍 Scrapy Engine:用来处理整个系统的数据流处理、触发事务,是整个框架的核心。 调度器Scheduler:用来接受引擎发过来的请求并加入队列中,并在引擎再次请求的时候提供给引擎。 管道item pipeline:负责处理由蜘蛛从网页中抽取的项目,它的主要任务是清洗、验证和存储数据。 爬虫器(爬虫组件) Spiders:其内定义了爬取的逻辑和网页的解析规则,它主要负责解析响应并生成提取结果和新的请求。 下载器 Downloader:用于下载网页内容,并将网页内容返回给Spiders爬虫器。 Downloader Middlewares(下载器中间件):位于引擎和下载器之间的钩子框架,主要是处理引擎与下载器之间的请求及响应。

请求流程

  1. 发起请求:首先,Spiders(爬虫)会提供需要抓取的网页的初始URL,然后将这些URL发送给Scrapy Engine(引擎)。
  2. 调度请求:Scrapy Engine将请求发送给Scheduler(调度器),Scheduler会对这些请求进行排序并放入队列中等待执行。
  3. 下载网页:当Scheduler调度好执行顺序后,Scrapy Engine会将请求发送给Downloader(下载器),Downloader会向互联网发送请求并接收下载的响应(response)。
  4. 处理响应:Downloader将接收到的响应返回给Scrapy Engine,Scrapy Engine再将响应发送给Spiders。Spiders会对响应进行解析,提取出需要的数据,并生成新的请求(如链接等)。
  5. 处理数据:提取到的数据会经过Scrapy Engine,然后交给Item Pipelines进行处理。Item Pipelines可以对数据进行清洗、过滤、存储等操作。
  6. 循环执行:如果在解析响应的过程中生成了新的请求,那么这些请求会重新经过Scrapy Engine发送给Scheduler进行调度,如此循环执行,直到没有更多的请求需要处理,程序才会停止。

Scrapy 初始

框架安装

创建沙箱
# 切入沙箱目录
cd F:\2024\Project\SpiderProject
# 创建沙箱
D:\Python37\python.exe -m venv venv
# 激活沙箱
.\venv\Scripts\activate.bat
安装框架
pip install scrapy

Installing collected packages: twisted-iocpsupport, PyDispatcher, incremental, constantly, zope.interface, zipp, w3lib, urllib3, typing-extensions, six, queuelib, pycparser, pyasn1, protego, packaging, lxml, jmespath, itemadapter, idna, filelock, cssselect, charset-normalizer, certifi, requests, pyasn1-modules, parsel, importlib-metadata, hyperlink, cffi, requests-file, itemloaders, cryptography, attrs, tldextract, service-identity, pyOpenSSL, automat, Twisted, scrapy
Successfully installed PyDispatcher-2.0.7 Twisted-23.8.0 attrs-23.2.0 automat-22.10.0 certifi-2024.2.2 cffi-1.15.1 charset-normalizer-3.3.2 constantly-15.1.0 cryptography-42.0.2 cssselect-1.2.0 filelock-3.12.2 hyperlink-21.0.0 idna-3.6 importlib-metadata-6.7.0 incremental-22.10.0 itemadapter-0.8.0 itemloaders-1.1.0 jmespath-1.0.1 lxml-5.1.0 packaging-23.2 parsel-1.8.1 protego-0.3.0 pyOpenSSL-24.0.0 pyasn1-0.5.1 pyasn1-modules-0.3.0 pycparser-2.21 queuelib-1.6.2 requests-2.31.0 requests-file-2.0.0 scrapy-2.9.0 service-identity-21.1.0 six-1.16.0 tldextract-4.0.0 twisted-iocpsupport-1.0.4 typing-extensions-4.7.1 urllib3-2.0.7 w3lib-2.1.2 zipp-3.15.0 zope.interface-6.1

嗨,Scrapy 捋一遍

Scrapy 命令行

嗨,Scrapy 捋一遍

命令描述
bench运行快速基准测试
fetch使用Scrapy下载器获取URL
genspider使用预定义模板生成新的spider
runspider运行独立的spider(不创建项目)
settings获取Scrapy设置值
shell交互式抓取控制台(调试,测试使用)
startproject创建新项目
version返回爬虫的版本
view下载连接文件,并在浏览器打开这个文件

创建项目

.\venv\Scripts\scrapy.exe startproject baiduSpider

嗨,Scrapy 捋一遍

命令描述
check检测爬虫
crawl启动爬虫
edit编辑爬虫
list列出可以使用的爬虫
parse解析URL(使用其spider)并打印结果
创建独立爬虫应用
cd F:\2024\Project\SpiderProject\baiduSpider
..\venv\Scripts\scrapy.exe genspider tieba tiebaSpider
项目结构

嗨,Scrapy 捋一遍

baiduSpider # 项目外壳目录

baiduSpider # 项目目录

spiders # 具体爬虫目录

__init__.py # 包初始化文件

tieba.py # 爬虫具体文件

__init__.py # 包初始化文件

item.py # 爬取数据的结构

middlewares.py # 爬虫中间件文件

pipelines.py # 爬虫数据传输文件

settings.py # 爬虫配置文件

scrapy.cfg # scrapy框架配置文件

一次基本的爬取

import scrapy
from baiduSpider.items import TiebaspiderItem

class TiebaSpider(scrapy.Spider):
    name = "tieba"
    allowed_domains = ["tiebaSpider"]
    start_urls = ["https://tieba.baidu.com/index.html"]

    def parse(self, response):
        for iter in response.xpath("//div[@class='title-tag-wraper']/a"):
            ba_name = iter.attrib.get("title")
            print(ba_name)

Scrapy MiddleWare

在Scrapy中,Middleware(中间件)是一个处理请求和响应的组件,它在Scrapy引擎和下载器之间提供了一个钩子(hook),允许你对请求和响应进行预处理和后处理。Middleware可以用于执行各种任务,如设置请求头、重试失败的请求、记录日志、跟踪请求和响应等。要创建一个Middleware,你需要定义一个类并实现Scrapy提供的特定方法。这些方法会在请求和响应流经Scrapy时触发。以下是一个简单的Scrapy Middleware示例,它会在每个请求发出之前添加一个自定义的请求头:

class CustomMiddleware:

    def process_request(self, request, spider):
        *# 添加一个自定义的请求头*
        request.headers.setdefault('X-Custom-Header', 'CustomValue')

    def process_response(self, request, response, spider):
        *# 你可以在这里对响应进行处理,比如检查状态码、修改内容等*
        return response

    def process_exception(self, request, exception, spider):
        *# 当请求抛出异常时,这个方法会被调用*
        *# 你可以在这里记录日志、重试请求等*
        pass

要使用这个Middleware,你需要在你的settings.py文件中添加或修改DOWNLOADER_MIDDLEWARES设置:

pythonDOWNLOADER_MIDDLEWARES = {    'myproject.middlewares.CustomMiddleware': 543,    # 其他中间件...}

确保将'myproject.middlewares.CustomMiddleware'替换为你Middleware的正确路径。数字543表示Middleware的优先级,数字越小优先级越高。

Scrapy内置了许多有用的Middleware,例如重试失败的请求、重定向、cookies和代理等。你可以通过修改settings.py文件中的DOWNLOADER_MIDDLEWARES和SPIDER_MIDDLEWARES来启用或禁用这些Middleware,或者添加你自己的Middleware。

Middleware在处理请求和响应时,可以返回None、Request对象或Response对象。返回None意味着请求被忽略,不会进一步处理。返回Request对象意味着使用新的请求替换原来的请求。返回Response对象意味着使用新的响应替换原来的响应。

Scrapy Pipline

在Scrapy中,Pipeline是负责处理由Spider爬取并返回的item的组件。Pipeline组件接收item,并对其进行一些后续处理,比如清理、验证和持久化数据。你可以编写自己的Pipeline来执行任何你需要的处理逻辑。

下面是一个简单的Scrapy Pipeline示例,它展示了如何将爬取的数据保存到CSV文件中:

import csv

class CsvWriterPipeline:
    def open_spider(self, spider):
        self.file = open('items.csv', 'w', newline='', encoding='utf-8')
        self.writer = csv.writer(self.file)
        self.writer.writerow(['Field1', 'Field2', 'Field3'])  # 写入CSV的表头

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        self.writer.writerow([item['field1'], item['field2'], item['field3']])  # 写入item的数据
        return item

要使用这个Pipeline,你需要在你的settings.py文件中启用它:

ITEM_PIPELINES = {
    'myproject.pipelines.CsvWriterPipeline': 300,
}

这里的数字300表示Pipeline的优先级。数字越小,优先级越高。如果有多个Pipeline,Scrapy会按照优先级从高到低的顺序执行它们。

process_item方法是Pipeline中最关键的方法。每个item都会通过这个方法进行处理。在这个方法中,你可以对item进行任何你需要的处理,比如数据清洗、验证、转换格式等。处理完成后,你可以选择返回这个item(继续传递给下一个Pipeline组件)或者抛出一个DropItem异常(停止后续的处理并丢弃这个item)。

open_spider和close_spider方法分别在爬虫开始时和结束时调用,你可以在这些方法中执行一些初始化和清理工作,比如打开和关闭文件。

请注意,在process_item方法中,你需要确保写入的CSV文件是线程安全的,因为Scrapy默认使用多线程来处理item。你可以使用csv.writer的线程安全版本,或者使用文件锁等机制来确保并发写入时的数据一致性。

最后,确保将'myproject.pipelines.CsvWriterPipeline'替换为你自己的Pipeline类的正确路径。

Scrapy 完整流程

spider.py

import scrapy
from baiduSpider.items import TiebaspiderItem

class TiebaSpider(scrapy.Spider):
    name = "tieba"
    allowed_domains = ["tiebaSpider"]
    start_urls = ["https://tieba.baidu.com/index.html"]

    def parse(self, response):
        for iter in response.xpath("//div[@class='title-tag-wraper']/a"):
            ba_name = iter.attrib.get("title")
            tb_item = TiebaspiderItem()
            tb_item["ba_name"] = ba_name
            yield tb_item

item.py

import scrapy


class BaiduspiderItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass

class TiebaspiderItem(scrapy.Item):
    ba_name = scrapy.Field()

pipline.py

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
import csv

class BaiduspiderPipeline:
    def process_item(self, item, spider):
        return item

class TiebaSpiderCSVPipeline:
    def __init__(self):
        self.file = "open.csv"

    def open_spider(self, spider):
        self.file = open('items.csv', 'w', newline='', encoding='utf-8')
        self.writer = csv.writer(self.file)
        self.writer.writerow(['论坛标题'])  # 根据需要定义列名

    def process_item(self, item, spider):
        title = item["ba_name"]
        self.writer.writerow([title])
        return item

    def close_spider(self, spider):
        self.file.close()

案例很简单,后续还想基于scarpy+redis进行分布式数据采集,还请给各位大佬多多指点。