scrapy框架
scrapy框架简介
Scrapy是一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试,也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等。
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。
**Engine(引擎)**:负责Spider、Item Pipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。
**Scheduler(调度器)**:它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。可以想象成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址。
Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理。
Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)。
**Item Pipeline(项目管道)**:它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。主要包括清理、验证、持久化(比如存到数据库)等操作。
Spider Middlewares(爬虫中间件):一个可以自定扩展和操作引擎和Spider中间通信的功能组件
- 安装
1 | pip3 install scrapy |
命令行工具
1 | # 1 查看帮助 |
目录结构
1 | project_name/ |
文件说明
- scrapy.cfg 项目的主配置信息,用来部署scrapy时使用,爬虫相关的配置信息在settings.py文件中。
- items.py 设置数据存储模板,用于结构化数据,如:Django的Model
- pipelines 数据处理行为,如:一般结构化的数据持久化
- settings.py 配置文件,如:递归的层数、并发数,延迟下载等。强调:配置文件的选项必须大写否则视为无效,正确写法USER_AGENT=’xxxx’
- spiders 爬虫目录,如:创建文件,编写爬虫规则
注意:
- 一般创建爬虫文件时,以网站域名命名
- 默认只能在终端执行命令,为了更便捷操作
在根目录下新建
.py
文件名无规定在项目根目录下新建:bin.py, 这就相当于帮助我们在终端执行了
scrapy crawl doutu
1 | from scrapy.cmdline import execute |
spider
- spiders是网站爬取,解析页面,定义自定义行为的地方。
1、 定义在start_requests()方法内的URL,默认从start_urls列表中获得url地址来生成Request请求。用生成的Requests来爬取第一个URL,并且标识一个回调函数(默认的回调函数是parse方法)
回调函数在下载完成返回response时自动触发。2、 在回调函数中,解析response并且返回值,返回值有四种
解析数据的字典
Item对象
新的Request对象(新的Requests也需要指定一个回调函数)
可迭代对象(包含Items或Request)3、在回调函数中解析页面内容,通常使用Scrapy自带的Selectors,也可以使用Beutifulsoup,lxml等。
4、最后,针对返回的Items对象将会被持久化到数据库
通过Item Pipeline组件存到数据库:https://docs.scrapy.org/en/latest/topics/item-pipeline.html)
或者导出到不同的文件(通过Feed exports:https://docs.scrapy.org/en/latest/topics/feed-exports.html)
Item
抓取的主要目标是从非结构化源(通常是网页)中提取结构化数据。Scrapy爬虫可以像Python一样返回提取的数据。但很容易在字段名称中输入拼写错误或返回不一致的数据,尤其是在具有许多爬虫的较大项目中。
为了定义通用输出数据格式,Scrapy提供了Item类。 Item对象是用于收集抓取数据的简单容器。它们提供类似字典的 API,并具有用于声明其可用字段的方便语法。
1 | import scrapy |
Scrapy Items类似于Django Models,而Scrapy Items更简单,因为没有不同字段类型的概念
Field对象用于指定每个字段的元数据。例如,last_updated上面示例中说明的字段的序列化函数。可以为每个字段指定任何类型的元数据。Field对象接受的值没有限制。出于同样的原因,没有所有可用元数据键的参考列表。
Field对象中定义的每个键可以由不同的组件使用,只有那些组件知道它。您也可以根据Field自己的需要定义和使用项目中的任何其他键。
Field对象的主要目标是提供一种在一个地方定义所有字段元数据的方法。通常,行为取决于每个字段的那些组件使用某些字段键来配置该行为。
Item PipeLine
- 在一个项目被蜘蛛抓取之后,它被发送到项目管道,该项目管道通过顺序执行的几个组件处理它。每个项目管道组件(有时简称为“项目管道”)是一个实现简单方法的Python类。他们收到一个项目并对其执行操作,同时决定该项目是否应该继续通过管道或被丢弃并且不再处理。
项目管道的典型用途是:
- 清洗数据
- 验证数据(检查Item某些字段是否为空)
- 数据查重
- 写入数据库
Item PipeLine的方法
- process_item
1 | process_item(self,项目,蜘蛛) |
- open_spider
1 | open_spider(self,蜘蛛) |
- close_spider
1 | close_spider(self,蜘蛛) |
- from_crawler
1 | from_crawler(cls,crawler ) |
当使用
settings
对象获取全局变量时,可以在 Scrapy 配置文件中设置该变量的值,然后通过settings.get('MY_SETTING')
方法来访问它。这样做很方便,但也有一些限制:
- 无法根据特定的 Crawler 实例动态地调整全局变量的值。例如,当您在多个爬虫之间共享同一个 Scrapy 项目时,某些设置可能需要在每个爬虫之间进行微调。
- 无法轻松地将其他参数传递给中间件。如果您想基于环境变量、命令行参数或其他外部因素配置中间件,那么使用
settings
对象可能很麻烦。为了解决这些问题,Scrapy 引入了
from_crawler
方法。这个方法可以让您根据具体的 Crawler 实例创建中间件实例,并动态地向中间件传递其他参数。具体来说,
from_crawler
方法接收一个crawler
参数,这是当前 Crawler 实例的引用。可以使用crawler.settings
访问 Scrapy 的全局配置变量,还可以使用crawler.signals
注册信号处理程序,以及使用crawler.engine
和crawler.spider
访问其他 Scrapy 子系统和资源。因此,在from_crawler
中,您可以使用更多的 Scrapy 资源,并根据需要动态地配置中间件。这使得中间件更加灵活和可扩展,可以适应多种场景和需求。
start_rquests重写
- scrapy中start_url是通过spider下的start_requests()来进行处理
1 | def start_requests(self): |
- 有时候,需要重写starte_rquests方法发起首次请求
1 | import scrapy |
全站爬虫(CrawlSpider)
- Scrapy 的基本使用当中,spider 如果要重新发送请求的话,就需要自己解析页面,然后发送请求。而 CrawlSpider 则可以通过设置 url 条件自动发送请求。
LinkExtractors
CrawlSpider 是 Spider 的一个派生类。CrawlSpider 与 spider 不同的是就在于下一次请求的 url 不需要自己手动解析,而这一点则是通过 LinkExtractors 实现的。
- LinkExtractor类的构造方法
1 | class scrapy.linkextractors.LinkExtractor( |
参数说明
allow:允许的 url。所有满足这个正则表达式的 url 都会被提取
deny:禁止的 url。所有满足这个正则表达式的 url 都不会被提取
allow_domains:允许的域名。只有在这个里面指定的域名的 url 才会被提取
deny_domains:禁止的域名。所有在这个里面指定的域名的 url 都不会被提取
restrict_xpaths:严格的 xpath。和 allow 共同过滤链接tags:接收一个标签或标签列表,提取标签内的列表,默认为[‘a’, ‘area’]
attrs:接收一个属性或属性列表,提取指定属性内的链接,默认为[‘href’]
Rule
- LinkExtractors 需要传递到 Rule 类对象中才能发挥作用
link_extractors:是一个LinkExtractor对象,用于定义需要提取的链接
callback:从link_extractor中没获取链接时,参数所制定的值作为回调函数,该回调函数接受一个response作为起第一个参数
注意:当编写爬虫规则是,避免使用parse作为回调函数。由于CrawlSpider使用parse方法来实现其逻辑,如果覆盖了parse方法,CrawlSpider将会运行失败follow:是一个布尔值(boolean),制定了根据该规则从response提取的链接是需要跟进。如果callback为None,follow默认设置为True,否则默认为Flase
process_links:指定该Spider中那个的函数将会被调用,从link_extractor中获取到链接列表是将会调用该函数。该方法主要用来过滤。
process_request:指定该Spider中哪个的函数将会被调用,该规则提取到每个request是都会调用该函数。(用来过滤request)
CrawlSpider工作流程
首先由start_requests
对start_urls
中的每一个url发起请求(make_requests_from_url
),这个请求会被parse接收。在Spider里面的parse需要我们定义,但CrawlSpider定义parse
去解析响应(self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)
)
_parse_response根据有无callback
,follow
和self.follow_links
执行不同的操作
1 | def _parse_response(self, response, callback, cb_kwargs, follow=True): |
其中_requests_to_follow
又会获取link_extractor
(这个是我们传入的LinkExtractor)解析页面得到的linklink_extractor.extract_links(response)
,对url进行加工(process_links
,需要自定义),对符合的link发起Request。使用.process_request
(需要自定义)处理响应。