09—小白学Python爬虫之Scrapy快速入门与实战

从本篇起,将学习一下Scrapy爬虫框架,以及如何通过该框架实现定向爬虫。Scrapy是一个非常优秀的框架,操作简单,扩展方便,是比较流行的爬虫解决方案。

初识

Scrapy是使用Python编写的Crawler Framework,简单轻巧,其使用Twisted异步库来处理网络通信,架构清晰,并且包含了各种中间件接口,可以灵活的完成各种需求。

架构及组件

首先看一下Scrapy的整体架构图(绿线是数据流向),如下:
这里写图片描述
根据架构图介绍一下Scrapy中各大组件及其功能:
- Scrapy引擎(Engine):负责Spider ItemPipeline Downloader Scheduler之间的通讯、数据传递等
- 调度器(Scheduler):负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,加入队列,当引擎需要时,交还给引擎
- Downloader(下载器):负责下载引擎发送过来的所有Request请求,并将其获取到的Responses交还给引擎,由引擎交给Spider来处理
- Spider(爬虫):负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)
- ItemPipeline(管道):负责处理Spider中获取的Item,并进行后期处理,比如详细分析、过滤、存储等
- 下载器中间件(Downloader middlewares):是在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的Response,可以自定义扩展下载功能
- Spider Middlewares(Spider中间件):是在引擎与Spider之间的特定钩子,可以自定义扩展通信功能,比如进入Spider的Responses和从Spider出去的Requests

Scrapy工作流程

官方版
  1. 引擎打开一个网站(open a domain),找到处理该网站的Spider,并向该Spider请求第一个要爬取的URL
  2. 引擎从Spider中获取到第一个要爬取的URL并通过调度器(Scheduler)以及Request进行调度
  3. 引擎向调度器请求下一个要爬取的URL
  4. 调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求request方向)转发给下载器(Downloader)
  5. 一旦页面下载完毕,下载器会生成该页面的Response,并将其通过下载中间件(返回response方向)发送给引擎
  6. 引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理
  7. Spider处理Response并返回爬取到的Item以及使用有需要跟进的新的Request给引擎
  8. 引擎将(Spider返回的)Item交给Item Pipeline,将(Spider返回的)Request给调度器
  9. (从第二步)重复直到调度器中没有Request,引擎关闭该网站
白话版
  1. 引擎:Hi!Spider, 你要处理哪一个网站?
  2. Spider:老大要我处理xxxx.com。
  3. 引擎:你把第一个需要处理的URL给我吧。
  4. Spider:给你,第一个URL是xxxxxxx.com。
  5. 引擎:Hi!调度器,我这有request请求你帮我排序入队一下。
  6. 调度器:好的,正在处理你等一下。
  7. 引擎:Hi!调度器,把你处理好的request请求给我。
  8. 调度器:给你,这是我处理好的request
  9. 引擎:Hi!下载器,你按照老大的下载中间件的设置帮我下载一下这个request请求
  10. 下载器:好的!给你,这是下载好的东西。(如果失败:sorry,这个request下载失败了。然后引擎告诉调度器,这个request下载失败了,你记录一下,我们待会儿再下载)
  11. 引擎:Hi!Spider,这是下载好的东西,并且已经按照老大的下载中间件处理过了,你自己处理一下(注意!这儿responses默认是交给def parse()这个函数处理的)
  12. Spider:(处理完毕数据之后对于需要跟进的URL),Hi!引擎,我这里有两个结果,这个是我需要跟进的URL,还有这个是我获取到的Item数据。
  13. 引擎:Hi !管道 我这儿有个item你帮我处理一下!调度器!这是需要跟进URL你帮我处理下。然后从第四步开始循环,直到获取完老大需要全部信息。
  14. 管道And调度器:好的,现在就做!

只有当调度器中不存在任何request了,整个程序才会停止。(也就是说,对于下载失败的URL,Scrapy也会重新下载。)

安装

Windows安装
  1. 安装pywin32点我下载,下载响应版本的pywin32,双击安装即可。
  2. 安装pyOpenSSL源码下载,下载完成后,运行python setup.py install安装即可
  3. 安装lxml,使用pip install lxml,如果提示Microsoft Visual C++库没安装,则需要下载响应支持的库,点我下载
  4. 安装Scrapy,使用pip install Scrapy
Linux(macOS)

Linux下绝大部分版本都预装了Python环境,而且还预装了lxml和OpenSSL,所有直接使用pip install Scrapy安装即可。
接下来,会发现,安装了如下包:

Installing collected packages: six, w3lib, cssselect, parsel, pycparser, cffi, asn1crypto, cryptography, pyOpenSSL, PyDispatcher, zope.interface, constantly, incremental, attrs, Automat, hyperlink, Twisted, queuelib, pyasn1, pyasn1-modules, service-identity, Scrapy
Successfully installed Automat-0.6.0 PyDispatcher-2.0.5 Scrapy-1.5.0 Twisted-17.9.0 asn1crypto-0.24.0 attrs-17.4.0 cffi-1.11.5 constantly-15.1.0 cryptography-2.2.2 cssselect-1.0.3 hyperlink-18.0.0 incremental-17.5.0 parsel-1.4.0 pyOpenSSL-17.5.0 pyasn1-0.4.2 pyasn1-modules-0.2.1 pycparser-2.18 queuelib-1.5.0 service-identity-17.0.0 six-1.11.0 w3lib-1.19.0 zope.interface-4.4.3

点我查看官方各平台安装方法

入门实战

目标
  • 创建一个Scrapy项目
  • 定义提取的结构化数据(Item)
  • 编写爬取网站的Spider并提取结构化数据(Item)
  • 编写Item Pipelines存储提取到的Item
新建项目(scrapy startproject)
  • 在开始爬取之前,先创建新的Scrapy项目。进入目标项目目录后,执行以下命名:
scrapy startproject novelSpider
  • 其中novelSpider为项目名称,可以看到会在当前目录下创建novelSpider文件夹,目录结构如下:
    这里写图片描述
  • 简单介绍一下各文件作用:
    • scrapy.cfg:项目的配置文件
    • novelSpider/:项目的python模块,将会从这里引用代码
    • novelSpider/items.py:项目的目标文件
    • novelSoider/pipelines.py:项目的管道文件
    • novelSpider/settings.py:项目的设置文件
    • novelSpider/spiders:存储爬虫代码目录
明确目标(novelSpider/items.py)

在此,我们打算抓取http://www.jjwxc.net/topten.php?orderstr=13中小说的序号、作者、类型、进度等信息。

  1. 打开novelSpider目录下的items.py
  2. Item定义结构化数据字段,用来保存爬取到的数据,有点像Python中的dict,但提供了一些额外的保护减少错误
  3. 创建一个scrapy.Item类,并定义类型为scrapy.Field的类属性来定义一个Item
  4. 接下来,创建NovalItem类和构建item模型(model)
import scrapy


class NovelItem(scrapy.Item):
    id = scrapy.Field()
    author = scrapy.Field()
    title = scrapy.Field()
    type = scrapy.Field()
    style = scrapy.Field()
    process = scrapy.Field()
    date = scrapy.Field()
制作爬虫(spiders/novel.py)
爬数据

上一步在调用scrapy startproject novelSpider时,曾提示我们:

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

接下来,就用到这个提示了。首先cd novelSpider进入小说爬虫目录,执行如下命令:

scrapy genspider novel "jjwxc.net"
  • 打开novelSpider/spiders目录中的novel.py,默认增加了如下代码:
# -*- coding: utf-8 -*-
import scrapy


class NovelSpider(scrapy.Spider):
    name = 'novel'
    allowed_domains = ['jjwxc.net']
    start_urls = ['http://jjwxc.net/']

    def parse(self, response):
        pass

其实我们也可以自行创建novel.py并编写上面代码,只不过使用命令可以免去编写固定代码的麻烦。

建立一个Spider,必须使用scrapy.Spider类创建一个子类,并确定三个属性和一个方法:

  1. name = "":爬虫的唯一标识,不可重复
  2. allowed_domains = []:爬虫搜索的域名范围,只能在该域名下进行爬取
  3. start_urls = []:爬取的URL元祖或列表。从这里开始抓取数据,也就是第一次下载的数据会从这些urls开始,其他子URL会从起始URL中继承性生成
  4. parse(self,response):解析方法,每个URL下载完成后被调用,传入Response对象作为参数,主要用来解析返回的网页数据(response.body),提取结构化数据(Item),生成下一页URL请求

在此,将start_urls的值修改为爬取的第一个url:

start_urls = ['http://www.jjwxc.net/topten.php?orderstr=13']
  • 修改parse方法
    def parse(self, response):
        filename = 'novel.html'
        with open(filename, 'w') as f:
            f.write(response.body.decode(response.encoding))
  • 运行抓取,执行如下命令
scrapy crawl novel

novel就是我们生成的唯一爬虫名。
运行之后,打印的日志出现[scrapy.core.engine] INFO: Spider closed (finished),代表执行完成。当前文件夹会出现一个novel.html文件,内容就是爬取网页的全部源代码信息。

取数据
  • 引入在novelSpider/items.py中定义的NovelItem
from novelSpider.items import NovelItem
  • 分析html内容,查询目标内容,把数据封装到NovelItem对象中
# -*- coding: utf-8 -*-
import scrapy
from novelSpider.items import NovelItem


class NovelSpider(scrapy.Spider):
    name = 'novel'
    allowed_domains = ['jjwxc.net']
    start_urls = ['http://www.jjwxc.net/topten.php?orderstr=13']

    def parse(self, response):
        content = response.body.decode(response.encoding)
        # filename = 'novel.html'
        # with open(filename, 'w') as f:
        #     f.write(content)
        # bgcolor #eefaee
        novelList = []
        for item in response.xpath('//tr[@bgcolor="#eefaee"]'):
            id = item.xpath('td')[0].xpath('text()').extract()
            author = item.xpath('td')[1].xpath('a/text()').extract()
            title = item.xpath('td')[2].xpath('a/text()').extract()
            type = item.xpath('td')[3].xpath('text()').extract()
            style = item.xpath('td')[4].xpath('text()').extract()
            date = item.xpath('td')[8].xpath('text()').extract()
            # print(id, author, title, type, style, date)

            novelItem = NovelItem()
            novelItem['num'] = id[0]
            novelItem['author'] = author[0]
            novelItem['title'] = title[0]
            novelItem['type'] = type[0]
            novelItem['style'] = style[0]
            novelItem['date'] = date[0]

            novelList.append(novelItem)

        return novelList
  • 暂时先不处理管道,后面再详细介绍
保存数据

scray保存信息主要有四种,-o输出指定格式的文件,命令如下:

# json格式,默认为Unicode编码啊
scrapy crawl novel -o novels.json

# json lines格式,默认为Unicode编码啊
scrapy crawl novel -o novels.jsonlines

# json格式,默认为Unicode编码啊
scrapy crawl novel -o novels.json

# xml格式
scrapy crawl novel -o novels.xml

好了,scrapy的基本介绍就到这了,有一个小问题,在parse方法中,我们使用的是return items,如果换成yield会有什么区别和不同呢?请听下回分解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值