很久没有使用scrapy做爬虫了,突然写有点手生,所以捋一捋知识点,做一个博客,记录一下。
Scrapy 框架介绍
Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架。
相较于其他框架,scrapy的优势在于:
1、Scrapy 使用异步处理方式,能够同时处理多个请求,从而提高程序执行效率。
2、Scrapy 支持多种数据格式的解析和处理,包括HTML、XML、JSON等。
3、Scrapy 提供了一系列插件和组件,允许用户根据需要进行定制和扩展。
4、由于其异步处理和多线程的特性,Scrapy 特别适合于大规模网页抓取项目。
框架结构
Scrapy Engine:用来处理整个系统的数据流处理、触发事务,是整个框架的核心。 调度器Scheduler:用来接受引擎发过来的请求并加入队列中,并在引擎再次请求的时候提供给引擎。 管道item pipeline:负责处理由蜘蛛从网页中抽取的项目,它的主要任务是清洗、验证和存储数据。 爬虫器(爬虫组件) Spiders:其内定义了爬取的逻辑和网页的解析规则,它主要负责解析响应并生成提取结果和新的请求。 下载器 Downloader:用于下载网页内容,并将网页内容返回给Spiders爬虫器。 Downloader Middlewares(下载器中间件):位于引擎和下载器之间的钩子框架,主要是处理引擎与下载器之间的请求及响应。
请求流程
- 发起请求:首先,Spiders(爬虫)会提供需要抓取的网页的初始URL,然后将这些URL发送给Scrapy Engine(引擎)。
- 调度请求:Scrapy Engine将请求发送给Scheduler(调度器),Scheduler会对这些请求进行排序并放入队列中等待执行。
- 下载网页:当Scheduler调度好执行顺序后,Scrapy Engine会将请求发送给Downloader(下载器),Downloader会向互联网发送请求并接收下载的响应(response)。
- 处理响应:Downloader将接收到的响应返回给Scrapy Engine,Scrapy Engine再将响应发送给Spiders。Spiders会对响应进行解析,提取出需要的数据,并生成新的请求(如链接等)。
- 处理数据:提取到的数据会经过Scrapy Engine,然后交给Item Pipelines进行处理。Item Pipelines可以对数据进行清洗、过滤、存储等操作。
- 循环执行:如果在解析响应的过程中生成了新的请求,那么这些请求会重新经过Scrapy Engine发送给Scheduler进行调度,如此循环执行,直到没有更多的请求需要处理,程序才会停止。
Scrapy 初始
框架安装
创建沙箱
bash
# 切入沙箱目录
cd F:\2024\Project\SpiderProject
# 创建沙箱
D:\Python37\python.exe -m venv venv
# 激活沙箱
.\venv\Scripts\activate.bat
安装框架
csharp
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 命令行

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

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

baiduSpider # 项目外壳目录
baiduSpider # 项目目录
spiders # 具体爬虫目录
init.py # 包初始化文件
tieba.py # 爬虫具体文件
init.py # 包初始化文件
item.py # 爬取数据的结构
middlewares.py # 爬虫中间件文件
pipelines.py # 爬虫数据传输文件
settings.py # 爬虫配置文件
scrapy.cfg # scrapy框架配置文件
一次基本的爬取
python
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示例,它会在每个请求发出之前添加一个自定义的请求头:
ruby
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设置:
ini
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文件中:
python
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文件中启用它:
ini
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 完整流程
ini
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
python
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()
python
# 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进行分布式数据采集,还请给各位大佬多多指点。