初识Scrapy框架
之前学习的requests
和selenium
,它们基本上已经可以满足绝大部分的爬虫需求了。但是,在使用这两个模块的时候,往往会出现爬取效率低的情况,处理的事物多的时候多线程写起来比较麻烦。scrapy
给我最大的感受就是可以使我们更便捷地写出高质量的爬虫程序。
1、Scrapy简介
Scrapy是一个为了爬取网站数据、提取结构性数据而编写的应用框架。它使用来Twisted
异步网络框架,提高了爬取效率。很多东西框架已经写好,我们可以不用修改或者稍做修改,就可以使用,进而提高了写爬虫程序的效率。
2、Scrapy架构
2.1 5+2结构 (5个组件+2个中间件)
-
Scrapy Enhine: 引擎负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。
-
Scheduler(调度器): 调度器从引擎接受request并将他们入队,以便之后引擎请求他们时提供给引擎。
-
Downloader(下载器) 下载器负责获取页面数据并提供给引擎,而后提供给Spiders。
-
Spiders: Spider是Scrapy用户编写用于分析response并提取item(即获取到的item)或额外跟进的URL的类。 每个spider负责处理一个特定(或一些)网站。
-
Item Pipeline: Item Pipeline负责处理被spider提取出来的item。典型的处理有清理、 验证及持久化(例如存取到数据库中)。
-
Downloader middlewares(下载器中间件): 下载器中间件是在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的response。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。
-
Spider middlewares(Spider中间件): Spider中间件是在引擎及Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出(items及requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。
2.2 数据流
- 引擎(Scrapy Engine)打开一个网站,找到处理该网站的Spider,并向该Spider请求第一个要爬取的URL
- 引擎(Scrapy Engine)从Spider中获取到第一个要爬取的URL后,通过调度器(Scheduler)以Request的形式调度
- 引擎(Scrapy Engine)向调度器(Scheduler)请求下一个要爬取的URL
- 调度器(Scheduler)返回下一个要爬取的URL给引擎(Scrapy Engine),引擎将该URL通过下载中间件(Downloader middlewares)转发给下载器(Downloader)
- 下载器(Downloader)下载页面,一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(Downloader middlewares)发送给引擎
- 引擎(Scrapy Engine)从下载中间件(Downloader middlewares)接收Response,并将其通过爬虫中间件(Spider middlewares)发送给爬虫(Spider)处理
- 爬虫(Spider)处理Response,并返回处理的Item及新的Request给引擎
- 引擎(Scrapy Engine)将爬虫(Spider)返回的Item给管道(Item Pipeline),将新的Request给调度器(Scheduler)
- 重复第2步到第8步,直到调度器(Scheduler)中没有更多的Request,引擎(Scrapy Engine)关闭该网站,爬虫结束
可见,Engine是整个程序的中枢。每一步的操作都要经过它。
3、使用Scrapy
3.1 安装Scrapy并配置环境
pip install scrapy
scrapy -h
查看是否已添加到path- 若2步骤不成功,则需要手动将scrapy添加到pyth
3.2 Scrapy使用步骤
新建项目
–>明确目标Item(要爬取的目标数据)
–>编写爬虫spider
–> 持久化存储Item pipline
- 建立一个scrapy爬虫工程
scrapy startproject Demo #创建一个名为Demo的工程
- 在工程中产生一个scrapy爬虫
此时Demo文件夹下的spiders文件夹下会多一个demo.py文件scrapy genspider demo mlp.ldeo.columbia.edu
. ├── Demo #外层目录 │ ├── __init__.py #初始化脚本 │ ├── __pycache__ #缓存目录无需修改 │ │ ├── __init__.cpython-38.pyc │ │ └── settings.cpython-38.pyc │ ├── items.py #Items代码模板(继承类) │ ├── middlewares.py #Middlewares代码模板(继承类) │ ├── pipelines.py #Pipelines代码模板(继承类) │ ├── settings.py #Scrapy爬虫的配置文件 │ └── spiders #Spiders代码模板目录(继承类) │ ├── __init__.py #初始化文件无需修改 │ ├── __pycache__ #缓存目录无需修改 │ │ └── __init__.cpython-38.pyc │ └── demo.py #用户自定义的爬虫程序 └── scrapy.cfg #部署Scrapy爬虫的配置文件
- 配置产生的spider爬虫
- 编写Spider
- start_urls
- parser
import scrapy class DemoSpider(scrapy.Spider): name = 'demo' allowed_domains = ['mlp.ldeo.columbia.edu'] start_urls = ['https://mlp.ldeo.columbia.edu/logdb/scientific_ocean_drilling/result/'] def parse(self, response): tr_list = response.xpath("//tr") for tr in tr_list[3:]: item = {} item['year']=tr.xpath('./td')[0].xpath('./text()').extract_first() item['program']=tr.xpath('./td')[1].xpath('./text()').extract_first() item['EG/EXP']=tr.xpath('./td')[2].xpath('./text()').extract_first() item['HOLE']=tr.xpath('./td')[3].xpath('./a/text()').extract_first() item['LOCATION']=tr.xpath('./td')[4].xpath('./text()').extract_first() item['OCEAN/SEA']=tr.xpath('./td')[5].xpath('./text()').extract_first() yield item
- 编写pipeline
- 在写pipeline之前需要在settings.py中将其开启
ITEM_PIPELINES = { 'Demo.pipelines.DemoPipeline': 300, }
- 同时将日志等级降,也在settings中设置
LOG_LEVEL = "WARNING"
- 写pipeline (在这里进行持久化存储)
from itemadapter import ItemAdapter class DemoPipeline: def process_item(self, item, spider): print(item) # 这里可以替换为保存到数据库、本地文件 return item
- 在写pipeline之前需要在settings.py中将其开启
- 编写Spider
- 运行爬虫工程
scrapy cral demo