zoukankan      html  css  js  c++  java
  • scrapy框架简单学习

    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 ProName(项目工程名称)
      • cd ProName
      • 创建一个爬虫文件:scrapy genspider spiderName www.xxx.com(指定的url,必须要先CD到项目中,保证爬虫文件在spiders目录中)
      • 执行工程:scrapy crawl spiderName
      • setting中添加UA伪装,并选择不遵从爬虫Robots协议
    #UA伪装
    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
    #不遵从爬虫Robots协议
    ROBOTSTXT_OBEY = False
    #只输出错误信息日志
    LOG_LEVEL = 'ERROR'
    
    • scrapy的数据解析

      • 在scrapy中使用xpath解析标签中的文本内容的话,最终获取的是一个Selector的对象,且我们需要的字符串数据全部被封装在了该对象中
      • 如果可以确定xpath返回的列表只有一个列表元素则使用extract_first(),否则使用extract()
    • scrapy的持久化存储

      • 基于终端指令:
        • 可以将parse方法的返回值对应的数据进行本地磁盘文件的持久化存储
        • scrapy crawl qiubai -o filePath
        • 优点:便捷
        • 缺点:局限性较强(数据不可以存储到数据库,数据存储文件的后缀有要求)
      • 基于终端指令的持久化存储代码示例
      #基于终端指令的持久化存储代码示例,直接写在你的项目文件中即可,
      #运行指令scrapy crawl qiubai -o filePath
      # -*- coding: utf-8 -*-
      import scrapy
      # from qiubaiPor.items import QiubaiporItem
      
      class QiubaiSpider(scrapy.Spider):
          name = 'qiubai'
          # allowed_domains = ['www.xxx.com']
          # 存放在该列表中的url都会被scrapy自动的进行请求发送
          start_urls = ['https://www.qiushibaike.com/text/']
      	#基于终端指令的持久化存储:可以将parse方法的返回值对应的数据进行本地磁盘文件的持久化存储
          def parse(self, response):
              all_data = []
              # 数据解析:作者and段子内容
              div_list = response.xpath('//div[@id="content-left"]/div')
              for div in div_list:
                  # 在scrapy中使用xpath解析标签中的文本内容的话,最终获取的是一个Selector的对象,且我们需要的字符串数据全部被封装在了该对象中
                  #如果可以确定xpath返回的列表只有一个列表元素则使用extract_first(),否则使用extract()
                  author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
                  content = div.xpath('./a/div/span/text()').extract()
      
                  dic = {"author":author,"content":content}
                  all_data.append(dic)
              return all_data
      
      
      • 基于管道:
        • 编码流程:
          • 1.数据解析
            • 2.在item类中进行相关属性的封装
              • 3.实例化一个item类型的对象
              • 4.将解析的数据存储封装到item类型的对象中
              • 5.将item提交给管道
              • 6.在配置文件中开启管道
      • 基于sarapy模块进行的数据爬取存储示例(qiubai项目运行文件内容)
      #基于sarapy模块进行的数据爬取存储
      # -*- coding: utf-8 -*-
      import scrapy
      from qiubaiPro.items import QiubaiproItem
      class QiubaiSpider(scrapy.Spider):
          name = 'qiubai'
          # allowed_domains = ['www.xxx.com']
          #存放在该列表中的url都会被scrapy自动的进行请求发送
          start_urls = ['https://www.qiushibaike.com/text/']
      
          #基于终端指令的持久化存储:可以将parse方法的返回值对应的数据进行本地磁盘文件的持久化存储
          # def parse(self, response):
          #     all_data = []
          #     #数据解析:作者and段子内容
          #     div_list = response.xpath('//div[@id="content-left"]/div')
          #     for div in div_list:
          #         #在scrapy中使用xpath解析标签中的文本内容的话,最终获取的是一个Selector的对象,且我们需要的字符串数据全部被封装在了该对象中
          #         #如果可以确定xpath返回的列表只有一个列表元素则使用extract_first(),否则使用extract()
          #         author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
          #         content = div.xpath('./a/div/span/text()').extract()
          #
          #         dic = {
          #             'author':author,
          #             'content':content
          #         }
          #         all_data.append(dic)
          #         # print(author,content)
          #     return all_data
      
      
          #基于管道实现持久化存储
          def parse(self, response):
              all_data = []
              #数据解析:作者and段子内容
              div_list = response.xpath('//div[@id="content-left"]/div')
              for div in div_list:
                  #在scrapy中使用xpath解析标签中的文本内容的话,最终获取的是一个Selector的对象,且我们需要的字符串数据全部被封装在了该对象中
                  #如果可以确定xpath返回的列表只有一个列表元素则使用extract_first(),否则使用extract()
                  author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
                  if not author:
                      author = '匿名用户'
                  content = div.xpath('./a/div/span/text()').extract()
                  content = ''.join(content)
      
                  #创建一个item类型的对象(只可以存储一组解析的数据)
                  item = QiubaiproItem()
                  #将解析到的数据存储到item对象中
                  item['author'] = author
                  item['content'] = content
      
                  #将item提交给管道类
                  yield item
      
      • pipelines.py中的内容,主要用于存储
      # -*- coding: utf-8 -*-
      
      # Define your item pipelines here
      #
      # Don't forget to add your pipeline to the ITEM_PIPELINES setting
      # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
      import pymysql
      from redis import Redis
      #一个管道类对应一种平台的数据存储
      class QiubaiproPipeline(object):
          fp = None
          #重写父类的方法:只在开始爬虫的时候被执行一次
          def open_spider(self,spider):
              print('开始爬虫......')
              self.fp = open('./qiubai.txt','w',encoding='utf-8')
      
          #处理item类型的对象
          #什么是处理?
              #将封装在item对象中的数据值提取出来且进行持久化存储
          #参数item表示的就是爬虫文件提交过来的item对象
          #该方法每接收一个item就会被调用一次
          def process_item(self, item, spider):
              print('this is process_item()')
              author = item['author']
              content = item['content']
      
              self.fp.write(author+':'+content+"
      ")
              #返回的item就会传递给下一个即将被执行的管道类
              return item
          def close_spider(self,spider):
              print('结束爬虫!')
              self.fp.close()
      
      #将数据同时存储到mysql
      class mysqlPileLine(object):
          conn = None
          cursor = None
          def open_spider(self,spider):
              self.conn = pymysql.Connect(host='127.0.0.1',port=3306,db='spider',user='root',password='',charset='utf8')
              print(self.conn)
          def process_item(self,item,spider):
              sql = 'insert into qiubai values ("%s","%s")'%(item['author'],item['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 redisPileLine(object):
          conn = None
          def open_spider(self,spider):
              self.conn = Redis(host='127.0.0.1',port=6379)
          def process_item(self,item,spider):
              dic = {
                  'author':item['author'],
                  'content':item['content']
              }
              self.conn.lpush('qiubaiData',dic)
      
      
      • 不要忘记对items.py文件中字段的设置
      # -*- coding: utf-8 -*-
      
      # Define here the models for your scraped items
      #
      # See documentation in:
      # https://doc.scrapy.org/en/latest/topics/items.html
      
      import scrapy
      
      
      class QiubaiporItem(scrapy.Item):
          # define the fields for your item here like:
          # name = scrapy.Field()
          author = scrapy.Field()
          content = scrapy.Field()
      
      
      • 最后将settings.py文件进行配置
      ITEM_PIPELINES = {
         'qiubaiPro.pipelines.QiubaiproPipeline': 300,
          # 'qiubaiPro.pipelines.mysqlPileLine': 301,
          'qiubaiPro.pipelines.redisPileLine': 302,
          #300表示的是优先级,数值越小优先级越高
      }
      
      • 注意事项:
        • 爬虫文件提交的item只会传递给第一个被执行的管道类
        • 在管道类的process_item方法中的return item,是将item传递给下一个即将被执行的管道类
        • 什么时候需要定制多个管道类?
          • 将数据同时存储到多个平台的时候
        • 习惯:每一个process_item中都需要编写return item
    • 进行全站数据的爬取
      - 手动请求的发送(get请求)
      - yield scrapy.Request(url,callback)
      - callback:用于数据解析

      • 发送post请求:
        • 手动进行post请求的发送:
          • yield scrapy.FromRequest(url,callback,formdata)
            • formdata请求参数 ==>requests.post(data)
        • 想要将起始url列表中存储的起始url进行post请求的发送
          • 重写父类的该方法:def start_requests(self):
      def start_requests(self):
      	for url in self.start_urls:
      		data = {}
      		yield scrapy.FormRequest(url,callback=self.parse,formdata=data)
      
      • 基于scrapy的全栈数据爬取(qiubai.py运行文件内容)
      # -*- coding: utf-8 -*-
      import scrapy
      #爬取多页
      from qiubaiByPages.items import QiubaibypagesItem
      class QiubaiSpider(scrapy.Spider):
          name = 'qiubai'
          # allowed_domains = ['www.xxx.com']
          start_urls = ['https://www.qiushibaike.com/text/']
      
      
          #定制一个通用的url模板
          url = 'https://www.qiushibaike.com/text/page/%d/'
          pageNum = 1
      
          def parse(self, response):
              print('正在爬取{}页......'.format(self.pageNum))
              all_data = []
              # 数据解析:作者and段子内容
              div_list = response.xpath('//div[@id="content-left"]/div')
              for div in div_list:
                  # 在scrapy中使用xpath解析标签中的文本内容的话,最终获取的是一个Selector的对象,且我们需要的字符串数据全部被封装在了该对象中
                  # 如果可以确定xpath返回的列表只有一个列表元素则使用extract_first(),否则使用extract()
                  author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
                  if not author:
                      author = '匿名用户'
                  content = div.xpath('./a/div/span/text()').extract()
                  content = ''.join(content)
      
                  # 创建一个item类型的对象(只可以存储一组解析的数据)
                  item = QiubaibypagesItem()
                  # 将解析到的数据存储到item对象中
                  item['author'] = author
                  item['content'] = content
      
                  # 将item提交给管道类
                  yield item
              #递归解析+手动请求发送 ==> 全站数据爬取
              if self.pageNum <= 13:
                  self.pageNum += 1
                  new_url = format(self.url%self.pageNum)
                  yield scrapy.Request(url=new_url,callback=self.parse)
      
      
      • piplines.py文件内容
      class QiubaibypagesPipeline(object):
          fp = None
      
          # 重写父类的方法:只在开始爬虫的时候被执行一次
          def open_spider(self, spider):
              print('开始爬虫......')
              self.fp = open('./qiubai.txt', 'w', encoding='utf-8')
      
          # 处理item类型的对象
          # 什么是处理?
          # 将封装在item对象中的数据值提取出来且进行持久化存储
          # 参数item表示的就是爬虫文件提交过来的item对象
          # 该方法每接收一个item就会被调用一次
          def process_item(self, item, spider):
              # print('this is process_item()')
              author = item['author']
              content = item['content']
      
              self.fp.write(author + ':' + content + "
      ")
              # 返回的item就会传递给下一个即将被执行的管道类
              return item
      
          def close_spider(self, spider):
              print('结束爬虫!')
              self.fp.close()
      
      • 最后不要忘记settings跟items文件的配置

      • 爬取http://www.521609.com/meinvxiaohua/ 图片数据

        #运行文件内容
        import scrapy
        from xiaohuaPro.items import XiaohuaproItem
        
        class XiaohuaSpider(scrapy.Spider):
            name = 'xiaohua'
            # allowed_domains = ['www.xxx.com']
            start_urls = ['http://www.521609.com/meinvxiaohua/']
            url = 'http://www.521609.com/meinvxiaohua/list12%d.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:
                    #创建一个对象
                    item = XiaohuaproItem()
                    img_src = 'http://www.521609.com'+li.xpath('./a[1]/img/@src').extract_first()
                    title = li.xpath('./a[1]/img/@alt').extract_first()
                    item['title'] = title
                    item['img_src'] = img_src
                    yield item
                if self.page_num <21:
                    self.page_num += 1
                    new_url = format(self.url%self.page_num)
                    #使用yield方式进行反复的递归回调,来获取新的内容
                    yield scrapy.Request(new_url,self.parse)
        
        
      • items中定义字段

        import scrapy
        
        
        class XiaohuaproItem(scrapy.Item):
            # define the fields for your item here like:
            title = scrapy.Field()
            img_src = scrapy.Field()
            pass
        
        
      • pipelines中接收并进行存储

        from scrapy.pipelines.images import ImagesPipeline
        import scrapy
        
        class XiaohuaproPipeline(object):
            def process_item(self, item, spider):
                print(item)
                return item
        
        #使用scrapy专门封装好的一个管道类(ImagesPipeline)文件数据下载和持久化存储
        class imgPileLine(ImagesPipeline):
            #进行文件请求
            def get_media_requests(self, item, info):
                yield scrapy.Request(item['img_src'])
        
            #指定文件最终持久化存储对应的文件名称
            def file_path(self, request, response=None, info=None):
                img_src = request.url
                img_name = img_src.split('/')[-1]
                return img_name
        
            def item_completed(self, results, item, info):
                print(results)
                return item  #可以将item传递给下一个即将被执行的管道类
        
      • 在这些代码操作之前不要忘了对你的工程项目进行settings的配置

        #UA伪装
        USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
        #不遵从爬虫Robots协议
        ROBOTSTXT_OBEY = False
        #只显示报错信息
        LOG_LEVEL = 'ERROR'
        #管道优先级
        TEM_PIPELINES = {
            'xiaohuaPro.pipelines.XiaohuaproPipeline': 301,
            'xiaohuaPro.pipelines.imgPileLine': 300,
        }
        #设置文件夹存储路径
        IMAGES_STORE = './xiaohuas'
        
    • scrapy的五大核心组件

      • 引擎(Scrapy)

        • 用来处理整个系统的数据流处理, 触发事务(框架核心)
      • 调度器(Scheduler)

        • 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求 的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
      • 下载器(Downloader)

        • 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
      • 爬虫(Spiders)

        • 爬虫是主要干活的, 用于从特定的网页中提取自己 需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
      • 项目管道(Pipeline)

        • 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验 证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

    • 请求传参:

      • 使用场景:
        • 爬取的数据没有存在于同一张页面中
      • 请求传参传递的是item
      • 实现:在进行手动请求发送的时候,可以将一个字典(meta)传递给回调函数
        • yield scrapy.Request(url,callback,meta)
        • callback取meta字典:
          • response.meta
    • 基于scrapy框架的对电影及详情页内容的爬取案例

      • 执行文件movie.py
      import scrapy
      
      from moviePro.items import MovieproItem
      class MovieSpider(scrapy.Spider):
          name = 'movie'
          # allowed_domains = ['www.xxx.com']
          start_urls = ['https://www.4567tv.tv/index.php/vod/show/id/5.html']
      
          #封装一个通用的url模板
          url = 'https://www.4567tv.tv/index.php/vod/show/id/5/page/%d.html'
          page_num = 1
      
          def parse(self, response):
              print('正在爬取第{}页......'.format(self.page_num))
      
              li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
              for li in li_list:
                  title = li.xpath('./div/a/@title').extract_first()
                  detail_url = 'https://www.4567tv.tv'+li.xpath('./div/a/@href').extract_first()
      
                  item = MovieproItem()
                  item['title'] = title
      
                  #对详情页发起get请求
                  #meta是一個字典,将meta传递给回调函数
                  yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})
              if self.page_num <= 33:
                  self.page_num += 1
                  new_url = format(self.url%self.page_num)
      
                  yield scrapy.Request(new_url,callback=self.parse)
      
          #用来解析详情页中的电影简介
          def parse_detail(self,response):
              #提取meta
              item = response.meta['item']
              desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
      
              item['desc'] = desc
      
              yield item
      
      • items.py文件内容
      import scrapy
      
      class MovieproItem(scrapy.Item):
          # define the fields for your item here like:
          #电影名称
          title = scrapy.Field()
          #电影详情介绍
          desc = scrapy.Field()
      
      • pipelines.py文件内容
      class MovieproPipeline(object):
          def process_item(self, item, spider):
              print(item)
              return item
      
  • 相关阅读:
    Bootstrap(项目2)
    Bootstrap(项目1)
    Bootstrap(Carousel幻灯片)轮播图
    Bootstrap(滚动监听)
    Bootstrap基础10(标签页)
    Bootstrap基础9(工具提示框、警告框、弹出框)
    Bootstrap基础8(模态框(弹窗))
    Bootstrap基础7(标签、徽章、大屏展播、页面标题、缩略图、进度条、面板、折叠效果)
    Bootstrap基础6(路径导航)
    2018~2019学年下学期《计算机图像处理》
  • 原文地址:https://www.cnblogs.com/Godisgirl/p/11048059.html
Copyright © 2011-2022 走看看