Day 43 爬虫_scrapy框架_持久化储存
scrapy框架
scrapy初识
- 什么是框架?
- 所谓的框架简单通用解释就是就是一个具有很强通用性并且集成了很多功能的项目模板,该模板可被应用在不同的项目需求中。也可被视为是一个项目的半成品。
- 如何学习框架?
- 对于刚接触编程或者初级程序员来讲,对于一个新的框架,只需要掌握该框架的作用及其各个功能的使用和应用即可,对于框架的底层实现和原理,在逐步进阶的过程中在慢慢深入即可。
- 什么是scrapy?
- Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍。其内部已经被集成了各种功能(高性能异步下载,队列,分布式,解析,持久化等)。对于框架的学习,重点是要学习其框架的特性、各个功能的用法即可。
scrapy基本使用
环境安装:
linux和mac操作系统:pip install scrapy
windows系统:
1、pip install wheel
2、下载twisted,下载地址为http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
3、安装twisted:pip install Twisted‑17.1.0‑cp36‑cp36m‑win_amd64.whl
4、pip install pywin32
5、pip install scrapy
测试:在终端里录入scrapy指令,没有报错即表示安装成功!
scrapy使用流程:
1、创建工程:scrapy startproject ProName
2、进入工程目录:cd ProName
3、创建爬虫文件:scrapy genspider spiderName www.xxx.com
4、编写相关操作代码
5、执行工程:scrapy crawl spiderName
代码示例:
spiders下项目文件
class FirstSpider(scrapy.Spider): # 爬虫文件的名称:就是爬虫源文件的一个唯一标识 name = 'first' # 允许的域名:用来限定 start_urls 列表中的 url 哪些可以即兴请求的发送(不常用) # allowed_domains = ['www.xxx.com'] # 起始的url列表:台列表中存放的url会被scrapy自动进行请求的发送 start_urls = ['http://www.baidu.com/','http://www.sogou.com'] # 用于数据解析:response 参数表示请求成功后对应的相应对象 def parse(self, response): print(response) # 运行 # scrapy crawl first # scrapy crawl first --nolog 执行时不显示日志信息,但也不会显示错误信息(不常用) # 可以在 settings 文件中设置显示的日志级别 log LEVEN:ERROR # 注意:默认是支持Roboot协议的,我们现在了解可以先关掉 # settings.py 中找到 ROBOTSTXT_OBEY = True 改为 ROBOTSTXT_OBEY = False
settings.py
# 修改内容及其结果如下: # 19行:伪装请求载体身份 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' # 22行:#可以忽略或者不遵守robots协议 ROBOTSTXT_OBEY = False # 添加日志打印级别 LOG_LEVEL = 'ERROR'
scrapy的高性能持久化存储操作
基于终端指令的持久化存储
基于终端指令:
要求:只可以将 parse 方法的返回值存储到本地的文本文件中
注意:持久化存储对应的文本文件的类型只可以为:json、jsonlines、jl、csv、xml、marshal、pickle)
指令:scrapy crawl xxx -o filePath
优点:简易、高效、便捷
缺点:局限性比较强(数据只可以存储到指定后缀的文件中)
保证爬虫文件的parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作。
执行指令:
执行输出指定格式进行存储,将爬取到的数据写入不同格式的文件中进行存储
scrapy crawl 爬虫名称 -o xxx.json
scrapy crawl 爬虫名称 -o xxx.xml
scrapy crawl 爬虫名称 -o xxx.csv
import scrapy class QiubaiproSpider(scrapy.Spider): name = 'qiubaiPro' allowed_domains = ['www.qiushibaike.com/text/'] start_urls = ['https://www.qiushibaike.com/text/'] # 基于终端指令的持久化存储 def parse(self, response): # 获取作者与内容 div_list = response.xpath('//*[@id="content"]/div/div[2]/div') data_list = [] for div in div_list: # xpath 返回的是列表,但是列表元素一定是Selector 类型的对象 # extract 可以将Selector 对象中 data 参数存储的字符串提取出出来 user = div.xpath('./div/a[2]/h2/text()')[0].extract() # 列表调用了 extract 之后,这表示将列表中每一个Selector 对象中 data 对应的字符串提取了出来 # user = div.xpath('./div/a[2]/h2/text()').extract_first() info = div.xpath('./a/div/span//text()').extract() info = ' '.join(info) data = { 'user':user, 'info':info } data_list.append(data) return data_list
基于管道的持久化存储操作
scrapy框架中已经为我们专门集成好了高效、便捷的持久化操作功能,我们直接使用即可。要想使用scrapy的持久化操作功能,我们首先来认识如下两个文件:
items.py:数据结构模板文件。定义数据属性。
pipelines.py:管道文件。接收数据(items),进行持久化操作。
持久化流程:
1、数据解析
2、在 item 类中定义相关的属性
3、将解析的数据封装存储到 item 类型对象
4、使用yield关键字将items对象提交给pipelines管道进行持久化操作。
5、在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,然后编写持久化存储的代码将item对象中存储的数据进行持久化存储
6、settings.py配置文件中开启管道
代码演示:
qiubaiPro.py
import scrapy from qiubai.items import QiubaiItem class QiubaiproSpider(scrapy.Spider): name = 'qiubaiPro' allowed_domains = ['www.qiushibaike.com/text/'] start_urls = ['https://www.qiushibaike.com/text/'] # 基于终端指令的持久化存储 # def parse(self, response): # # 获取作者与内容 # div_list = response.xpath('//*[@id="content"]/div/div[2]/div') # data_list = [] # for div in div_list: # # xpath 返回的是列表,但是列表元素一定是Selector 类型的对象 # # extract 可以将Selector 对象中 data 参数存储的字符串提取出出来 # user = div.xpath('./div/a[2]/h2/text()')[0].extract() # # 列表调用了 extract 之后,这表示将列表中每一个Selector 对象中 data 对应的字符串提取了出来 # # user = div.xpath('./div/a[2]/h2/text()').extract_first() # info = div.xpath('./a/div/span//text()').extract() # info = ' '.join(info) # # data = { # 'user':user, # 'info':info # } # data_list.append(data) # return data_list # 基于管道的持久化存储操作 def parse(self, response): # 获取作者与内容 div_list = response.xpath('//*[@id="content"]/div/div[2]/div') data_list = [] for div in div_list: # xpath 返回的是列表,但是列表元素一定是Selector 类型的对象 # extract 可以将Selector 对象中 data 参数存储的字符串提取出出来 user = div.xpath('./div/a[2]/h2/text()')[0].extract() # 列表调用了 extract 之后,这表示将列表中每一个Selector 对象中 data 对应的字符串提取了出来 # user = div.xpath('./div/a[2]/h2/text()').extract_first() info = div.xpath('./a/div/span//text()').extract() info = ' '.join(info) item = QiubaiItem() item['user'] = user item['info'] = info yield item
items.py
import scrapy class QiubaiItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() user = scrapy.Field() info = scrapy.Field()
pipelines.py
import pymysql class QiubaiPipeline(object): fp = None # 重写一个父类方法:该方法只在开始爬虫的时候调用一次 def open_spider(self, spider): print('爬虫开始...') self.fp = open(r'./qiubai/file/qiubai.xlsx', 'w', encoding='utf-8') # 专门用来处理 item 类型对象 # 该方法可以接收爬虫文件提交过来的 item 对象 # 该方法每接收一个 item 对象就会被调用一次 def process_item(self, item, spider): user = item['user'] info = item['info'] self.fp.write(user + info) return item # 重写一个父类方法:该方法只在结束爬虫的时候调用一次 def close_spider(self, spider): print("爬虫结束...") self.fp.close() # 管道文件中一个管道类对应将一组数据存储到一个平台或载体中 class QiubaiPipeline_DB(object): conn = None cursor = None def open_spider(self, spider): print('写入数据库。。。') self.conn = pymysql.Connect(host='192.168.214.23', port=3306, user='root', password='123456', db='srcapy', charset='utf8') def process_item(self, item, spider): self.cursor = self.conn.cursor() try: self.cursor.execute('insert into src_qiushi value("%s","%s")' % (item['user'], item['info'])) self.conn.commit() except Exception as e: print(e) self.conn.rollback() return item def close_spider(self, spider): print('入库成功') self.cursor.close() self.conn.close()
settings.py
BOT_NAME = 'qiubai' SPIDER_MODULES = ['qiubai.spiders'] NEWSPIDER_MODULE = 'qiubai.spiders' USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36 OPR/67.0.3575.115 (Edition B2)' ROBOTSTXT_OBEY = False LOG_LEVEL = 'ERROR' ITEM_PIPELINES = { 'qiubai.pipelines.QiubaiPipeline': 300, 'qiubai.pipelines.QiubaiPipeline_DB': 200, }
Spider类的全站数据爬取
大部分的网站展示的数据都进行了分页操作,那么将所有页码对应的页面数据进行爬取就是爬虫中的全站数据爬取。
基于scrapy如何进行全站数据爬取呢?
1、将每一个页码对应的url存放到爬虫文件的起始url列表(start_urls)中。(不推荐)
2、使用Request方法手动发起请求。(推荐)
案例:爬取图片名称
import scrapy class XiaohuaproSpider(scrapy.Spider): name = 'xiaohuaPro' # allowed_domains = ['www.521609.com/daxuemeinv/'] start_urls = ['http://www.521609.com/daxuemeinv/'] # 设置一个通用的url模本(不可变) url = 'http://www.521609.com/daxuemeinv/list8%s.html' page_num = 1 def parse(self, response): li_list = response.xpath('//*[@id="content"]/div[2]/div[2]/ul/li') for li in li_list: href = li.xpath('./a/@href')[0].extract() title = li.xpath('./a/img/@alt')[0].extract() print(href,title) if self.page_num<2: self.page_num += 1 new_url = format(self.url%self.page_num) # 手动请求发送,callback回调函数是专门用作于数据解析的 yield scrapy.Request(url=new_url,callback=self.parse)
scrapy五大核心组件简介
scrapy的基本使用我们已经掌握,但是各位心中一定会有些许的疑问,我们在编写scrapy工程的时候,我们只是在定义相关类中的属性或者方法,但是我们并没有手动的对类进行实例化或者手动调用过相关的方法,那么这些操作都是谁做的呢?接下来我们就来看看scrapy的五大核心组件的工作流程,然后大家就会上述的疑问有基本了解了。
引擎(Scrapy):用来处理整个系统的数据流处理, 触发事务(框架核心)
调度器(Scheduler):用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
下载器(Downloader):用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
爬虫(Spiders):爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
项目管道(Pipeline):负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。