Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架。

Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

通常我们可以很简单的通过 Scrapy 框架实现一个爬虫,抓取指定网站的内容或图片。


Scrapy架构图(绿线是数据流向)

  • Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。

  • Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。

  • Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,

  • Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器).

  • Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。

  • Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。

  • Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)

Scrapy的运作流程

代码写好,程序开始运行...

  • 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 管道调度器:好的,现在就做!

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

安装

Windows 安装方式

安装 Scrapy 框架步骤流程:

1、

pip3 install wheel

2、

下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/

进入下载目录,执行 pip3 install Twisted‑17.1.0‑cp35‑cp35m‑win_amd64.whl

备注(一定要下载对应的python版本号以及电脑的系统对应下载,否则安装不成功)

3、

pip3 install pywin32

4、

pip3 install scrapy

制作 Scrapy 爬虫 一共需要4步:

  1. 新建项目 (scrapy startproject xxx):新建一个新的爬虫项目
  2. 明确目标 (编写items.py):明确你想要抓取的目标
  3. 制作爬虫 (spiders/xxspider.py):制作爬虫开始爬取网页
  4. 存储内容 (pipelines.py):设计管道存储爬取内容

      

学习目标

  • 创建一个Scrapy项目
  • 定义提取的结构化数据(Item)
  • 编写爬取网站的 Spider 并提取出结构化数据(Item)
  • 编写 Item Pipelines 来存储提取到的Item(即结构化数据)

一. 新建项目(scrapy startproject)

在开始爬取之前,必须创建一个新的Scrapy项目。进入自定义的项目目录中,运行下列命令:

scrapy startproject mySpider

其中, mySpider 为项目名称,可以看到将会创建一个 mySpider 文件夹,目录结构大致如下:

下面来简单介绍一下各个主要文件的作用:

mySpider/
    scrapy.cfg
    mySpider/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...

这些文件分别是:

  • scrapy.cfg: 项目的配置文件。(爬虫相关的配置信息在settings.py文件中)
  • mySpider/: 项目的Python模块,将会从这里引用代码。
  • mySpider/items.py: 项目的目标文件。(设置数据储存模板,用于结构化数据)(相当于Django的Model)
  • mySpider/pipelines.py: 项目的管道文件。(数据持久化处理)
  • mySpider/settings.py: 项目的设置文件。(递归的层数,并发数。延迟下载等等)
  • mySpider/spiders/: 存储爬虫代码目录。(编写爬虫解析规则)

二、明确目标(mySpider/items.py)

  

我们打算抓取 https://www.thepaper.cn/channel_25951网站里的标题和内容

    1. 打开 mySpider 目录下的 items.py。

    2. Item 定义结构化数据字段,用来保存爬取到的数据,有点像 Python 中的 dict,但是提供了一些额外的保护减少错误。

    3. 可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个 Item(可以理解成类似于 ORM 的映射关系)。

接下来,创建一个 ItcastItem 类,和构建 item 模型(model)。

三、制作爬虫 (spiders/pengpai.py)

1

cd project_name(进入项目目录)

2

scrapy genspider 应用名称 爬取网页的起始url(scrapy gensipider app名  要爬取的域名) 例如:scrapy genspider pengpai www.thepaper.cn/channel_25951

3

编写爬虫文件:在步骤2执行完毕后,会在项目的spiders中生成一个应用名的py爬虫文件,文件源码如下:

# -*- coding: utf-8 -*-
import scrapy


class PengpaiSpider(scrapy.Spider):
    name = 'pengpai'
    allowed_domains = ['www.thepaper.cn/channel_25951']
    start_urls = ['http://www.thepaper.cn/channel_25951/']

    def parse(self, response):
        pass

4、

在settings.py中配置user-agent

在爬取数据时,可以选择是否往.../robots.txt/发送验证,是否允许爬取,一般设置为False

使用scrapy解析文本内容时,可以使用每个应用中的response.xpath(xxx) 进行数据的解析。

5、 

执行爬虫程序:scrapy crawl  应用名称

四、将澎湃首页中财经的内容和标题进行爬取

# -*- coding: utf-8 -*-
import scrapy


class PengpaiSpider(scrapy.Spider):
    name = 'pengpai'#应用的名称
    #允许爬取的域名(如果遇到非该域名的url则怕取不到数据)
    allowed_domains = ['www.thepaper.cn/channel_25951']
    #起始爬取的url
    start_urls = ['http://www.thepaper.cn/channel_25951/']
    #访问起始url并获取结果后的回调函数,response就是请求后响应对象
    #该函数返回值必须是可迭代对象或者NULL
    def parse(self, response):
        #xpath是response的方法,直接调用xpath,
        page_list = response.xpath('//*[@class="news_li"]')
        text_list = []
        for page in page_list:
            #返回的是一个selector标签列表,需要的数据在data中,因此取值需要用extract()
            title = page.xpath('./h2/a/text()')[0].extract()
            content = page.xpath('./p/text()')[0].extract()
            print(title,content)
            dic = {
                "title":title,
                "content":content,
            }
            text_list.append(dic)
        print(text_list)
        return text_list

执行爬虫程序:

scrapy crawl 爬虫名称 :显示执行的日志信息 scrapy crawl 爬虫名称 --nolog:不会显示执行的日志信息

备注:xpath使用方法:
  1.//+标签  表示从全局的子子孙孙中查找标签    

  2./+标签   表示从子代中查找标签
  3.查找带有xxx属性的标签:   标签+[@标签属性="值"]   
  4.查找标签的某个属性:  /标签/@属性  
  5.从当前标签中查找时:.//+标签    
xpath中支持正则的使用:    用法  标签+[re:test(@属性值,"正则表达式")]
  获取标签的文本内容:   /text()     
  获取第一个值需要  selector_obj.extract_first()    获取所有的值  selector_obj.extract()  值在一个list中