爬虫学习笔记(第八章)Scrapy框架[上]

13 篇文章 4 订阅

第八章章节

爬虫学习笔记(第八章)Scrapy框架[上]
爬虫学习笔记(第八章)Scrapy框架[下]


前言

2021.8.30完成第八章的学习


第八章

scrapy框架

1.基础了解

  • 什么是框架?
    • 就是一个集成了很多功能并且具有很强通用性的一个项目模板。
  • 如何学习框架?
    • 专门学习框架封装的各种功能的详细用法。
  • 什么是scrapy?
    • 爬虫中封装好的一个明星框架。
    • 功能:
      • 高性能的持久化存储
      • 异步数据的下载
      • 高性能的数据解析
      • 分布式
  • scrapy框架的基本使用
    • 环境的安装:
      • mac or Linux: pip install scrapy
      • windows:
        • pip install wheel
        • 下载twisted:下载地址http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
        • 安装twisted:Twisted-21.7.0-py3-none-any.whl
        • pip install pywin32
        • pip install scarpy
          [PS:pywin32的主要作用:
          • 捕获窗口
          • 模拟鼠标键盘动作
          • 自动获取某路径下文件列表
          • PIL截屏功能]
        • 测试:在终端里录入scrapy指令,没有报错即表示安装成功
    • 基本使用:
      • 1.创建一个工程:scrapy startproject xxxPro(在pycharm中下方的terminal中输入)
      • 2.cd xxxPro
      • 3.在spiders子目录中创建一个爬虫文件
        • scrapy genspider spiderName www.xxx.com
      • 需要暂时修改的信息:
        settings.py中修改并添加如下代码
        1.ROBOTSTXT_OBEY的值由True改为False(robots协议,详见第一章)
        2.添加指定代码,使相应数据中不输出正常的日志刷屏
# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# 显示指定类型的日志信息
LOG_LEVEL = 'ERROR'

spiders子目录中创建的爬虫文件分析:

import scrapy


class FirstSpider(scrapy.Spider):
    # 爬虫文件的名称:爬虫源文件的唯一标识
    name = 'first'
    
    # 允许的域名:用来限定start_urls列表中哪些url可以进行请求发送
    # allowed_domains = ['www.baidu.com']       # 通常不用(例如爬取图片时图片的url就不会被访问到)
    
    # 起始的url列表:该列表中存放的url会被scrapy自动进行的请求发送
    start_urls = ['http://www.baidu.com/', 'https://www.sogou.com']

    # 用作于数据解析:response参数表示的是请求成功后对应的响应对象
    def parse(self, response):
        print(response)
        # pass

2.scrapy数据解析

  • scrapy数据解析:

  • 需求:使用scrapy爬取糗事百科的段子

代码如下:

import scrapy


class QiubaiSpider(scrapy.Spider):
    name = 'qiubai'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://www.qiushibaike.com/text/']

    def parse(self, response):
        # 解析:作者的名称&段子的内容
        div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
        # print(div_list)
        for div in div_list:
            # 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之后,则表示将列表中每一个selector对象中data对应的字符串提取了出来
            content = div.xpath('./a[1]/div/span//text()').extract()
            content = ''.join(content)
            print(author, content)
            break

3.scrapy持久化存储

Ⅰ知识点
  • scrapy持久化存储
    • 基于终端指令:
      • 要求:只可以将parse方法的返回值存储到本地的文本文件中
      • 注意:持久化存储对应的文本文件的类型只可以为:‘json’, ‘jsonlines’, ‘jl’, ‘csv’, ‘xml’, ‘marshal’, ‘pickle’(没有’txt’)
      • 指令:scrapy crawl xxx -o filePath
      • 好处:简洁高效便捷
      • 缺点:局限性比较强(数据只可以存储到指定后缀的文本文件中)
    • 基于管道:
      • 编码流程:
        • 1.数据解析
        • 2.在item类中定义相关的属性
        • 3.将解析的数据存储到item类型的对象
        • 4.将item类型的对象提交给管道进行持久化存储的操作
        • 5.在管道类的process_item中要将其接收到的item对象中存储的数据进行持久化存储操作
        • 6.在配置文件中开启管道
      • 好处:
        • 通用性强
    • 面试题:将爬取的数据一份存储到本地一份存储到数据库,如何实现?
Ⅱ代码部分
①基于终端指令

代码如下:

import scrapy


class QiubaiSpider(scrapy.Spider):
    name = 'qiubai'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://www.qiushibaike.com/text/']

    def parse(self, response):
        # 解析:作者的名称&段子的内容
        div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
        all_data = []       # 存储所有解析到的数据
        # print(div_list)
        for div in div_list:
            # 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之后,则表示将列表中每一个selector对象中data对应的字符串提取了出来
            content = div.xpath('./a[1]/div/span//text()').extract()
            content = ''.join(content)

            dic = {
                'author': author,
                'content': content
            }

            all_data.append(dic)
            # print(author, content)
            # break
        return all_data
②基于管道

代码如下:

import scrapy
# from qiubaiPro.items import QiubaiproItem
from ..items import QiubaiproItem


class QiubaiSpider(scrapy.Spider):
    name = 'qiubai'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://www.qiushibaike.com/text/']


    # -----基于终端-----
    # def parse(self, response):
    #     # 解析:作者的名称&段子的内容
    #     div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
    #     all_data = []       # 存储所有解析到的数据
    #     # print(div_list)
    #     for div in div_list:
    #         # 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之后,则表示将列表中每一个selector对象中data对应的字符串提取了出来
    #         content = div.xpath('./a[1]/div/span//text()').extract()
    #         content = ''.join(content)
    #
    #         dic = {
    #             'author': author,
    #             'content': content
    #         }
    #
    #         all_data.append(dic)
    #         # print(author, content)
    #         # break
    #     return all_data

    # -----基于管道-----
    def parse(self, response):
        # 解析:作者的名称&段子的内容
        div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
        all_data = []       # 存储所有解析到的数据
        # print(div_list)
        for div in div_list:
            # xpath返回的是列表,但列表元素一定是selector类型的对象
            # extract可以将selector对象中data参数存储的字符串提取出来
            author = div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span/h2/text()')[0].extract()

            # 列表调用了extract之后,则表示将列表中每一个selector对象中data对应的字符串提取了出来
            content = div.xpath('./a[1]/div/span//text()').extract()
            content = ''.join(content)

            item = QiubaiproItem()
            item['author'] = author
            item['content'] = content

            # 将ite提交给了管道
            yield item
Ⅲ面试题(代码有报错,暂未解决)
  • 面试题:将爬取到的数据一份存储到本地一份存储到数据库,如何实现?
    • 管道文件中的一个管道类对应的是将数据存储到一种平台
    • 爬虫文件提交的item只会给管道文件中第一个被执行的管道类接受
    • process_item中的return item表示将item传递给下一个即将被执行的管道类

代码如下:

# pipelines.py


# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
import pymysql

class QiubaiproPipeline:
    fp = None
    # 重写父类的一个方法:该方法只在开始爬虫的时候被调用一次


    def open_spider(self, spider):
        print('开始爬虫...')
        self.fp = open('./qiubai.txt', 'w', encoding='utf-8')


    # 专门用来处理item类型对象
    # 该方法可以接收爬虫文件提交过来的item对象
    # 该方法每接收到一个item就会被调用一次


    def process_item(self, item, spider):
        author = item['author']
        content = item['content']

        self.fp.write(author + ':' + content + '\n')

        # 很重要的一行代码
        return item     # 传递给下一个即将被执行的管道类

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

# 管道文件中一个管道类对应将一组数据存储到一个平台或者载体中
class MysqlPipeline(object):
    conn = None
    cursor = None

    def open_spider(self, spider):
        self.conn = pymysql.Connect(host="localhost", user="root", passwd="123456", database="pydata", port=3306,
                                    charset='utf-8')

    def process_item(self, item, spider):
        self.cursor = self.conn.cursor()
        sql = """
                    create table qiubai(
                    num int primary key auto_increment,
                    author varchar(100) not null,
                    content varchar(9999) not null,
                    )
                """
        self.cursor.execute(sql)
        try:
            self.cursor.execute('insert into qiubai values("%s", "%s")' % (item["author"], item["content"]))
            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()

# 爬虫文件提交的item类型的对象最终会提交给哪一个管道类?
# 先执行管道类优先级高的

4.基于spider的全站数据爬取

  • 基于spider的全站数据爬取
    • 就是将网站中某板块下的全部页码对应的页面数据进行爬取和解析
    • 需求:爬取校花网中的照片的名称
    • 实现方式:
      • 1.将所有页面的url添加到start_urls列表(不推荐)
      • 2.自行手动请求发送(推荐)
        • 手动请求发送:
          • yield scrapy.Request(url, callback):callback专门用于数据解析

样例代码如下:

  • 创建工程:scrapy startproject xiaohuaPro
  • 创建文件:scrapy genspider xiaohua www.xxx.com
  • 修改设置:
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

LOG_LEVEL = 'ERROR'
  • 编写代码:
import scrapy


class XiaohuaSpider(scrapy.Spider):
    name = 'xiaohua'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://www.521609.com/meinvxiaohua/']

    # 生成一个通用的url模板(不可变)
    url = 'http://www.521609.com/meinvxiaohua/list12%d.html'
    page_num = 2

    def parse(self, response):
        li_list = response.xpath('/html/body/div[4]/div[2]/div[2]/ul/li')
        for li in li_list:
            img_name = li.xpath('./a[2]/b/text() | ./a[2]/text()').extract_first()
            print(img_name)

        if self.page_num <= 11:
            new_url = format(self.url % self.page_num)
            self.page_num += 1
            # 手动请求发送:callback回调函数是专门用于数据解析
            yield scrapy.Request(url=new_url, callback=self.parse)

5.五大核心组件

调度器过滤器会进行检查,避免重复请求;队列
下载器使用到twisted,基于异步
管道用于持久化存储
引擎进行数据流处理,触发事物
spider请添加图片描述

  • 引擎(Scrapy)

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

  • 调度器(Scheduler)

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

  • 下载器(Downloader)

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

  • 爬虫(Spiders)

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

  • 项目管道(Pipeline)

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

请添加图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竹清兰香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值