Python——Scrapy初学

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。Scrapy最初是为了页面抓取(更确切来说, 网络抓取)所设计的,也可以应用在获取API所返回的数据(例如Amazon Associates Web Services)或者通用的网络爬虫。

1 安装

简要说明下Scrapy的安装:

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

下载后缀名为whl的scrapy文件,在cmd中进入Scripts所在的位置,输入pip install scrapy文件名.whl(可参考《Python初学基础》中的7.1 模块安装),注意scrapy依赖twiste,同样使用whl格式的包进行安装。安装完这两个模块后我在进行爬虫操作的时候提示没有win32api,该文件为exe,下载地址为https://sourceforge.net/projects/pywin32/files/pywin32/Build%20220/。

在安装好模块后要注意环境变量的配置,以我自己的安装目录为例,应当将D:\Program Files (x86)\Python\Scripts以及D:\Program Files (x86)\Python\Lib\site-packages加入环境变量中,否则模块只能在安装目录下运行,在别的目录下运行时会提示不是内部或者外部命令。在cmd下输入scrapy查看是否安装成功。

上述简单介绍了scrapy的安装,在安装的过程中不要着急,如果安装出错,要注意查看错误信息,根据这些信息一个一个去解决。

2 Scrapy架构及组件介绍

使用Scrapy抓取一个网站一共需要四个步骤:

1. 创建一个Scrapy项目;

2. 定义Item容器;

3. 编写爬虫;

4. 存储内容

学习怎么使用Scrapy之前,我们需要先来了解一下Scrapy的架构以及组件之间的交互。下图展现的是Scrapy的架构,包括组件及在系统中发生的数据流(图中绿色箭头)。

下面对每个组件都做了简单介绍:

Scrapy Engine

Scrapy引擎是爬虫工作的核心,负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。

调度器(Scheduler)

调度器从引擎接受request并将他们入队,以便之后引擎请求他们时提供给引擎。

下载器(Downloader)

下载器负责获取页面数据并提供给引擎,而后提供给spider。

Spiders

Spider是Scrapy用户编写用于分析由下载器返回的response,并提取出item和额外跟进的URL的类。 Item Pipeline Item Pipeline负责处理被spider提取出来的item。典型的处理有清理、验证及持久化(例如存取到数据库中)。

接下来是两个中间件,它们用于提供一个简便的机制,通过插入自定义代码来扩展Scrapy的功能。

下载器中间件(Downloader middlewares)

下载器中间件是在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的response。

Spider中间件(Spider middlewares)

Spider中间件是在引擎及Spider之间的特定钩子(specific hook),处理spider的输入(就是接收来自下载器的response)和输出(就是发送items给item pipeline以及发送requests给调度器)。

3 Scrapy爬虫框架入门实例

例程参考《scrapy爬虫框架入门实例》,该例子是抓取慕课网(http://blog.csdn.net/zjiang1994/article/details/52779537)。慕课网的页面结构已经变了,所以说该案例实际上已经不能达到抓取目的。但是关于scrapy爬虫框架整体的使用方式和流程目前还是正确的,可以进行参考。根据慕课网现有的页面结构做了一些改动可以成功实现。

要抓取的内容是全部的课程名称,课程图片,课程人数,课程简介,课程URL:

右键审查元素查看

#如果response是网页资源的话,下面的代码可以帮助我们获得div
divs = response.xpath('//div[@class="course-card-container"]')

所以如果div已经获得的话通过如下获得信息(详解介绍见下文):

#获取每个div中的课程路径item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0]#获取div中的课程标题
item['title'] = box.xpath('.//h3[@class="course-card-name"]/text()').extract()[0].strip()
#获取div中的标题图片地址
item['image_url'] =  'http:' + box.xpath('.//@src').extract()[0]
#获取div中的学生人数
item['student'] = box.xpath('.//span/text()').extract()[1].strip()
#获取div中的课程简介
item['introduction'] = box.xpath('.//p/text()').extract()[0].strip()

工作流程

Scrapy框架抓取的基本流程是这样:

当然了,还有一些中间件等等,这里是入门例子,所以不涉及。

1)创建一个Scrapy项目

在开始爬取之前,您必须创建一个新的Scrapy项目。

进入您打算存储代码的目录中,运行下列命令: scrapy startproject tutorial

该命令将会创建包含下列内容的tutorial目录:

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

这些文件构成Scrapy爬虫框架,它们分别的作用是:

scrapy.cfg – 项目的配置文件

tutorial/ – 该项目的python模块,之后您将在此加入代码

tutorial/items.py – 项目中的item文件

tutorial/pipelines.py – 项目中的pipelines文件

tutorial/settings.py – 项目的设置文件

tutorial/spiders/ – 放置spider代码的目录

2)定义Item容器

Item是保存爬取到的数据的容器,其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。

首先根据需要获取到的数据对item进行建模。比如我们需要从慕课网中获取课程名称,课程图片,课程人数,课程简介,课程URL。对此,我们需要在item中定义相应的字段。

我们在工程目录下可以看到一个items文件,我们可以更改这个文件或者创建一个新的文件来定义我们的item。将item.py中的内容修改如下:

#引入文件
import scrapy

class CourseItem(scrapy.Item):
    #课程标题
    title = scrapy.Field()
    #课程url
    url = scrapy.Field()
    #课程标题图片
    image_url = scrapy.Field()
    #课程描述
    introduction = scrapy.Field()
    #学习人数
    student = scrapy.Field()
    image_path = scrapy.Field()

根据如上的代码,我们创建了一个名为item的容器,用来保存、抓取的信息, title->课程标题, url->课程url, image_url->课程标题图片, introduction->课程描述, student->学习人数。在创建完item文件后我们可以通过类似于词典(dictionary-like)的API以及用于声明可用字段的简单语法。常用方法如下:

#定义一个item
course = CourseItem()
#赋值
course['title'] = "语文"
#取值
course['title']
course.get('title')
#获取全部键
course.keys()
#获取全部值
course.items()

3) 创建一个爬虫

我们要编写爬虫,首先是创建一个Spider我们在tutorial/spiders/目录下创建一个文件MySpider.py

文件包含一个MySpider类,它必须继承scrapy.Spider类。

同时它必须定义一下三个属性:

-name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。 -start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。 -parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。

创建完成后MySpider.py的代码如下

#引入文件
import scrapy

class MySpider(scrapy.Spider):
    #用于区别Spider
    name = "MySpider"
    #允许访问的域
    allowed_domains = []
    #爬取的地址
    start_urls = []
    #爬取方法
    def parse(self, response):
        pass

为了简单清晰,我们先抓取一个页面中的信息。

首先我们编写爬取代码。我们在上文说过,爬取的部分在MySpider类的parse()方法中进行。 parse()方法负责处理response并返回处理的数据以及(/或)跟进的URL。该方法及其他的Request回调函数必须返回一个包含 Request 及(或) Item 的可迭代的对象。

在网页中提取我们所需要的数据,之前所学习的是根据正则表达式来获取,在Scrapy中是使用一种基于Xpath和CSS的表达式机制:Scrapy Selectors。

Selector是一个选择器,它有四个基本的方法:

xpath() – 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 。

css() – 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表。

extract() – 序列化该节点为unicode字符串并返回list。

re() – 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。

在Shell中尝试Selector选择器

为了介绍Selector的使用方法,接下来我们将要使用内置的Scrapy shell。

你需要先进入项目的根目录,执行下列命令来启动Scrapy shell:

scrapy shell “http://www.imooc.com/course/list”

shell的输出类似:

在Shell载入后,你将获得response回应,存储在本地变量response中。

所以如果你输入response.body,你将会看到response的body部分,也就是抓取到的页面内容,或者输入response.headers 来查看它的 header部分。现在就像是一大堆沙子握在手里,里面有我们想要的金子,所以下一步我们就要用筛子把沙子去掉,淘出金子。selector选择器就是这样一个筛子,正如我们刚才讲到的,你可以使用response.selector.xpath()、response.selector.css()、response.selector.extract()和response.selector.re()这四个基本方法。

使用XPath

什么是XPath?XPath是一门在网页中查找特定信息的语言。所以用XPath来筛选数据,要比使用正则表达式容易些。

这里给出XPath表达式的例子及对应的含义:

/html/head/title – 选择HTML文档中<head>标签内的<title>元素

/html/head/title/text() – 选择上面提到的<title>元素的文字

//td – 选择所有的<td>元素

//div[@class=”mine”] – 选择所有具有class=”mine”属性的div元素

上边仅仅是几个简单的XPath例子,XPath实际上要比这远远强大的多。如果你想了解更多关于XPath的内容,推荐学习这篇文章http://www.w3school.com.cn/xpath/

值得一提的是,response.xpath()、response.css()已经被映射到response.selector.xpath()、response.selector.css(),所以直接使用response.xpath()即可。

在Python编写时,由于没有学习过Xpath,所以我先在cmd中编写试验得到正确的返回结果后再写入代码中,注意shell根据response的类型自动为我们初始化了变量sel,我们可以直接使用。

例如获取每个div中的课程路径:

此外,我们希望Spiders将爬取并筛选后的数据存放到item容器中,所以我们MySpider.py的代码应该是这样的:

import scrapy
#引入容器
from tutorial.items import CourseItem


class MySpider(scrapy.Spider):
    #设置name
    name = "MySpider"
    #设定域名
    allowed_domains = ["imooc.com"]
    #填写爬取地址
    start_urls = ["http://www.imooc.com/course/list"]
    #编写爬取方法
    def parse(self, response):
        #实例一个容器保存爬取的信息
        item = CourseItem()  
        #这部分是爬取部分,使用xpath的方式选择信息,具体方法根据网页结构而定
        #先获取每个课程的div
        for box in response.xpath('//div[@class="course-card-container"]'):
            #获取每个div中的课程路径
            item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0]
            #获取div中的课程标题
            item['title'] = box.xpath('.//h3[@class="course-card-name"]/text()').extract()[0].strip()
            #获取div中的标题图片地址
            item['image_url'] =  'http:' + box.xpath('.//@src').extract()[0]
            #获取div中的学生人数
            item['student'] = box.xpath('.//span/text()').extract()[1].strip()
            #获取div中的课程简介
            item['introduction'] = box.xpath('.//p/text()').extract()[0].strip()
            #返回信息
            yield item

在parse()方法中response参数返回一个下载好的网页信息,我们然后通过xpath来寻找我们需要的信息。 在scrapy框架中,可以使用多种选择器来寻找信息,这里使用的是xpath,同时我们也可以使用BeautifulSoup,lxml等扩展来选择,而且框架本身还提供了一套自己的机制来帮助用户获取信息,就是Selectors。 

在执行完以上步骤之后,我们可以运行一下爬虫,看看是否出错。

在命令行下进入工程文件夹,然后运行:

scrapy crawl MySpider

如果操作正确会显示如下信息:

上面信息表示,我们已经获取了信息,接下来我们开始进行信息的储存。

最简单存储爬取的数据的方式是使用Feed exports,主要可以导出四种格式:JSON,JSON lines,CSV和XML。

我们这里将结果导出为最常用的JSON格式:

scrapy crawl dmoz -o items.json -t json

-o 后边是导出的文件名,-t 指定导出类型 成功执行命令后,根目录出现了一个叫 items.json 的文件,内容如下:

或者使用Pipeline处理数据:

当我们成功获取信息后,要进行信息的验证、储存等工作,这里以储存为例。 当Item在Spider中被收集之后,它将会被传递到Pipeline,一些组件会按照一定的顺序执行对Item的处理。 Pipeline经常进行以下一些操作: 清理HTML数据 验证爬取的数据(检查item包含某些字段) 查重(并丢弃) 将爬取结果保存到数据库中

这里只进行简单的将数据储存在json文件的操作。

改写在tutorial/目录下文件pipelines.py的代码如下:

# -*- coding: utf-8 -*-

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

#引入文件
from scrapy.exceptions import DropItem
import json

class MyPipeline(object):
    def __init__(self):
        #打开文件
        self.file = open('data.json', 'w', encoding='utf-8')
    #该方法用于处理数据
    def process_item(self, item, spider):
        #读取item中的数据
        line = json.dumps(dict(item), ensure_ascii=False) + "\n"
        #写入文件
        self.file.write(line)
        #返回item
        return item
    #该方法在spider被开启时被调用。
    def open_spider(self, spider):
        pass
    #该方法在spider被关闭时被调用。
    def close_spider(self, spider):
        pass

要使用Pipeline,首先要注册Pipeline

找到settings.py文件,这个文件时爬虫的配置文件

在其中添加:

ITEM_PIPELINES = {
    'tutorial.pipelines.MyPipeline': 1,
}

上面的代码用于注册Pipeline,其中'tutorial.pipelines.MyPipeline为你要注册的类,右侧的’1’为该Pipeline的优先级,范围1~1000,越小越先执行。

进行完以上操作,我们的一个最基本的爬取操作就完成了

这时我们再运行:

scrapy crawl MySpider

就可以在项目根目录下发现data.json文件,里面存储着爬取的课程信息。

上面的代码只进行了比较简单的爬取,并没有完成爬取慕课网全部课程的目标。 下面进行一些简单的扩展完成我们的目标。

url跟进

在上面我们介绍了如何进行简单的单页面爬取,但是我们可以发现慕课网的课程是分布在去多个页面的,所以为了完整的爬取信息课程信息,我们需要进行url跟进。

为了完成这个目标需要对MySpider.py文件进行如下更改

import scrapy
#引入容器
from tutorial.items import CourseItem


class MySpider(scrapy.Spider):
    #设置name
    name = "MySpider"
    #设定域名
    allowed_domains = ["imooc.com"]
    #填写爬取地址
    start_urls = ["http://www.imooc.com/course/list"]
    #编写爬取方法
    def parse(self, response):
        #实例一个容器保存爬取的信息
        item = CourseItem()  
        #这部分是爬取部分,使用xpath的方式选择信息,具体方法根据网页结构而定
        #先获取每个课程的div
        for box in response.xpath('//div[@class="course-card-container"]'):
            #获取每个div中的课程路径
            item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0]
            #获取div中的课程标题
            item['title'] = box.xpath('.//h3[@class="course-card-name"]/text()').extract()[0].strip()
            #获取div中的标题图片地址
            item['image_url'] =  'http:' + box.xpath('.//@src').extract()[0]
            #获取div中的学生人数
            item['student'] = box.xpath('.//span/text()').extract()[1].strip()
            #获取div中的课程简介
            item['introduction'] = box.xpath('.//p/text()').extract()[0].strip()
            #返回信息
            yield item

        #url跟进开始
        #获取下一页的url信息
        url = response.xpath("//a[contains(text(),'下一页')]/@href").extract()
        if url :
            #将信息组合成下一页的url
            page = 'http://www.imooc.com' + url[0]
            #返回url
            yield scrapy.Request(page, callback=self.parse)
        #url跟进结束

修改成功后就可以自动进行url跟进了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ASP.NETCore

Asp.Net Core 通过中间件防止图片盗链

  要实现防盗链,我们就必须先理解盗链的实现原理,提到防盗链的实现原理就不得不从HTTP协议说起,在HTTP协议中,有一个表头字段叫referer,采用URL的...

1503
来自专栏纯洁的微笑

分布式爬虫系统设计、实现与实战:爬取京东、苏宁易购全网手机商品数据+MySQL、HBase存储

2963
来自专栏微信公众号:Java团长

Java线程的5个使用技巧

萝卜白菜各有所爱。像我就喜欢Java。学无止境,这也是我喜欢它的一个原因。日常工作中你所用到的工具,通常都有些你从来没有了解过的东西,比方说某个方法或者是一些有...

842
来自专栏大数据挖掘DT机器学习

用scrapy爬虫抓取慕课网课程数据详细步骤

关于如何安装scrapy框架,可以参考这篇文章 史上最完全Mac安装Scrapy指南 http://www.jianshu.com/p/a03aab073...

5748
来自专栏腾讯大数据的专栏

网卡收包流程

0.前言 为提升信鸽基础服务质量,笔者就网络收包全流程进行了内容整理。 网络编程中我们接触得比较多的是socket api和epoll模型,对于系统内核和网卡驱...

2K14
来自专栏友弟技术工作室

常用python爬虫框架整理Python中好用的爬虫框架1.Scrapy2.PySpider3.Crawley4.Portia5.Newspaper6.Beautiful Soup7.Grab8.Co

一般比价小型的爬虫需求,我是直接使用requests库 + bs4就解决了,再麻烦点就使用selenium解决js的异步 加载问题。相对比较大型的需求才使用框架...

1473
来自专栏小怪聊职场

爬虫课堂(十四)|URL的去重方法

5357
来自专栏技术小站

Python3 Scrapy 安装方法

转自:https://blog.csdn.net/zjiang1994/article/details/52689144

1242
来自专栏前端儿

【转】http-equiv="X-UA-Compatible" 设置IE浏览器兼容模式详解

文件兼容性用于定义让IE如何编译你的网页。此文件解释文件兼容性,如何指定你网站的文件兼容性模式以及如何判断一个网页该使用的文件模式。

2911
来自专栏cnblogs

Hi,给他介绍一款markdown的帮助文档生成器

      当今大多数的团队都实现了前、后端分支。前端与后端的沟通都是通过接口来实现的(一般情况下都是webapi接口)。这种情况你肯定需要一个接口查询的帮助文...

1262

扫码关注云+社区

领取腾讯云代金券