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跟进了。

Python——Scrapy初学的更多相关文章

  1. python scrapy版 极客学院爬虫V2

    python scrapy版 极客学院爬虫V2 1 基本技术 使用scrapy 2 这个爬虫的难点是 Request中的headers和cookies 尝试过好多次才成功(模拟登录),否则只能抓免费课 ...

  2. python Scrapy安装和介绍

    python Scrapy安装和介绍 Windows7下安装1.执行easy_install Scrapy Centos6.5下安装 1.库文件安装yum install libxslt-devel ...

  3. Python.Scrapy.14-scrapy-source-code-analysis-part-4

    Scrapy 源代码分析系列-4 scrapy.commands 子包 子包scrapy.commands定义了在命令scrapy中使用的子命令(subcommand): bench, check, ...

  4. Python.Scrapy.11-scrapy-source-code-analysis-part-1

    Scrapy 源代码分析系列-1 spider, spidermanager, crawler, cmdline, command 分析的源代码版本是0.24.6, url: https://gith ...

  5. python scrapy cannot import name xmlrpc_client的解决方案,解决办法

    安装scrapy的时候遇到如下错误的解决办法: "python scrapy cannot import name xmlrpc_client" 先执行 sudo pip unin ...

  6. Python爬虫初学(二)—— 爬百度贴吧

    Python爬虫初学(二)-- 爬百度贴吧 昨天初步接触了爬虫,实现了爬取网络段子并逐条阅读等功能,详见Python爬虫初学(一). 今天准备对百度贴吧下手了,嘿嘿.依然是跟着这个博客学习的,这次仿照 ...

  7. 教程+资源,python scrapy实战爬取知乎最性感妹子的爆照合集(12G)!

    一.出发点: 之前在知乎看到一位大牛(二胖)写的一篇文章:python爬取知乎最受欢迎的妹子(大概题目是这个,具体记不清了),但是这位二胖哥没有给出源码,而我也没用过python,正好顺便学一学,所以 ...

  8. 天气提醒邮件服务器(python + scrapy + yagmail)

    天气提醒邮件服务器(python + scrapy + yagmail) 项目地址: https://gitee.com/jerry323/weatherReporter 前段时间因为xxx上班有时候 ...

  9. Python -- Scrapy 框架简单介绍(Scrapy 安装及项目创建)

    Python -- Scrapy 框架简单介绍 最近在学习python 爬虫,先后了解学习urllib.urllib2.requests等,后来发现爬虫也有很多框架,而推荐学习最多就是Scrapy框架 ...

随机推荐

  1. dotweb框架之旅 [四] - 常用对象-HttpContext

    dotweb属于一个Web框架,希望通过框架行为,帮助开发人员快速构建Web应用,提升开发效率,减少不必要的代码臃肿. dotweb包含以下几个常用对象: App(dotweb) App容器,为Web ...

  2. Java IO(IO流)-1

    IO流 第一部分 (outputStream/InputStream Writer/Redaer) IO流对象中输入和输出是相辅相成的,输出什么,就可以输入什么. IO的命名方式为前半部分能干什么,后 ...

  3. 系统讲解CSS,前端开发最神奇的技术,新手的你一定不能错过

    前面小编带领大家重温了前端开发中最基本的HTML语言.如果你已经掌握了这门语言,那么恭喜你,可以去深入了解CSS技术了.CSS技术最主要的功能就是弥补HTML标记对在页面中显示外观的不足,对这些标记对 ...

  4. .net 面试题

    1.列举ASP.NET页面之间传值的几种方式. 答:使用QueryString,如.../id=1;response.Redirect() 使用Session 使用Server.Transfer 使用 ...

  5. LINUX 软件管理

    dpkg 安装 dpkg -i package.deb 卸载 dpkg -r packagename 彻底卸载 dpkg -P packagename apt-get 搜查包 apt-cache se ...

  6. Linux.SSH.修改SSH端口号

    Linux系统的默认SSH端口是22, 一般为发安全起见, 建议修改成其它端口 编辑配置文件: vi /etc/ssh/sshd_config 找到 #Port 22 把前面的#号去掉, 22修改成新 ...

  7. 启动报错 Unsupported major.minor version 51.0

    Unsupported major.minor version 51.0错误, 是使用jdk6启动jdk7编译的项目,更换jdk7就好了,或者用jdk6重新打包项目. 解决起来也很方便:打开excli ...

  8. LeetCode 245. Shortest Word Distance III (最短单词距离之三) $

    This is a follow up of Shortest Word Distance. The only difference is now word1 could be the same as ...

  9. python 文件相关知识

    字符编码相关 什么是字符编码 字符编码的类型 字符编码的使用 python2和python里字符编码的区别 文件的相关 文件的基础操作 打开文件的模式 字符编码 什么是字符编码在计算机里只识别二进制, ...

  10. c++ 类的默认八种函数

    c++ 类的默认八种函数 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #incl ...