爬虫-第五篇-scrapy框架初识,持久化存储,手动请求发送

Posted yinhaiping

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了爬虫-第五篇-scrapy框架初识,持久化存储,手动请求发送相关的知识,希望对你有一定的参考价值。

准备工作

  • 什么是框架?如何学习框架?

    就是一个集成了各种功能且具有很强通用性(可以被应用在各种不同的需求中)的一个项目模板.

  • scrapy集成了哪些功能:

    • 高性能的数据解析操作,持久化存储操作,高性能的数据下载的操作.....
  • 环境的安装:

    a. pip3 install wheel
    
    b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
    
    c. 进入下载目录,执行 pip3 install Twisted?17.1.0?cp35?cp35m?win_amd64.whl
    
    d. pip3 install pywin32
    
    e. pip3 install scrapy

scrapy的基本使用

  • 创建一个工程:scrapy startproject firstBlood
  • 必须在spiders这个目录下创建一个爬虫文件
    • cd 项目目录
    • scrapy genspider spiderName www.xxx.com
  • 执行工程:scrapy crawl spiderName
import scrapy


class FirstSpider(scrapy.Spider):
    #爬虫文件的名称:爬虫文件的唯一标识(在spiders子目录下是可以创建多个爬虫文件)
    name = 'first'
    #允许的域名
    # allowed_domains = ['www.baidu.com']
    #起始的url列表:列表中存放的url会被scrapy自动的进行请求发送
    start_urls = ['https://www.baidu.com/','https://www.sogou.com/']
    #用作于数据解析:将start_urls列表中对应的url请求成功后的响应数据进行解析
    def parse(self, response):
        print(response)
  • settings.py:

    • 不遵从robots协议
    • 进行UA伪装
    • 进行日志等级设定:LOG_LEVEL = ‘ERROR‘

    持久化存储

    基于终端指令:

    • 特性:只可以将parse方法的返回值存储到本地的磁盘文件中
    • 指令:scrapy crawl spiderName -o filePath
    • 文件名后缀只能是json,csv,xml,pickle等
def parse(self, response):
    div_list = response.xpath('//*[@id="content-left"]/div')
    all_data = []
    for div in div_list:
        author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()  
        content = div.xpath('./a[1]/div/span//text()').extract()
        content = ''.join(content)
        #构建数据结构
        dic = 
            'author':author,
            'content':content
        
        all_data.append(dic)
        return all_data

基于管道

  • 实现流程
    1.数据解析
    2.在item类中定义相关的属性

    # item.py
    import scrapy
    class QiubaiproItem(scrapy.Item):
        # define the fields for your item here like:
        author = scrapy.Field() #Field可以将其理解成是一个万能的数据类型
        content = scrapy.Field()

    3.将解析的数据存储或者封装到一个item类型的对象(items文件中对应类的对象)

    # qiubai.py
    def parse(self, response):
        div_list = response.xpath('//*[@id="content-left"]/div')
        all_data = []
        for div in div_list:
            author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
            content = div.xpath('./a[1]/div/span//text()').extract()
            content = ''.join(content)
    
            #将解析的数据存储到item对象
            item = QiubaiproItem()
            item['author'] = author
            item['content'] = content
    
            #将item提交给管道
            yield item #item一定是提交给了优先级最高的管道类

    4.向管道提交item--->yield
    5.在管道文件的process_item方法中接收item进行持久化存储

    class QiubaiproPipeline(object):
        fp = None
        def open_spider(self,spider):
            print('开始爬虫......')
            self.fp = open('qiushibaike.txt','w',encoding='utf-8')
    
        #使用来接收爬虫文件提交过来的item,然后将其进行任意形式的持久化存储
        #参数item:就是接收到的item对象
        #该方法每接收一个item就会调用一次
        def process_item(self, item, spider):
            author = item['author']
            content= item['content']
    
            self.fp.write(author+':'+content+'\n')
            return item #item是返回给了下一个即将被执行的管道类
    
        def close_spider(self,spider):
            print('结束爬虫!')
            self.fp.close()

    6.在配置文件中开启管道

    # settings.py
    ITEM_PIPELINES = 
       'qiubaiPro.pipelines.QiubaiproPipeline': 300, #300表示的是优先级
       #  'qiubaiPro.pipelines.mysqlPL': 301,
       #  'qiubaiPro.pipelines.RedisPL': 302,
    

将同一份数据持久化到不同的平台

  • 1.管道文件中的一个管道类负责数据的一种形式的持久化存储
  • 2.爬虫文件向管道提交的item只会提交给优先级最高的那一个管道类
  • 3.在管道类的process_item中的return item表示的是将当前管道接收的item返回/提交给
    下一个即将被执行的管道类
#负责将数据存储到mysql
class MysqlPL(object):
    conn = None
    cursor = None
    def open_spider(self,spider):
        self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='123',db='spider',charset='utf8')
        print(self.conn)
    def process_item(self,item,spider):
        author = item['author']
        content = item['content']

        sql = 'insert into qiubai values ("%s","%s")'%(author,content)
        self.cursor = self.conn.cursor()
        try:
            self.cursor.execute(sql)
            self.conn.commit()
        except Exception as e:
            print(e)
            self.conn.rollback()
        return item
    def close_spider(self,spider):
        self.cursor.close()
        self.conn.close()

class RedisPL(object):
    conn = None
    def open_spider(self,spider):
        self.conn = Redis(host='127.0.0.1',port=6379)
        print(self.conn)
    def process_item(self,item,spider):
        self.conn.lpush('all_data',item)
        #注意:如果将字典写入redis报错:pip install -U redis==2.10.6

在scrapy中如何进行手动请求发送

手动请求发送(GET)

  • 使用场景:爬取多个页码对应的页面源码数据
  • yield scrapy.Request(url,callback)
 #将多个页码对应的页面数据进行爬取和解析的操作
    url = 'https://www.qiushibaike.com/text/page/%d/'#通用的url模板
    pageNum = 1
    #parse第一次调用表示的是用来解析第一页对应页面中的段子内容和作者
    def parse(self, response):
        div_list = response.xpath('//*[@id="content-left"]/div')
        all_data = []
        for div in div_list:
            # scrapy中的xpath返回的列表的列表元素一定是Selector对象,我们最终想要的解析的
            # 数据一定是存储在该对象中
            # extract()将Selector对象中data参数的值取出
            # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
            author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()

            # 列表直接调用extract表示的是将extract作用到每一个列表元素中
            content = div.xpath('./a[1]/div/span//text()').extract()

            content = ''.join(content)

            # 将解析的数据存储到item对象
            item = QiubaiproItem()
            item['author'] = author
            item['content'] = content

            # 将item提交给管道
            yield item  # item一定是提交给了优先级最高的管道类

        if self.pageNum <= 5:
            self.pageNum += 1
            new_url = format(self.url%self.pageNum)
            #手动请求(get)的发送
            yield scrapy.Request(new_url,callback=self.parse)

手动请求发送(POST)

data = #post请求的请求参数
‘kw‘:‘aaa‘

yield scrapy.FormRequest(url,formdata=data,callback)

很少用此框架发送post请求

scrapy五大核心组件的工作流程

引擎(Scrapy)

? 用来处理整个系统的数据流处理, 触发事务(框架核心)
调度器(Scheduler)
? 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
下载器(Downloader)
? 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
爬虫(Spiders)
? 爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
项目管道(Pipeline)
? 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

以上是关于爬虫-第五篇-scrapy框架初识,持久化存储,手动请求发送的主要内容,如果未能解决你的问题,请参考以下文章

爬虫系统

爬虫相关

python爬虫框架scrapy初识

python网络爬虫——scrapy框架持久化存储

爬虫系列

爬虫知识总结