11,scrapy框架持久化存储

今日总结

  • 基于终端指令的持久化存储
  • 基于管道的持久化存储

今日详情

1.基于终端指令的持久化存储

  • 保证爬虫文件的parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作。
执行输出指定格式进行存储:将爬取到的数据写入不同格式的文件中进行存储
    scrapy crawl 爬虫名称 -o xxx.json
    scrapy crawl 爬虫名称 -o xxx.xml
    scrapy crawl 爬虫名称 -o xxx.csv

2.基于管道的持久化存储

scrapy框架中已经为我们专门集成好了高效、便捷的持久化操作功能,我们直接使用即可。要想使用scrapy的持久化操作功能,我们首先来认识如下两个文件:

    items.py:数据结构模板文件。定义数据属性。
    pipelines.py:管道文件。接收数据(items),进行持久化操作。

持久化流程:
    1.爬虫文件爬取到数据后,需要将数据封装到items对象中。
    2.使用yield关键字将items对象提交给pipelines管道进行持久化操作。
    3.在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,然后编写持久化存储的代码将item对象中存储的数据进行持久化存储
    4.settings.py配置文件中开启管道

小试牛刀:将boss招聘网站中的招聘爬虫的数据爬取下来,然后进行持久化存储

- 爬虫文件:boss.py

# -*- coding: utf-8 -*-
import scrapy

from bossPro.items import BossproItem

class BossSpider(scrapy.Spider):
    name = 'boss'
    # allowed_domains = ['www.xxx.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=%d&ka=page-2'
    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[@class="info-primary"]/h3/a/div/text()').extract_first()
            salary = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()').extract_first()
            company = li.xpath('.//div[@class="company-text"]/h3/a/text()').extract_first()

            # print(company)
            item = BossproItem()
            item['job_name'] = job_name
            item['salary'] = salary
            item['company'] = company
            yield item

        if self.page <= 3:
            print(f'执行第{self.page+1}页')
            self.page += 1
            new_url = format(self.url % self.page)

            yield scrapy.Request(url=new_url, callback=self.parse)

- items文件:items.py

import scrapy

class BossproItem(scrapy.Item):
    # define the fields for your item here like:
    job_name = scrapy.Field()
    salary = scrapy.Field()
    company = scrapy.Field()

- 管道文件:pipelines.py

import os
import pymysql
from redis import Redis

# 文件存储
class BossproPipeline(object):

    fp = None
    def open_spider(self, spider):
        print('开始爬虫.............................')
        if not os.path.exists('./boss'):
            os.mkdir('./boss')
        self.fp = open('./boss/boss.txt', 'w', encoding='utf8')

    def close_spider(self, spider):
        print('结束爬虫.............................')
        self.fp.close()

    def process_item(self, item, spider):
        self.fp.write(item['job_name']+':'+item['salary']+':'+item['company']+'
')
        return item

# mysql数据库存储
class mysqlPipeline(object):
    conn = None
    cursor =None
    def open_spider(self,spider):
        self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='', db='boss', charset="utf8")
        print(self.conn)
    def process_item(self, item, spider):
        self.cursor = self.conn.cursor()
        try:
            print('insert into boss values ("%s","%s","%s")'%(item['job_name'],item['salary'],item['company']))
            self.cursor.execute('insert into boss(job_name,salary,company) values ("%s","%s","%s")'%(item['job_name'],item['salary'],item['company']))
            self.conn.commit()
        except Exception as e:
            self.conn.rollback()
    def close_spider(self,spider):
        self.conn.close()
        self.cursor.close()

# redis存储
class redisPipeLine(object):
    conn = None

    def open_spider(self,spider):
        self.conn = Redis(host='127.0.0.1', port=6379, db=2, charset='utf-8')
        print(self.conn)

    def process_item(self, item, spider):
        # print(item['salary'],)
        dic = {
            'name': item['job_name'],
            'salary': item['salary'],
            'company': item['company']
        }

        self.conn.lpush('boss', dic)

- 配置文件:settings.py

#开启管道
ITEM_PIPELINES = {
   'bossPro.pipelines.BossproPipeline': 300,
   'bossPro.pipelines.mysqlPipeline': 301,
   'bossPro.pipelines.redisPipeLine': 302,
}

 

- 面试题:如果最终需要将爬取到的数据值一份存储到磁盘文件,一份存储到数据库中,则应该如何操作scrapy?  

- 答:管道文件中的代码为

#该类为管道类,该类中的process_item方法是用来实现持久化存储操作的。
class DoublekillPipeline(object):

    def process_item(self, item, spider):
        #持久化操作代码 (方式1:写入磁盘文件)
        return item

#如果想实现另一种形式的持久化操作,则可以再定制一个管道类:
class DoublekillPipeline_db(object):

    def process_item(self, item, spider):
        #持久化操作代码 (方式1:写入数据库)
        return item

 在settings.py开启管道操作代码为:

#下列结构为字典,字典中的键值表示的是即将被启用执行的管道文件和其执行的优先级。
ITEM_PIPELINES = {
   'doublekill.pipelines.DoublekillPipeline': 300,
    'doublekill.pipelines.DoublekillPipeline_db': 200,
}

#上述代码中,字典中的两组键值分别表示会执行管道文件中对应的两个管道类中的process_item方法,实现两种不同形式的持久化操作。

  

 
 
 
原文地址:https://www.cnblogs.com/feifeifeisir/p/10458554.html