一, 基于终端指令的持久化存储
要保证爬虫文件的parse方法中有可迭代类型对象(一般是列表或字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中,进行持久化存储的操作
持久化存储的命令:
scrapy crawl 爬虫名称 -o 文件名.后缀名 # 仅支持这几种文件格式:'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle'
# -*- coding: utf-8 -*- import scrapy class XiaopapaSpider(scrapy.Spider): name = 'xiaopapa' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.qiushibaike.com/text/'] def parse(self, response): # xpath为response中的方法,可以直接用response直接调用xpath div_list = response.xpath("//div[@id='content-left']/div") # 创建空列表,用于存储获取的内容 content_list = [] for div in div_list: # xpath函数返回的为列表,列表中存放的数据为selector类型的数据 # 我们解析的内容被封装在了selector对象中,需要调用extract()将数据取出 # 如果可以保证xpath返回的列表中只有一条数据的时候可以用[0].extract()或者extract_first() author = div.xpath("./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()").extract_first() # 如果xpath返回的列表中有多条数据,则要使用extract() detail = "".join(div.xpath("./a[1]/div/span//text()").extract()) dic = { "author":author, "detail":detail } content_list.append(dic) # 必须要有返回,返回一个可迭代对象 return content_list
二 , 基于管道的持久化存储
scrapy框架中已经为我们专门集成好了高效,便捷的持久化操作功能,我们可以直接使用
两个有关文件 :
items.py : 数据结构模板文件,定义数据属性
pipelines.py : 管道文件,接收数据items,进行持久化操作
持久化存储流程:
- 爬虫文件爬取到数据后,需要将数据封装到items对象中
- 使用yield关键字将items对象提交给pipelines管道进行持久化操作
- 在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,然后编写持久化存储的代码将items对象中存储的数据进行持久化存储
- settings.py配置文件中开启管道
爬取boos直聘有关python爬虫前三页的职位名称,薪资和公司名称,进行持久化存储:
items:

1 # -*- coding: utf-8 -*- 2 3 # Define here the models for your scraped items 4 # 5 # See documentation in: 6 # https://doc.scrapy.org/en/latest/topics/items.html 7 8 import scrapy 9 10 11 class BoosItem(scrapy.Item): 12 # define the fields for your item here like: 13 # name = scrapy.Field() 14 job_name = scrapy.Field() 15 salary = scrapy.Field() 16 company = scrapy.Field()
爬虫文件:

1 # -*- coding: utf-8 -*- 2 import scrapy 3 4 from boos.items import BoosItem 5 6 7 class BoosDetilSpider(scrapy.Spider): 8 name = 'boos_detil' 9 # allowed_domains = ['www.boos.com'] 10 start_urls = ['https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&scity=101010100&industry=&position='] 11 12 url = "https://www.zhipin.com/c101010100/?query=python爬虫&page=%s&ka=page-1" 13 page = 1 14 15 def parse(self, response): 16 li_list = response.xpath("//div[@class='job-list']/ul/li") 17 for li in li_list: 18 job_name = li.xpath("./div/div[1]/h3/a/div[1]/text()").extract_first() 19 salary = li.xpath("./div/div[1]/h3/a/span/text()").extract_first() 20 company = li.xpath("./div/div[2]/div/h3/a/text()").extract_first() 21 22 # 实例化一个item对象 23 item = BoosItem() 24 # 将解析的数据封装到item中 25 item["job_name"] = job_name 26 item["salary"] = salary 27 item["company"] = company 28 29 # 将item交给管道 30 yield item 31 32 # 取前三页数据 33 if self.page <= 3: 34 self.page += 1 35 new_url = format(self.url%self.page) 36 37 # 手动发送请求 38 yield scrapy.Request(url=new_url,callback=self.parse)
pipeline管道文件:

1 # -*- coding: utf-8 -*- 2 3 # Define your item pipelines here 4 # 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html 7 8 9 class BoosPipeline(object): 10 fp = None 11 12 def open_spider(self,spider): 13 print("开始爬虫......") 14 self.fp = open("./boos.txt","w",encoding="utf-8") 15 16 # 爬虫文件每向管道提交一次item,则该方法就会被调用一次 17 # 参数item就是管道接收的item类型对象 18 def process_item(self, item, spider): 19 self.fp.write(item["job_name"]+":"+item["salary"]+":"+item["company"]+"\n") 20 # 返回给下一个即将被执行的管道类 21 return item 22 23 def close_spider(self,spider): 24 print("结束爬虫") 25 self.fp.close()
settings配置文件67-69行:

1 ITEM_PIPELINES = { 2 'boos.pipelines.BoosPipeline': 300, # 300表示优先级,每写一个类在这里注册一次 3 }
基于mysql的持久化存储:
只有pipeline添加了一个持久化存储的类,并且在settings中注册,其他没有改变
pipeline管道文件添加类:
import pymysql

1 class mysqlPileLine(object): 2 conn = None 3 cursor =None 4 def open_spider(self,spider): 5 self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='',db='scrapy',charset="utf8") 6 print(self.conn) 7 def process_item(self, item, spider): 8 self.cursor = self.conn.cursor() 9 # print(item) 10 #print('insert into boss values ("%s","%s","%s")'%(item['job_name'],item['salary'],item['company'])) 11 try: 12 print('insert into boss values ("%s","%s","%s")'%(item['job_name'],item['salary'],item['company'])) 13 self.cursor.execute('insert into boss values ("%s","%s","%s")'%(item['job_name'],item['salary'],item['company'])) 14 self.conn.commit() 15 except Exception as e: 16 print(e) 17 self.conn.rollback() 18 def close_spider(self,spider): 19 self.conn.close() 20 self.cursor.close()
settings注册:

1 ITEM_PIPELINES = { 2 #'bossPro.pipelines.BossproPipeline': 300, 3 'bossPro.pipelines.mysqlPileLine': 301, 4 }
基于redis的持久化存储:
pipeline管道文件添加类:
from redis import Redis

1 class redisPileLine(object): 2 conn = None 3 def open_spider(self,spider): 4 self.conn = Redis(host='127.0.0.1',port=6379) 5 print(self.conn) 6 def process_item(self, item, spider): 7 # print(item) 8 dic = { 9 'name':item['job_name'], 10 'salary':item['salary'], 11 'company':item['company'] 12 } 13 self.conn.lpush('boss',dic)
settings注册:

1 ITEM_PIPELINES = { 2 #'bossPro.pipelines.BossproPipeline': 300, 3 #'bossPro.pipelines.mysqlPileLine': 301, 4 'bossPro.pipelines.redisPileLine': 302, 5 }
三, 递归解析
当需要爬取一个多页面的网站的时候,每一个页面对应的url都是不同的,这时候就需要对这些不同的url依次发起请求,然后再通过对应的解析方法进行内容的解析
实现方案 :
1, 将每一个页面对应的url放到爬虫文件的起始url列表中,但是因为比较麻烦,所以不推荐这样做
2, 使用Request方法,手动发送请求
代码展示:
# -*- coding: utf-8 -*- import scrapy from boos.items import BoosItem class BoosDetilSpider(scrapy.Spider): name = 'boos_detil' # allowed_domains = ['www.boos.com'] start_urls = ['https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&scity=101010100&industry=&position='] url = "https://www.zhipin.com/c101010100/?query=python爬虫&page=%s&ka=page-1" page = 1 def parse(self, response): li_list = response.xpath("//div[@class='job-list']/ul/li") for li in li_list: job_name = li.xpath("./div/div[1]/h3/a/div[1]/text()").extract_first() salary = li.xpath("./div/div[1]/h3/a/span/text()").extract_first() company = li.xpath("./div/div[2]/div/h3/a/text()").extract_first() # 实例化一个item对象 item = BoosItem() # 将解析的数据封装到item中 item["job_name"] = job_name item["salary"] = salary item["company"] = company # 将item交给管道 yield item # 取前三页数据 if self.page <= 3: self.page += 1 new_url = format(self.url%self.page) # 使用Request方法手动发送请求,进行递归解析 yield scrapy.Request(url=new_url,callback=self.parse)