zoukankan      html  css  js  c++  java
  • 5-爬虫-Scrapy爬虫框架环境安装及使用、数据解析、持久化存储、redis数据库的使用、全站数据的爬取

    scrapy基本介绍

    基本介绍:基于异步爬虫的框架。高性能的数据解析,高性能的持久化存储,全站数据爬取,增量式爬虫,分布式爬虫......

    scrapy环境的安装

    - Linux:

      pip install scrapy

    - Windows:

      a. pip install wheel

      b. 下载twisted https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

         - twisted插件是scrapy实现异步操作的三方组件。
      c. 进入下载目录,执行 pip install Twisted‑17.1.0‑cp35‑cp35m‑win_amd64.whl

      d. pip install pywin32

      e. pip install scrapy

    scrapy基本使用

    - 1.创建一个工程:scrapy startproject proName
      - 工程的目录结构:
      - spiders:爬虫包/文件夹
        - 要求:必须要存储一个或者多页爬虫文件
      - settings.py:配置文件
    - 2.创建爬虫文件
      - cd proName
      - scrapy genspider spiderName www.xxx.com
    - 3.执行工程
      - scrapy crawl spiderName
      - 重点关注的日志信息:ERROR类型的日志信息
        - settings.py:LOG_LEVEL = 'ERROR'
        - settings.py:不遵从robots协议 (将True改为False)
        - settings.py:UA伪装    

           USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'

     spiders下的爬虫文件内容介绍

    cd proName
    scrapy genspider spiderName www.xxx.com

    # -*- coding: utf-8 -*-
    import scrapy
    
    
    class FirstSpider(scrapy.Spider):
        #爬虫文件名称:当前爬虫文件的唯一标识
        name = 'first'
        #允许的域名(用来做限定)
        # allowed_domains = ['www.taobao.com']
        #起始的url列表:存储即将要发起请求的url,列表存有的url都会被框架自动进行get请求的发送
        start_urls = ['https://www.sogou.com/','https://www.taobao.com']
        #数据解析
        #参数response就是请求成功后对应的响应对象
        def parse(self, response):
            print(response)

    数据解析

    - 使用xpath进行数据解析
    - 注意:使用xpath表达式解析出来的内容不是直接为字符串,而是Selector对象,想要的
    字符串数据是存储在该对象中。
    - extract():如果xpath返回的列表元素有多个
    - extract_first():如果xpath返回的列表元素只有一个

    import scrapy
    
    
    class QiubaiSpider(scrapy.Spider):
        name = 'qiubai'
        # allowed_domains = ['www.xxx.com']
        start_urls = ['https://www.qiushibaike.com/text/']
    
        def parse(self, response):
            div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
            for div in div_list:
                # 返回的并不是字符串形式的作者名称,而是返回了一个Selector对象
                # 想要的字符串形式的作者名称是存储在该对象中
                # 需要将Selector对象中存储的字符串形式的作者名称取出
                # author = div.xpath('./div[1]/a[2]/h2/text()')[0]  # 这样取出得是一个对象需要在后边加extract才能取出文本
                author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
                # Selector.extract():将Selector对象中的字符串取出
                # [].extract_first():将列表中的第一个列表元素(Selector)中的字符串取出
                content = div.xpath('./a/div/span//text()').extract()
                # [].extract():将列表中的每一个列表元素Selector对象中的字符串取出
                content = ''.join(content)
                print(author, content)

    持久化存储

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

    只可以将parse方法的返回值存储到制定后缀的文本文件中(只支持这些文本文件类型'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle')

    局限性:
        - 1.只可以将parse方法返回值进行持久化存储
        - 2.只可以将数据存储到文件中无法写入到数据库
     存储指令:scrapy crawl spiderName -o filePath

    import scrapy
    
    
    class QiubaiSpider(scrapy.Spider):
        name = 'qiubai'
        # allowed_domains = ['www.xxx.com']
        start_urls = ['https://www.qiushibaike.com/text/']
    
        # 基于终端指令进行持久化存储
        def parse(self, response):
            div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
            all_list = []
            for div in div_list:
                author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
                content = div.xpath('./a/div/span//text()').extract()
                content = ''.join(content)
                dic = {
                    'author': author,
                    'content': content
                }
                all_list.append(dic)
            return all_list

    基于管道的持久化存储

    1.在爬虫文件中进行数据解析

    2.在items.py文件中定义相关的属性

      - 属性的个数要和解析出来的字段个数同步

    3.将解析出来的数据存储到item类型的对象中

    4.将item提交给管道

    5.在管道中接收item对象且将该对象中存储的数据做任意形式的持久化存储

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

    qiubai.py
    import scrapy
    from qiubaiPro.items import QiubaiproItem
    
    
    class QiubaiSpider(scrapy.Spider):
        name = 'qiubai'
        # allowed_domains = ['www.xxx.com']
        start_urls = ['https://www.qiushibaike.com/text/']
    
        def parse(self, response):
            div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
            all_list = []
            for div in div_list:
                author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
                content = div.xpath('./a/div/span//text()').extract()
                content = ''.join(content)
    
                # 实例化item类型的对象
                item = QiubaiproItem()
                # 只能通过中括号调属性,不能用点
                item['author'] = author
                item['content'] = content
    
                # 将item提交给管道
                yield item 
    item.py
    import scrapy
    
    
    class QiubaiproItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        author = scrapy.Field()
        content = scrapy.Field()
    pipelines.py
    class QiubaiproPipeline:
        fp = None
        def open_spider(self,spider):#方法只会在爬虫开始时执行一次
            print('i am open_spider()')
            self.fp = open('./qiubai.txt','w',encoding='utf-8')
        #用来接收item对象,该方法调用的次数取决于爬虫文件像管道提交item的次数
        #参数:
            #- item:就是接收到的item对象
            #- spider:爬虫类实例化的对象
        def process_item(self, item, spider):
            author = item['author']
            content = item['content']
            self.fp.write(author+':'+content)
    
            return item
        def close_spider(self,spider):#在爬虫结束时被执行一次
            print('i am close_spider()')
            self.fp.close()
    settings.py

    在settings.py中解除该代码得注释

    ITEM_PIPELINES = {
      #300:表示管道的优先级,数值越小优先级越高,优先级越高表示该管道越先被执行
        'qiubaiPro.pipelines.QiubaiproPipeline': 300, 
        'qiubaiPro.pipelines.MysqlPipeline': 301,
        'qiubaiPro.pipelines.redisPipeLine': 302,
    }

    管道细节处理

    在配置文件中,管道对应的数值表示的是优先级
    什么情况下需要使用多个管道类?
      - 数据备份。一个管道类表示将数据存储到一种形式的载体中。
      想要将数据存储到mysql一份,redis一份,需要有两个管道类来实现。
    思考:
      - 爬虫文件向管道提交的item只会提交给优先级最高的那一个管道类
      - proces_item方法中的return item的作用
        - 将item对象提交给下一个即将被执行的管道类

    from itemadapter import ItemAdapter
    
    
    class QiubaiproPipeline:
        fp = None
    
        def open_spider(self, spider):
            print('打开文件')
            self.fp = open('./qiubai.txt', 'w', encoding='utf-8')
    
        def process_item(self, item, spider):
            author = item['author']
            content = item['content']
            self.fp.write(author + ':' + content)
            return item
    
        def close_spider(self, spider):
            print('关闭文件')
            self.fp.close()
    
    
    import pymysql
    
    #封装一个管道类,将数据存储到mysql中
    class MysqlPipeline:
        conn = None
        cursor = None
    
        def open_spider(self, spider):
            self.conn = pymysql.Connect(
                host='127.0.0.1',
                port=3306,
                user='root',
                password='123',
                charset='utf8',
                db='spider',
            )
    
        def process_item(self, item, spider):
            author = item['author']
            content = item['content']
            self.cursor = self.conn.cursor()
            sql = 'insert into qiubai values("%s","%s")' % (author, content)
    
            try:
                self.cursor.execute(sql)
                self.conn.commit()
            except Exception as e:
                print(e)
                self.conn.rollback()
    
        def close_spider(self, spider):
            self.cursor.close()
            self.conn.close()
    
    
    import redis
    
    
    class redisPipeline:
        conn = None
    
        def open_spider(self, spider):
            self.conn = redis.Redis(host='127.0.0.1', port=6379)
    
        def process_item(self, item, spider):
            self.conn.lpush('qiubaiData', item)

    redis数据库的使用

     redis是一个非关系型数据库

    下载安装

      中文官网:http://www.redis.cn/

    启动  

      1.启动redis的服务器端

        - redis-server
      2.启动redis的客户端
        - redis-cli

    具体使用

      查看所有数据:keys *
      删除所有数据:flushall
      set集合:
        - 插入数据: sadd 集合的名称 存储的值
        - 查看数据:smembers 集合的名称
        - set集合自动去重
      list列表
        - 插入数据:lpush 列表的名称 插入的值
        - 查看数据:lrange 列表名称 0 -1
        - 查看长度:llen 列表名称
        - 可以存储重复的数据

    python中使用需要导包

       pip install -U redis==2.10.6

      必须下载2.10.6,其他版本不能往里边存字典

    import redis
    
    
    class redisPipeline:
        conn = None
    
        def open_spider(self, spider):
            self.conn = redis.Redis(host='127.0.0.1', port=6379)
    
        def process_item(self, item, spider):
            self.conn.lpush('qiubaiData', item)

    全站数据爬取

    将所有页码对应的数据进行爬取+存储
    - 手动请求发送:
      - 通过代码的形式进行请求发送get请求
        - yield scrapy.Request(url,callback):
          - 可以对指定url发起get请求,回调callback进行数据解析
      - 手动发起post请求:
        - yield scrapy.FormRequest(url, formdata, callback)
    - 问题:start_urls列表中的url是如何发起post请求?
      重写父类如下方法即可:
      def start_requests(self):
        for url in self.start_urls:
          yield scrapy.FormRequest(url=url, formdata,callback=self.parse)

    duanzi.py

    import scrapy
    from duanziPro.items import DuanziproItem
    
    
    class DuanziSpider(scrapy.Spider):
        name = 'duanzi'
        # allowed_domains = ['www.xxx.com']
        start_urls = ['https://duanziwang.com/category/一句话段子/1/']
        url_model = 'https://duanziwang.com/category/一句话段子/%d/'
        page = 2
    
        def start_requests(self):
            for url in self.start_urls:
                yield scrapy.Request(url=url, callback=self.parse11)
    
        def parse11(self, response):
            article_list = response.xpath('/html/body/section/div/div/main/article')
            for article in article_list:
                title = article.xpath('./div[1]/h1/a/text()').extract_first()
                content = article.xpath('./div[2]/p/text()').extract_first()
    
                item = DuanziproItem()
                item['title'] = title
                item['content'] = content
                yield item
            if self.page < 3:
                new_url = format(self.url_model %self.page)
                self.page += 1
                yield scrapy.Request(url=new_url, callback=self.parse11)

    pipelines.py

    from itemadapter import ItemAdapter
    
    
    class DuanziproPipeline:
        fp = None
    
        def open_spider(self, spider):
            print(spider.name)     # duanzi
            self.fp = open('./duanzi.txt', 'w', encoding='utf-8')
    
        def process_item(self, item, spider):
            self.fp.write(item['title'] + ':' + item['content']+'
    ')
            return item
    
        def close_spider(self, spider):
            self.fp.close()
  • 相关阅读:
    不同编程语言中获取现在的Unix时间戳
    Zend Studio8.0.0中文汉化教程及入门教程
    Apache+php+mysql在windows下的安装与配置图解
    SQl 跨服务器查询语句和跨数据创建表
    .NET平台依赖注入机制及IoC的设计与实现
    整理基础的CentOS常用命令
    jQuery boxy弹出层插件中文演示及讲解
    VB 冒泡排序
    Windows7下使用IIS7与FastCGI模块配置PHP5.3.1运行环境
    Eclipse快捷键大全(转载)
  • 原文地址:https://www.cnblogs.com/wgwg/p/13267360.html
Copyright © 2011-2022 走看看