Scrapy是用纯Python实现的一个开源爬虫框架,是为了高效地爬取网站数据,提取结构性数据而编写的应用框架,用途非常广泛,可用于爬虫开发,数据挖掘,数据监测,自动化测试等领域。
Scrapy框架包含以下组件
1.Scrapy Engine(引擎):负责Spider,Item Pipeline,DownLoader,Scheduler之间的通信,包括信号和数据的传递
2.Scheduler(调取器):负责接收引擎发送过来的Requests请求,并按照一定的方式进行整理排列和入队,当引擎需要时,交还给引擎
3.Downloader(下载器):负责下载Scrapy Engine发送过来的Requests请求;并将其获取到的Response(响应)交还给引擎,由引擎交给Spider处理
4.Spider(爬虫):负责处理所有的Response,从中提取分析数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler调取器
5.Item Pipeline(管道):负责处理Spider中获取的Item数据,并进行后期处理(详细分析,过滤,存储等)
6.Downloader Middlewares(下载中间件):是一个可以自定义扩展下载功能的组件
7.Spider Middlewares(Spider中间件):是一个自定义扩展的Scrapy Engine和Spiders中间通信的功能组件 (例如:进入Spider的Response和从Spider出去的Requests)
小结:Spider的这些组件通力合作,共同完成整个爬取任务。首先从URL开始,Scheduler调度器会将其交给Downloader进行下载,下载之后会交给Spiders进行分析。Spider分析出来的结果有两种:一种是需要进一步爬取的链接,例如之前分析“下一页”链接,这些URL会被传回Scheduler;另一种是需要保存的数据,它们被送到Item Pipeline,这是对数据进行后期处理(详细分析,过滤,存储等)。另外,在数据流动通道里还可以安装各种中间件,进行必要的处理。
pip install scrapy
1.创建Scrapy项目
scrapy startproject 项目名称
2.在项目中创建爬虫
需要先进入scrapy项目中
scrapy genspider 爬虫名称 "爬取的域名"
3.Scrapy项目目录结构
1.Items.py 用于存放爬取下来的数据模型
2.middlewares.py 用于存放各种中间件文件
3.pipelines.py 用于将items模型存放到本地磁盘
4.setting.py 本爬虫的一些配置信息(比如请求头,多久发一次请求,ip代理池等)
5.scrapy.cfg 项目配置文件
6.spiders包 以后的爬虫都是存放在这个文件里面
1.案例简介
爬取糗事百科段子中的标题的内容
2.代码演示
qsbk_spider.py (爬虫)
# -*- coding: utf-8 -*-
import scrapy
# 将QsbkItem导入过来,用于封装项目字段
from qsbk.items import QsbkItem
from scrapy.http.response.html import HtmlResponse
from scrapy.selector.unified import SelectorList
class QsbkSpiderSpider(scrapy.Spider):
name = 'qsbk_spider'
# allowed_domains = ['aa.com']
start_urls = ['https://www.qiushibaike.com/text/']
def parse(self, response):
# contents 的数据类型是SelectorList
contents = response.xpath('//div[@class="col1 old-style-col1"]/div')
for content in contents:
# content 类型:Selector
# get方法 序列化并返回单个unicode字符串中的匹配节点。未引用百分比编码内容。
# title 类型:List
title = content.xpath('./div[@class="author clearfix"]/a[2]/h2/text()').get().strip()
# getall()返回匹配的所有节点,并以列表的形式返回
detail = content.xpath('.//div[@class="content"]//text()').getall()
detail = "".join(detail).strip()
# 创建一个字典,用于返回爬取结果
item = QsbkItem(title = title,detail = detail)
# item = {"title":title,"detail":detail}
# yield可以将函数变成生成器,可以将结果一个一个的返回到爬虫引擎
yield item
# 找到下一页的url
next_url = response.xpath('//ul[@class="pagination"]/li[last()]/a/@href').get()
# 判断是否找到最后一页
if not next_url:
return
else:
# 拼接出完整的url链接
url1 = "https://www.qiushibaike.com" + next_url
# 请求下一页
yield scrapy.Request(url1,callback=self.parse)
item.py
import scrapy
class QsbkItem(scrapy.Item):
# 此处用于定义项目的字段,使得代码更加规范
# 固定写法
title = scrapy.Field()
detail = scrapy.Field()
pipelines.py (存储数据)
将爬取下来的数据保存成json文件格式有三种方式
方式一:直接存入json文件
import json
class QsbkPipeline(object):
def __init__(self):
# 构造方法用于打开一个文件,也可以在open_spider方法中打开文件
self.file = open("./糗事段子.json","w",encoding="utf-8")
def open_spider(self,spider):
# 爬虫开始时会执行这行代码
print("爬虫开始")
# 这个方法用于处理爬虫引擎返回过来的结果
def process_item(self, item, spider):
# 因为item被QsbkItem类包装,所有要先转换成字典,才能被dumps成json格式
# 将返回过来的数据 dumps成json格式
# ensure_ascii = False表示不适用ascii码,即可正常显示中文
item_json = json.dumps(dict(item),ensure_ascii=False)
self.file.write(item_json+"\n")
return item
def close_spider(self,spider):
# 爬虫结束时会执行这行代码
print("爬虫结束")
方式二:使用JsonItemExporter存储
# 数据先存储到内存中,爬虫结束后,统一存储到文件
from scrapy.exporters import JsonItemExporter
class QsbkPipeline(object):
def __init__(self):
# 构造方法用于打开一个文件,也可以在open_spider方法中打开文件
# 因为这个模块是以二进制的方式写入,所以文件需要用二进制的方式打开
self.file = open("./糗事段子.json","wb")
# 创建一个导出对象
self.exports = JsonItemExporter(self.file,ensure_ascii=False,encoding="utf-8")
# 打开到处对象
self.exports.start_exporting()
def open_spider(self,spider):
# 爬虫开始时会执行这行代码
print("爬虫开始")
# 这个方法用于处理爬虫引擎返回过来的结果
def process_item(self, item, spider):
# 将数据存入
# 用这种方式就不需要将item转换成字典了
# 存储格式为列表,列表中的每一项时字典
# 这种方式会先把数据统一存储导内存中,然后最后统一存储导磁盘,比较费内存
self.exports.export_item(item)
return item
def close_spider(self,spider):
# 关闭exporters对象
self.exports.finish_exporting()
# 爬虫结束时会执行这行代码
print("爬虫结束")
方式三:使用JsonLinesItemExporter存储
# 每行每行的写入文件,跟第一种方式存储方式一样
from scrapy.exporters import JsonLinesItemExporter
class QsbkPipeline(object):
def __init__(self):
# 构造方法用于打开一个文件,也可以在open_spider方法中打开文件
# 也需要使用二进制的方式打开
self.file = open("./糗事段子.json", "wb")
self.exporters = JsonLinesItemExporter(self.file, ensure_ascii=False, encoding="utf-8")
def open_spider(self, spider):
# 爬虫开始时会执行这行代码
print("爬虫开始")
# 这个方法用于处理爬虫引擎返回过来的结果
def process_item(self, item, spider):
# 写入数据
self.exporters.export_item(item)
return item
def close_spider(self, spider):
# 关闭文件
self.file.close()
# 爬虫结束时会执行这行代码
print("爬虫结束")
这三种存储方式小结:
1.打开文件,将item转换成json格式,然后一个一个写入到文件(常规方式)
2.使用scrapy自带类存储JsonItemExporter和JsonLinesItemExporters两种方式
(1)JsonItemExporters:这个是每次把数据添加到内存中,最后统一写入到磁盘。好处是:存储的是一个满足json规则的数据,坏处是,如果数据大时,比较耗内存
(2)JsonLinesItemExporters:这个是每次调用export_item时,就把这个item存储到磁盘中。坏处时每个字典就是一行,整个文件不是满足json格式的文件。好处是每次处理数据的时候就直接写入到了磁盘,不会耗内存,比较安全
1.response是一个scrapy.http.response.html.HtmlResponse
对象,可以执行xpath css语法来提取数据
2.提取出来的数据是一个Selector
或者SelectorList
对象,如果想获取其中的字符串,那么应该执行get或者getall方法
3.getall方法
,用于获取selector中所有的文本,返回一个列表
4.get方法
,获取Selector中第一个方法,返回一个str类型
5.如果数据解析回来,要传给pipeline处理,那么可以使用yield来返回,也可以搜集所有的item,最后存入列表统一用return返回
6.item 建议在Items.py中定义好模型,以后不要使用字典返回
7.pipeline,这个专门用于保存数据的,其中有三个方法比较常用:
(1)open_spider(self,spider) 爬虫被打开时会被调用
(2)process_spider(self,item,spider) 爬虫将item转过来时会被调用
(3)close_spider(self,spider) 爬虫结束时会被调用
注意:要使用pipeline, 需要在setting.py中激活pipeline,并设置ITEM_PIPELINES