Scrapy 爬虫框架介绍

官网:https://www.scrapy.org/

文档:https://docs.scrapy.net.cn/en/latest/

快速功能强大的网络爬虫框架

Scrapy 的安装

pip install scrapy

scrapy -h

Scrapy 爬虫框架结构

Scrapy不是一个函数功能库,而是一个爬虫框架

爬虫框架是实现爬虫功能的一个软件结构和功能组件集合

爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫

Scrapy 爬虫框架解析

数据流的三个路径

数据流的出入口

“5 + 2"结构

小结:

Scrapy 爬虫框架是一个包含5个主要模块和2个中间键的框架。其中,

engine模块是整个框架的核心,控制所有模块之间的数据流;

downloader模块负责根据用户提供的请求下载网页;

scheduler模块对爬取请求进行调度管理;

spider模块解析下载器返回的响应,产生爬取项和额外的爬取请求;

item pipelines模块以流水线的方式处理爬取项,对数据进行清理、检验、查重等操作。

用户主要需要编写spider模块和item pipelines模块的相关代码,可以通过中间键对请求、响应和爬取项进行操作和配置。

requests 库和 Scrapy 爬虫的比较

相同点:

两者都可以进行页面请求和爬取,Python爬虫的两个重要技术路线

两者可用性都好,文档丰富,入门简单

两者都没有处理js、提交表单、应对验证码等功能(可扩展)

不同点:

选用哪个技术路线开发爬虫呢?

非常小的需求,requests库

不太小的需求,Scrapy框架

定制程度很高的需求(不考虑规模),自搭框架,requests > Scrapy

Scrapy 爬虫的常用命令

Scrapy 是为持续运行设计的专业爬虫框架,提供操作的 Scrapy 命令行

Scrapy 命令行格式

>scrapy <command> [options] [args]

常用命令

Scrapy 爬虫的使用

应用Scrapy爬虫框架主要是编写配置型代码

第一个实例

步骤1:建立一个Scrapy爬虫工程

选取一个目录(D:\pycodes\),然后执行如下命令:

scrapy startproject python123demo

生成的工程目录:

步骤2:在工程中产生一个Scrapy爬虫

进入工程目录(D:\pycodes\python123demo),然后执行如下命令:

scrapy genspider demo python123.io

该命令作用:

(1) 生成一个名称为demo的spider

(2) 在spiders目录下增加代码文件demo.py

该命令仅用于生成demo.py,该文件也可以手工生成

步骤3:配置产生的spider爬虫

配置:(1)初始URL地址

(2)获取页面后的解析方式

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import scrapy


class DemoSpider(scrapy.Spider):
    name = "demo"
    allowed_domains = ["python123.io"]
    start_urls = ["https://python123.io/ws/demo.html"]

    def parse(self, response):
        fname = response.url.split("/")[-1]
        with open(fname, "wb") as f:
            f.write(response.body)
        self.log('Saved %s' % fname)

步骤4:运行爬虫,获取网页

在命令行下,执行如下命令:

scrapy crawl demo

demo爬虫被执行,捕获页面存储在demo.html

yield 关键字的使用

yield 关键字

实例

生成器每调用一次在 yield 位置产生一个值,直到函数执行结束

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def gen(n):
    for i in range(n):
        yield i**2

    
for i in gen(5):
    print(i, " ", end="")

    
0  1  4  9  16  

为什么要有生成器?

改进 demo.py

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import scrapy

class DemoSpider(scrapy.Spider):
    name = "demo"

    def start_requests(self):
        urls = [
            "https://python123.io/ws/demo.html",
        ]
        #把 URL 交给 Scrapy 的调度器,让 Scrapy 去“异步下载页面,并在下载完成后自动调用 parse 处理结果”。
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)


    def parse(self, response):
        fname = response.url.split("/")[-1]
        with open(fname, "wb") as f:
            f.write(response.body)
        self.log('Saved %s' % fname)

yield scrapy.Request()
是 Scrapy 爬虫的 入口
负责把 URL 提交给调度器
下载完成后自动调用回调函数处理响应

Scrapy 爬虫的使用步骤

步骤1:创建一个工程和Spider模板

步骤2:编写Spider

步骤3:编写Item Pipeline

步骤4:优化配置策略

Scrapy 爬虫的数据类型

Request类

class scrapy.http.Request()

Request对象表示一个HTTP请求

由Spider生成,由Downloader执行

Response类

class scrapy.http.Response()

Response对象表示一个HTTP响应

由Downloader生成,由Spider处理

Item类

class scrapy.item.Item()

Item 对象表示一个从 HTML 页面中提取的信息内容

由 Spider 生成,由 Item Pipeline 处理

Item 类似字典类型,可以按照字典类型操作

Scrapy 爬虫提取信息的方法

Scrapy爬虫支持多种HTML信息提取方法:

• Beautiful Soup

• lxml

• re

• XPath Selector

• CSS Selector

CSS Selector 的基本使用

<HTML>.css('a::attr(href)').extract()

实例:“股票数据 Scrapy 爬虫”

步骤

步骤1:建立工程和Spider模板

步骤2:编写Spider

步骤3:编写ITEM Pipelines

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
D:\pycodes>scrapy startproject BaiduStocks
New Scrapy project 'BaiduStocks', using template directory 'C:\Users\SZZY\AppData\Local\Programs\Python\Python310\Lib\site-packages\scrapy\templates\project', created in:
    D:\pycodes\BaiduStocks

You can start your first spider with:
    cd BaiduStocks
    scrapy genspider example example.com

D:\pycodes>cd BaiduStocks

D:\pycodes\BaiduStocks>scrapy genspider stocks baidu.com
Created spider 'stocks' using template 'basic' in module:
  BaiduStocks.spiders.stocks

D:\pycodes\BaiduStocks>

stocks.py

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import scrapy
import re

class StocksSpider(scrapy.Spider):
    name = "stocks"
    start_urls = ['http://quote.eastmoney.com/stocklist.html']

    def parse_stock(self, response):
        infoDict = {}
        stockInfo = response.css('.stock-bets')
        name = stockInfo.css('.bets-name').extract()[0]
        keyList = stockInfo.css('dt').extract()
        valueList = stockInfo.css('dd').extract()
        for i in range(len(keyList)):
            key = re.findall(r'>.*<\dt>', keyList[i])[0][1:-5]
            try:
                val = re.findall(r'>.*<\dt>', valueList[i])[0][0:-5]
            except:
                val = '--'
            infoDict[key] = val

        infoDict.update(
            {
                '股票名称': re.findall('\s.*\(', name)[0].split()[0] + re.findall('\>.*\<', name)[0][1:-1]
            }
        )

        yield infoDict

pipeline.py

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from itemadapter import ItemAdapter


class BaidustocksPipeline(object):
    def process_item(self, item, spider):
        return item

class BaiduStocksPipeline(object):
    def open_spider(self, spider):
        self.f = open('BaiduStocks.txt','w')
        
    def close_spider(self, spider):
        self.f.close()
        
    def process_item(self, item, spider):
        try:
            line = str(dict(item)) + "\n" 
            self.f.write(str(item))
        except:
            pass
        return item
            

setting.py