15--Scrapy01:介绍与初步使用

Scrapy01--基本介绍与初步使用

一、爬虫工程化

何为工程化,就是让你的程序更加的有体系,有逻辑,更加的模块化.

到目前为止,我们所编写的爬虫我们都是从头到尾的每一步都要亲力亲为. 这样做固然有其优点(可控性更好),但是各位请认真思考.
这样的代码逻辑是不能形成批量生产的效果的(写100个爬虫). 很多具有共通性的代码逻辑都没有进行重复利用.
那我们就可以考虑看看,能不能把一些共性的问题(获取页面源代码,数据存储),单独搞成一个功能.
如果我们把这些功能单独进行编写. 并且产生类似单独的功能模块,将大大的提高我们爬虫的效率. 已达到我们爬虫工程化开发的效果.

爬虫工程化: 对爬虫的功能进行模块化的开发. 并达到可以批量生产的效果(不论是开发还是数据产出)

二、Scrapy简介

Scrapy到目前为止依然是这个星球上最流行的爬虫框架. 摘一下官方给出对scrapy的介绍

An open source and collaborative framework for extracting the data you need from websites.

In a fast,simple,yet extensible way.

scrapy的特点: 速度快,简单,可扩展性强

Scrapy的官方文档(英文): https://docs.scrapy.org/en/latest/

神马叫框架:按照框架本身设计的逻辑. 往里面填写内容就可以了

学习其他框架的时候. 切忌:不要去直接上来去抠它的源码

先学会如何使用(怎么往里填窟窿),再反着去看他的源代码. 理解起来就容易了

三、Scrapy工作流程(重点)

  • 之前爬虫的逻辑:

# 伪代码,只为说明
def get_page_srouce():
    resp = requests.get(xxxxx)
    return resp.text | resp.json()
    
def parse_source():
    xpath,bs4,re
    return data
    
def save_data(data):
    txt,csv,mysql,mongodb
    
def main():  # 负责掌控全局
    # 首页的页面源代码
    ret = get_page_source()  # 获取页面源代码,发送网络请求
    data = parse_source(ret)  # 去解析出你要的数据
    # 需要继续请求新的url
    while: 
        # 详情页 
        ret = get_page_source()  # 获取页面源代码,发送网络请求
        data = parse_source(ret)  # 去解析出你要的数据
        save_data(data) # 负责数据存储
        
        # 详情页如果还有分页.
        # ...继续上述操作. 
      
if __name__ == '__main__':
    main()
  • scrapy的工作流程:

scrapy整个工作流程

  1. 爬虫中起始的url构造成request对象,并传递给调度器
  2. 引擎调度器中获取到request对象,然后交给下载器
  3. 下载器来获取到页面源代码,并封装成response对象。并回馈给引擎
  4. 引擎将获取到的response对象传递给spider。由spider对数据进行解析(parse)。并回馈给引擎
  5. 引擎将数据传递给pipeline进行数据持久化保存或进一步的数据处理
  6. 在此期间,如果spider中提取到的并不是数据, 而是子页面url,可以进一步提交给调度器,进而重复步骤2的过程

# 伪代码,只为说明
def get_page_srouce(url,method):
    if method == get:
        resp = requests.get(xxxxx)
        return resp.text | resp.json()
    
def parse_source():
    xpath,bs4,re
    
def save_data(data):
    txt,csv,mysql,mongodb
    
def main():  # 负责掌控全局->为了你理解
    # 主页
    req = spider.get_first_req()
    while 1:
        scheduler.send(req)
        next = scheduler.next_req()
        sth = downloader.get_page_source(next)
        data = spider.parse(sth)
        if data is 数据:
            pipeline.process_item(data)


if __name__ == '__main__':
    main()

上述过程中一直在重复着几个东西:5大组件

  1. 引擎(engine)

    scrapy的核心,所有模块的衔接,数据流程梳理.

  2. 调度器(scheduler)

    本质上这东西可以看成是一个集合和队列. 里面存放着一堆即将要发送的请求. 可以看成是一个url的容器. 它决定了下一步要去爬取哪一个url. 通常在这里可以对url进行去重操作.

  3. 下载器(downloader)

    它的本质就是用来发动请求的一个模块. 小白们完全可以把它理解成是一个requests.get()的功能. 只不过这货返回的是一个response对象.

  4. 爬虫(spider)

    这是我们要写的第一个部分的内容,负责解析下载器返回的response对象.从中提取到我们需要的数据.

  5. 管道(pipeline)

    这是我们要写的第二个部分的内容,主要负责数据的存储和各种持久化操作.

经过上述的介绍来看,scrapy其实就是把平时写的爬虫进行了四分五裂式的改造. 对每个功能进行了单独的封装,并且,各个模块之间互相的不做依赖. 一切都由引擎进行调配。

这种思想希望你能知道:解耦. 让模块与模块之间的关联性更加的松散.

这样我们如果希望替换某一模块的时候会非常的容易. 对其他模块也不会产生任何的影响.

到目前为止,我们对scrapy暂时了解这么多就够了. 后面会继续在这个图上进一步展开.

四、Scrapy安装

在windows上安装scrapy,可能会出现各种各样的异常BUG.

4.1 正常安装

### scrapy 2.5.1  --->  scrapy-redis 0.7.2

注意:由于scrapy的升级. 导致scrapy-redis无法正常使用
所以选择2.5.1这个版本作为学习. 后期各位可以根据scrapy-redis的升级,而跟着升级scrapy


# 先使用pip直接安装,看看报错不
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy==2.5.1 
pip install scrapy==2.5.1


如果安装成功,直接去创建项目即可
如果安装失败,请先升级一下pip,然后重新安装scrapy即可.
最新版本的pip升级完成后. 安装依然失败,可以根据报错信息进行一点点的调整,多试几次pip. 直至success

4.2 安装包安装

如果上述过程还是无法正常安装scrapy,可以考虑用下面的方案来安装:

# 1.安装wheel
pip install wheel

# 2.下载twisted安装包,https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

# 3.用wheel安装twisted
pip install Twisted‑21.7.0‑py3‑none‑any.whl

# 4.安装pywin32
pip install pywin32

# 5.安装scrapy
pip install scrapy

# 最终控制台输入 scrapy version 能显示版本号. 就算成功了

4.3 调整OpenSSL版本

安装完成后. 请调整OpenSSL的版本

输入命令: scrapy version --verbose

### 错误版本:

Scrapy       : 2.5.1
lxml         : 4.9.0.0
libxml2      : 2.9.12
cssselect    : 1.1.0
parsel       : 1.6.0
w3lib        : 1.22.0
Twisted      : 22.4.0
Python       : 3.9.12 (tags/v3.9.12:b28265d,Mar 23 2022,23:52:46) [MSC v.1929 64 bit (AMD64)]
pyOpenSSL    : 22.0.0 (OpenSSL 3.0.4 21 Jun 2022)  # 此时用的是3.0.4  要降低它的版本
cryptography : 37.0.3
Platform     : Windows-10-10.0.19043-SP0

更改方案:

pip uninstall cryptography

pip install cryptography==36.0.2

再次输入 scrapy version --verbose

### 正确版本:

Scrapy       : 2.5.1
lxml         : 4.9.0.0
libxml2      : 2.9.12
cssselect    : 1.1.0
parsel       : 1.6.0
w3lib        : 1.22.0
Twisted      : 22.4.0
Python       : 3.9.12 (tags/v3.9.12:b28265d,Mar 23 2022,23:52:46) [MSC v.1929 64 bit (AMD64)]
pyOpenSSL    : 22.0.0 (OpenSSL 1.1.1n  15 Mar 2022)  # 正确
cryptography : 36.0.2
Platform     : Windows-10-10.0.19043-SP0

五、Scrapy实例

接下来,用scrapy来完成一个超级简单的爬虫,目标: 深入理解Scrapy工作的流程,以及各个模块之间是如何搭配工作的.

5.1 创建项目

scrapy startproject 项目名称


# eg:
scrapy startproject mySpider_2

5.2 创建爬虫

cd 文件夹  # 进入项目所在文件夹

scrapy genspider 爬虫名称 允许抓取的域名范围

# eg:
cd mySpider_2

scrapy genspider youxi 4399.com

至此,爬虫创建完毕,目录结构如下:

mySpider_2       # 项目根目录  项目所在文件夹,建议用pycharm打开该文件夹
├── mySpider_2          # 项目包名
│   ├── __init__.py
│   ├── items.py        # 多个item类,相当于models.py   数据临时存放的对象(item)的多个类
│   ├── middlewares.py  # 所有中间件  爬虫/下载中间件 都写在这
│   ├── pipelines.py    # 多个pipeline管道类 (持久化相关写在这)  从item(items.py中类的对象)中,取出数据,存到文件、数据库等
│   ├── settings.py     # 爬虫配置信息
│   └── spiders         # 爬虫文件夹
│       ├── __init__.py
│       └── youxi.py    # 多个的爬虫 解析 (以后基本上都在这写东西)  从下载器返回的response对象中 解析数据,并把数据 存放进 item中
|
├── main.py             # 自己手动填加的脚本文件,用于执行 启动爬虫
└── scrapy.cfg          # scrapy项目配置信息  上线部署相关  别动它 

5.3 编写数据解析过程

主要就是编写 spiders 中爬虫的 parse()方法

# 完善youxi.py中的内容

import scrapy

class YouxiSpider(scrapy.Spider):
    name = 'youxi'  # 该名字非常关键,在启动该爬虫的时候,需要这个名字
    allowed_domains = ['4399.com']  # 爬虫抓取的域.
    start_urls = ['http://www.4399.com/flash/']  # 起始页

    def parse(self,response,**kwargs):
        # response.url   当前响应,是哪个请求url返回的

        # response.text     # 页面源代码
        # response.json()   # 提取json数据
        
        # response.xpath()  # 通过xpath方式提取
        # response.css()    # 通过css方式提取
            # 返回的是列表套selector对象(标签元素),若需要提取内容
              .extract_first()  # 取一个  返回是字符串
              .extract()        # 取所有  返回是列表形式  
 

        # 用最熟悉的方式: xpath提取游戏名称,游戏类别,发布时间等信息
        li_list = response.xpath("//ul[@class='n-game cf']/li")
        for li in li_list:
            name = li.xpath("./a/b/text()").extract_first()
            category = li.xpath("./em/a/text()").extract_first()
            date = li.xpath("./em/text()").extract_first()

            dic = {
                "name": name,
                "category": category,
                "date": date
            }

            # 将提取到的数据提交到管道内.
            # 注意,这里只能返回 request对象,item对象,or None
            yield dic    # 字典可以充当item对象
            
            
### 注意:   通常就是 借助item对象 来进行将数据 传输到管道中,进而持久化保存
spider返回的内容只能是requestes对象、item对象、None ,其他内容一律报错

5.4 编写持久化

主要就是 编写数据的存储 涉及文件 items.py 和 pipelines.py

首先修改settings.py文件中的pipeline信息

ITEM_PIPELINES = {
    # 前面是pipeline的类名地址  后面是优先级,优先级越低,越先执行
   'mySpider_2.pipelines.Myspider2Pipeline': 300,
    
    # 指定pipline,可以指定多个  保存到多个位置 (文件、数据库等)
    
}

简单修改一下pipeline中的代码:

class Myspider2Pipeline:
    # 这个方法的声明不能动!!! 在spider返回的数据,会自动的调用这里的process_item方法.
    def process_item(self, item, spider):
        # 真正存储的地方
        print(item)
        return item   # 一定不要忘了return item,交给后续的pipline继续使用

5.5 运行爬虫

scrapy crawl 爬虫名字

# eg:
scrapy crawl youxi



### 支持右键执行爬虫 (使用脚本文件运行爬虫)
在项目根目录下,新建一个main.py

from scrapy.cmdline import execute

# execute(['scrapy','crawl','youxi','--nolog'])   # 参数是:命令 列表
execute('scrapy crawl youxi '.split()) 

六、自定义数据传输结构item

在上述案例中,使用字典作为数据传递的载体,但是如果数据量非常大. 由于字典的key是随意创建的. 极易出现问题

Scrapy中提供item,作为数据格式的声明位置.

可以在items.py文件提前定义好,该爬虫在进行数据传输时的数据格式,然后再写代码的时候,就有了数据名称的依据了.

  • item.py文件
import scrapy

class GameItem(scrapy.Item):
    # 定义数据结构
    name = scrapy.Field()
    category = scrapy.Field()
    date = scrapy.Field()
    
class Person:
    private String name;
    private int age;
    
    
dic = {name: "alex",age: 18}

p = Person( "alex",18)
  • spiders下的youxi.py
from mySpider_2.items import GameItem

# 以下代码在spider中的parse替换掉原来的字典
item = GameItem()

# 封装数据 到 item中
item["name"] = name
item["category"] = category
item["date"] = date

yield item
  • pipelines.py
class Myspider2Pipeline:
   
    def process_item(self,item,spider):
        # 真正存储的地方
        print(item)   # 从item中取出数据,进行持久化存储
        
        return item   # 一定不要忘了return item,交给后续的pipline继续使用

七、scrapy使用小总结

至此,我们对scrapy有了一个非常初步的了解和使用.

快速总结一下scrapy框架的使用流程:

  1. 创建爬虫项目 scrapy startproject 项目名

  2. 进入项目目录 cd 项目名

  3. 创建爬虫 scrapy genspider 爬虫名 抓取网站的域名

  4. 编写item.py 文件,定义好数据传输类 item

  5. 调整spider

    • 给出起始url start_urls=[]

    • 修改spider中的parse方法,对返回的响应response对象进行解析, 返回item

  6. 在pipeline中对数据进行保存工作.

  7. 调整settings配置文件

    • 设置延迟访问时间 (单位:秒) 防止过快,干崩网站

      DOWNLOAD_DELAY = 1

    • 将pipeline管道设置为生效,并设置好优先级

    • 设置不遵守robots协议

      ROBOTSTXT_OBEY = False

    • 调整日志记录级别 控制台输出,留下有用的内容

      LOG_LEVEL = "WARNING"

  8. 启动爬虫 scrapy crawl 爬虫名

posted @ 2024-04-15 16:34  Edmond辉仔  阅读(25)  评论(0编辑  收藏  举报