实训小项目(详细讲解)"/>
Scrapy实训小项目(详细讲解)
前言:
我们大多数基于requests或aiohttp来实现爬虫的整个逻辑的。可以发现,在这个过程中,我们需要实现爬虫相关的所有操作,例如爬取逻辑、异常处理、数据解析、数据存储等,但其实这些步骤很多是通用或者重复的。既然如此,我们完全可用把这些步骤的逻辑抽离出来,把其中通用的功能做成一个个基础的组件
架构设计(理解)
架构
Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,
Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器).
Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。
Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
数据流动
- 引擎打开一个网站(open a domain),找到处理该网站的Spider并向该spider请求第一个要爬取的URL(s)。
- 引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler )以Request调度。
- 引擎向调度器请求下一个要爬取的URL。
- 调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求( request)方向)转发给下载器(Downloader )。
- 一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(返回( response)方向)发送给引擎。
- 引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理。
- Spider处理Response并返回爬取到的Item及(跟进的)新的Request给引擎。
- 引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度器。
- (从第二步)重复直到调度器中没有更多地request,引擎关闭该网站。
从整体上来看,各个组件都只专注于一个功能,组件和组件之间的耦合度非常低,也非常容易扩展。再由引擎将各个组件组合起来,使得各个组件各司其职,互相配合,共同完成爬取工作。另外加上Scrapy对异步处理的支持,Scrapy还可以最大限度地利用网络带宽,提高数据爬取和处理的效率
Scrapy框架的使用(重点)
安装Scrapy
pip install Scrapy
安装好Scrapy框架之后,我们首先来了解一下Scrapy爬虫的制作过程:
制作 Scrapy 爬虫 一共需要4步:
- 新建项目 (scrapy star tproject xxx):新建一个新的爬虫项目
- 明确目标 (编写items.py):明确你想要抓取的目标
- 制作爬虫 (spiders/xxspider .py):制作爬虫开始爬取网页
- 存储内容 (pipelines.py):设计管道存储爬取内容
实训一:(百度爬虫)
升级 pip 版本
pip install --upgrade pip
安装Scrapy
pip install Scrapy
1、创建一个工程
scrapy star tproject f r istProject
这些文件分别是:
spiders ----------------------------------------------------# 放置Spiders的文件夹
item.py -------------------------------------# Items的定义,定义爬取的数据结构
middleware.py ------------------# Middlewares的定义,定义爬取时的中间件
pipelines.py -----------------------------------# Pipelines的定义,定义数据管道
settings.py -------------------------------------------------------------------# 配置文件
2、创建Spider
cd fristProject
scrapy genspider baidu baidu
(先进入对应的目录,再创建Spider)
- 执行完毕后,spiders文件夹中多了一个baidu.py,它就是刚刚创建的Spider
- 这个BaiduSpider就是刚才命令行自动创建的Spider,它继承了scrapy的Spider类
- BaiduSpider有3个属性:
1、name:每个项目唯一的名字,用来区分不同的Spider
2、allowd_domains:允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过滤掉
3、star t_ur l:包含了Spider在启动时爬取的URL列表,初始请求是由它来定义的
- BaiduSpuder有1个方法:
1、parse():在默认情况下,star t_ur ls里面的链接构成的请求完成下载后,parse()方法就会被调用,返回的响应就会作为唯一的参数传递给parse()方法。该方法负责解析返回的响应、提取数据或者进一步生成要处理的请求,相当于回调函数
我们可以通过修改baidu.py来定义爬虫逻辑
baidu.py
import scrapy
class BaiduSpider(scrapy.Spider ):
# 爬虫名的唯一标识
name = 'baidu'
# 允许的域名
# ps:但是有一个问题:对于star t_ur ls里的起始爬取页面,它是不会过滤的,它的作用是过滤首页之后的页面-----待验证
allowed_domains = ['baidu']
# 起始的ur l列表:只可以存储ur l
# 作用:列表中存储的ur l都会被进行get请求的发送
star t_ur ls = ['/']
# 数据解析
# parse方法调用的次数完全取决于请求的次数
# 参数response:表示的就是服务器返回的响应对象
def parse(self, response):
# 输出响应
print(response)
4、修改set t ings.py
- settings.py是整个项目的设置文件
- Scrapy项目允许问我们自定义所有Scrapy组件的行为,其中就是通过修改settings.py来完成
- 我们将会在接下来的学习中一步一步的了解Scrapy组件的设置
- Scrapy框架可以客制化的设置有很多,我们从中选3个用得比较多的基本设置开始:
1、 禁止robots:
ROBOTSTXT_OBEY = False
2、指定日志类型:
LOG_LEVEL = 'ERROR'
3、UA伪装
UA伪装: USER_AGENT = ' '
- 执行工程后,默认会输出工程所有的日志信息(默认 LOG_LEVEL=‘INFO’ )。为了避免输出过多的日志信息,我们将日志等级提升到ERROR
4、执行爬虫
scrapy crawl baidu
实训二(段子网爬虫)
链接:/
【知识点一】:
- 在scrapy框架中,GET请求发送的方式是:
# callback指定解析函数,用于解析数据
# GET请求
yield scrapy.Request(url, callback)
# # 完整版
# yield scrapy.Request(url, headers.cookies, meta, callback=self.parse_response)
- POST请求的方式是:
# POST请求
yield scrapy.FormRequest(ur l,callback,formdata)
# # 完整版
# yield scrapy.FormRequest(ur l, headers. cookies, formdata, meta,callback=self.parse_response)
在 scrapy.Request(url, callback) 还有一个必须用到的参数callback,它默认是 self.parse() ,代表回调函数,代表将Request执行请求后得到的Response对象调用到该回调函数中,这也是为什么我们能在 self.parse() 进行数据解析的原因;
【知识点二】:
在Scrapy框架中,已经默认为我们实现一个 star t_requests() 方法:
def star t_requests(self):for u in self.start_urls:yield Request(u,callback=self.parse)
- 我们还发现这是一个生成器,返回的所有Request都会作为初始Request加入调度队列
因此,如果我们想要自定义初始请求,只需要重新 star t_requests() 方法就可以。比如说我们改成POST请求:
def star t_requests(self):for u in self.star t_ur ls:yield scrapy.FormRequest(ur l=u,callback=self.parse)
我们开始正式的段子网爬虫实训:
1、创建一个工程
scrapy startproject duanziProject
2、定义item(items.py)
import scrapyclass DuanziprojectItem(scrapy.Item):# define the fields for your item here like:# 标题title = scrapy.Field()# 作者author = scrapy.Field()# 时间re_time = scrapy.Field()# 正文content = scrapy.Field()
3、创建爬虫
cd duanziProject
scrapy genspider duanzi duanzixing
duanzi.py
import scrapy
from duanziProject.items import DuanziprojectItem
class DuanziSpider(scrapy.Spider ):name = 'duanzi'# allowed_domains = ['/']star t_ur ls = ['//']# 通用的url模板base_url = '/{}/'# 页码(从第二页开始)page = 2# 重写父类方法:这个是该方法的原始实现# 这里其实和原本一样def start_requests(self):for u in self.star t_urls:yield scrapy.Request(url=u, callback=self.parse)# 将段子网中所有页码对应的数据进行爬取def parse(self, response):# 找到所有的ar ticlearticle_ls = response.xpath('/html/body/section/div/div/ar ticle')# 遍历for article in article_ls:# 实例化itemitem = DuanziprojectItem()# 标题item['title'] = ar ticle.xpath('./header /h2/a/text()').ext ract_first()# 作者item['author '] = ar ticle.xpath('./p[1]/span[1]/text()').ext ract_first()# 时间item[' re_time'] = ar ticle.xpath('./p[1]/time/text()').ext ract_first()# 正文item['content'] = ar ticle.xpath('./p[2]/text()').ext ract_first()# 传递给管道yield item# 对新的页面发起请求# 直到递归条件结束if self.page < 11: # 结束递归的条件print(self.page)new_url = self.base_url.format(self.page) # 其他页码对应的完整urlself.page += 1# 对新的页码对应的ur l进行请求发送(手动请求GET发送)yield scrapy.Request(ur l=new_url, callback=self.parse)
我们在 self.parse() 后面手动设置了一个对新的ur l发起的请求,由于回调函数还是 self.parse() ,当递归条件未结束时,Scrapy爬虫会一直重复调用 self.parse() ,此时 self.parse() 兼顾了数据解析和发送请求的功能
4、定义Piplines
from itemadapter import ItemAdapter
import jsonclass DuanziprojectPipeline:# 初始化def __init__(self):# 文件self.fp = Nonedef process_item(self, item, spider ):# 提示print(f'JSON正在写入{item["title"]}')# 写入文件json.dump(str(item), self.fp, ensure_ascii=False, indent=4)# 伪装json格式self.fp.wr ite( " ,\n" )# 将item存储到本文文件return item# open_spiderdef open_spider (self, spider ):print('使用json方式的open_spider ()!')self.fp = open('./duanzi.json', 'wt', encoding='utf-8')# 伪装json格式self.fp.wr ite('[\n')# close_spiderdef close_spider (self, spider ):print('结束使用json方式的close_spider ()')self.fp.wr ite(']')self.fp.close()
5、修改settings.py
- 禁止robots:
ROBOTSTXT_OBEY = False
- 指定日志类型:
LOG_LEVEL = 'ERROR'
- UA伪装:
USER_AGENT = ' '
- 开启管道:
ITEM_PIPELINES = {}
6、执行爬虫
scrapy crawl duanzi
实训三(远鉴字幕组电影详情页爬虫)
链接:
待完成
更多推荐
Scrapy实训小项目(详细讲解)
发布评论