zoukankan      html  css  js  c++  java
  • 爬虫---10.scrapy框架(壹-初接触)

    • 所谓框架就是一个被集成了很多功能且具有很强通用性的项目模板

    • 学习框架就是学习集成好的各种功能的特性和作用 进阶探索框架的底层

    • scrapy是一个专门用于异步爬虫的框架。

      • 高性能的数据分析、请求发送、持久化存储、全站数据爬取、中间件,分布式...
    • 环境安装

      • mac和linux pip install scrapy
      • window分5个步骤
        • 1.pip3 install wheel
        • 2.下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#teisted
          1,2步是为第3步服务的 twisted就是一个异步的架构
        • 3.安装twisted
          进入下载目录 执行 pip install Twisted-20.3.0-cp38-cp38m-win_amd64.whl
          twisted是异步架构 被作用在scrapy中
          如果安装报错 需要更换另一版本安装即可
        • 4.pip install pywin32
        • 5.pip install scrapy
        • 6.测试 在cmd中scrapy,如果没报错,安装成功
    • scrapy的基本使用

      • 创建一个工程

        • Console 是python控制台 Terminal是终端 命令行模式
        • 执行 scrapy startproject ProName(项目名,在选定的目录下创建)
        • 目录结构
          • spiders 文件夹叫爬虫目录 必须存放一个爬虫源文件
          • settings.py 工程的配置文件
        • cd 到ProName目录 创建一个爬虫源文件
          • scrapy genspider spiderName www.xxx.com(生成一个spiderName.py文件,源文件创造好了)
        • 编写对应的代码在爬虫文件中(后继操作,暂时不用)
      • 执行工程

        • scrapy crawl spiderName 是创建的py文件
          • 执行工程后 默认会输出工程所有的日志信息
        • 指定类型日志的输出:
          • 1.settings.py中加入 LOG_LEVEL = 'ERROR' 打印日志会消失
          • 2.在settings.py中 ROBOTSTXT_OBEY=False 要改成True 不改的话,目前测试https能返回正常response http不能返回
          • 3.可以把User-Agent写在配置文件中
          • 最后 重新执行scrapy crawl spiderName 要在ProName路径下执行
        • 碰到了连接超时问题 暂时没解决
          • windows下 其实是自己创建的网址无法访问报错 拓展知识
            • netstat -ano|findstr 端口号 (查看在用端口) 随后 taskkill /pid PID(进程号) /f 杀掉端口
      • 爬虫文件内容阐述

        • name 爬虫文件名称 该文件的唯一标识
        • start_urls 起始url列表 存储的都是url url可以被自动进行get请求的发送
        • parse方法 请求后的数据解析操作
      • 文件说明

        • scrapy.cfg 项目的配置信息,主要为Scrapy命令行工具提供一个基础的配置信息。(真正爬虫相关的配置信息在settings.py文件中)
        • items.py 设置数据存储模板,用于结构化数据,如:Django的Model
        • pipelines 数据处理行为,如:一般结构化的数据持久化
        • settings.py 配置文件,如:递归的层数、并发数,延迟下载等
          = spiders 爬虫目录,如:创建文件,编写爬虫规则
      • settings.py 需要做的操作

        • 1.禁止robots ROBOTSTXT_OBEY = False
        • 2.指定日志类型 LOG_LEVEL = 'ERROR'
        • 3.UA伪装 USER_AGENT = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE'
      • 数据解析

        • 用scrapy自己的xpath做解析 代码写完后 在终端执行scrapy crawl spidername
        • 得到的结果是selector对象 需要的字符串对象被存储在data属性中
        • 取出方式 变量名2 = 变量名1.xpath()[0].extract() extract就是将属性值取出
        • 正式书写是 xpath().extract_first() 意思是将列表中第一个元素表示的selector对象中的data值取出
        • 直接使用列表调用extract() 可以将列表中每个列表元素表示的selector中的data取出 结果为列表
      • 持久化存储

        • 基于终端指令:

          • 局限:该种方式只可以将parse方法的返回值存储到本地指定后缀的文本文件中
          • 命令:scrapy crawl spiderName -o ./qiubai.csv
          • 注意:持久化存储对应的文本文件类型只能为:json jsonlines jl csv xml marshal pickle
          • 优点:简洁便捷高效
          简单代码 点击查看
             class FirstSpider(scrapy.Spider):
             # 爬虫文件名称: 当前源文件的唯一标识
             name = 'duanzi'
          
             # 允许的域名 这里是做域名限定的 所以通常会把allowed_domains注释掉
             # allowed_domains = ['www.baidu.com']
          
             # 起始的url列表 只可以存储url
             # 作用:列表中存储的url都会被进行get请求的发送
             start_urls = ['https://duanzixing.com/微段子/']
          
             # 数据解析 parse方法调用的次数完全取决于请求的次数 response表示的就是服务器返回的响应对象
          
             # 将解析到的数据做持久化存储
          
             def parse(self, response):
                 article_list = response.xpath('/html/body/section/div/div/article')
                 all_data = []
                 for article in article_list:
                 # title = article.xpath('.//h2/a/text()')[0].extract()
                 title = article.xpath('.//h2/a/text()').extract_first()
          
             dic = {
                'title': title,
             }
             all_data.append(dic)
          
             return all_data
          
             # 终端执行 scrapy crawl duanzi -o duanzi.csv
          
        • 基于管道(重点)(步骤):

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

          • 2.在item.py中定义相关的属性

            • 步骤1中解析出了几个字段的数据 在此就定义几个属性
              Filed()定义好的属性当做是一个万能类型的属性
              name=scrapy.Field()
          • 3.在爬虫文件中将解析的数据封装存储到item类型的对象中

            • 在代码文件中 既scrapy genspider spiderName www.xxx.com创建的文件中
              from 文件夹名称.items import items文件中的类名

            • 随后实例化一个item类型的对象 将解析到的数据存储到该对象中
              在类方法中 item = items中的类名()
              注意 item调用属性不能用. 只能用item[''] = 获取到的数据
              如 item['title'] = title

              操作实例 点击查看
                def parse(self, response):
                    all_data = []
                    # 数据解析名称和内容 
                    article_lst = response.xpath('')
                    for article in article_lst:
                        title = article.xpath().extract_first()
                        # 实例化一个item类型的对象 将解析到的数据存储到该对象中
                        item = duanziproItem()
                        # 不可以通过.的形式调用属性
                        item['title'] = title
              
              
          • 4.将item类型的对象提交给管道进行持久化存储的操作
            在sprid文件的parse方法中 最后录入 yield item 是将item对象提交给管道

          • 5.在管道文件(pipelines.py)中, 接收爬虫文件提交过来的Item类型对象,且对其进行任意形式的持久化存储操作
            工程里只能有一个管道文件, 但是可以有多个管道类

            简单代码 点击查看
                # 文件中有管道类 管道类的的方法是用来接受item对象的 
                # 一次只能接收一个item 说明该方法会被调用多次
                # 参数item就是接受到的tiem对象
            
                # 如果有多个爬虫文件 不能执行一个就打开一次文件 所以要重写父类的2个方法 让文件只打开一次 写入多次
                def open_spider(self, spider):
                    print('我是open_spider(), 我只会在爬虫开始的时候执行一次')
                    self.fp = open('xx.txt', 'w', encoding='utf-8')
                                          
                    # 文件需要关闭 所以需要重写父类的另一个方法
                    def close_spider(self, spider):
                        print("我是close_spider(), 我只会在爬虫结束的时候执行一次!")
                        self.fp.close()
            
                    def process_item(self, item, spider):
                        print(item)          # item其实就是一个字典
                        self.fp.write(item['title']+'
            ')
                        # 将item存储到文件
                        return item
            
          • 6.在配置文件中开启管道机制
            在配置文件中有 ITEM_PIPELINES = {'XXX.pipelines.xxxPipeline': 300,}
            300表示优先级,数字越小 优先级越高

        • 基于管道实现数据的备份

          • 将爬取到的数据分别存储到不同的载体
          • 实现:将数据一份存储到mysql 一份存储到redis
          • 问题:管道文件中的一个管道类表示怎样一组操作?
            • 一个管道类对应一种形式的持久化存储操作 如果将数据存储到不同的载体中就需要使用多个管道类。
          • 定义好了三个管道类 将数据写入到三个载体中进行存储
            • item不会依次提交给三个管道类

            • 爬虫文件中的item只会被提交给优先级最高的那一个管道类

            • 优先级高的管道类需要在process_item中实现return item就传递给下一个即将执行的管道

            • 如果redis报错 需要将redis模块指定为2.10.6即可 pip install -U redis==2.10.6

              简单实例 写入mysql 点击查看
                 import mysql
                 # 将数据存储到mysql中 在pipelines管道文件中写一个类
                 class MysqlPileLine(object):
                     conn = None 
                     # 链接对象和文件句柄一样 只能创建一次                     
                     def open_spider(self, spider):
                         self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='567913', db='lj')
                         print(conn)
                     def process_item(self, item, spider):
                         self.cursor = self.conn.cursor()
                         sql = 'insert into duanziwang values (%s, %s)'
                         try:
                             self.cur.execute(sql, [item['title'], item['content']])
                             self.conn.commit()
                         except Exception as e:
                             print(e)
                             self.conn.rollback()
                     def close_spider(self, spider):
                         self.cursor.close()
                         self.conn.close()
                          
              
              简单实例 写入redis 点击查看
                 from redis import Redis
                 
                 class RedisPileLine(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):
                         sql.conn.lpush('duanziData', item)
              
              
    • scrapy手动请求发送实现的全站数据爬取

      • yield srapy.Request(url, callback) # 这个是GET请求
        • callback指定解析函数 用于解析数据
      • yield scrapy.FormRequest(url, callback, formdata) # 这个是POST请求
        • formdata字典 请求参数
    • 为什么start_urls列表中的url会被自动进行get请求的发送?

      • 因为列表中的url其实是被start_requests这个父类方法实现的get请求发送


        点击查看代码

          ```
              #父类方法:这个是该方法的原始实现
              def start_requests(self):
                  for u in self.start_urls:
                      yield scrapy.Request(url=u, callback=self.parse)
          ```
          </details>
        
    • 如何将start_urls中的url默认改成post请求发送?

      • 重写start_requests方法即可


        点击查看代码

        ```
            def start_requests(self):
                for u in self.start_urls:
                    yield scrapy.FormRequst(url=u, callback=self.parse)
        
        ```
        </details>
  • 相关阅读:
    Android TextView中实现点击文本超链接(无下划线)的封装类
    first day for new job
    配置Log4j(非常具体)
    验证数字的正则表达式集
    虚拟化知识点
    Java实现第十届蓝桥杯数的分解
    Java实现第十届蓝桥杯数的分解
    Java实现第十届蓝桥杯数的分解
    Java实现第十届蓝桥杯数列求值
    Java实现第十届蓝桥杯数列求值
  • 原文地址:https://www.cnblogs.com/FGdeHB/p/15496834.html
Copyright © 2011-2022 走看看