摘要:本文介绍了Scrapy的基础爬取流程,也是最重要的部分

Scrapy的爬取流程

Scrapy的爬取流程可以概括为一个方程式:UR2IM,其含义如下图所示

URL:Scrapy的运行就从那个你想要爬取的网站地址开始,当你想要验证用xpath或其他解析器来解析这个网页时,可以使用Scrapy shell工具来进行分析,譬如

现在你就可以开始验证了

Request和Response:在上面使用Scrapy shell的过程中可以发现,只要我们输入了一个URL,它就可以自动发送一个GET请求并获取返回结果。request是一个把url封装好的对象,response则是一个把网页返回结果封装好的对象,response.body的值是网页的源代码,response.url是网页的url地址,还有更多相关的属性

Items:我们要爬取一个网页的时候并不是只把源代码下载下来就完事了,还需要提取网页中的相关信息,譬如网页的标题,网页的发布时间等等内容,而这些内容使用面向对象的技术,封装成一个Item对象,然后从网页中提取信息来填充这个Item

新建Scrapy工程

首先新建一个名为properties的Scrapy工程

$ scrapy startproject properties
$ cd properties
$ tree .
├── properties
│ ├── __init__.py
│ ├── items.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ └── __init__.py
└── scrapy.cfg
2 directories, 6 files

注意,本系列文章的源代码都可以从github上下载

编写爬虫

定义item

编辑items.py文件,在该文件中定义的item并不是一定要在每一个spider中填充,也不是要全部同时使用的,你可以随意添加字段,并且在任何时候填充。

from scrapy.item import Item, Field

class PropertiesItem(Item):
# Primary fields
title = Field()
price = Field()
description = Field()
address = Field()
image_urls = Field() # Calculated fields,这些字段需要运算后才得到,后面的文章会解析,暂时不用管
images = Field()
location = Field() # Housekeeping fields,这些字段用来在调试时显示相关信息
url = Field()
project = Field()
spider = Field()
server = Field()
date = Field()

定义spider

在项目的根目录下根据basic模板创建一个名为basic的spider,后面的web指的是spider的可运行的域名

scrapy genspider –t basic basic web

当然可以自己手写一个spider,但是从模板里创建可以省去不少的时间和减少出错机率,查看其他模板的命令:

scrapy genspider -l

由模板创建的basic.py文件的代码如下

# -*- coding: utf-8 -*-
import scrapy class BasicSpider(scrapy.Spider):
name = "basic"
allowed_domains = ["web"]
start_urls = (
'http://www.web/',
) def parse(self, response):
pass

把抓取到的网页存入item中(文件名:basic.py)

import scrapy
from properties.items import PropertiesItem
class BasicSpider(scrapy.Spider):
name = "basic"
allowed_domains = ["web"]
start_urls = (
'http://web:9312/properties/property_000000.html',
)
def parse(self, response):
item = PropertiesItem()
item['title'] = response.xpath(
'//*[@itemprop="name"][1]/text()').extract()
item['price'] = response.xpath(
'//*[@itemprop="price"][1]/text()').re('[.0-9]+')
item['description'] = response.xpath(
'//*[@itemprop="description"][1]/text()').extract()
item['address'] = response.xpath(
'//*[@itemtype="http://schema.org/'
'Place"][1]/text()').extract()
item['image_urls'] = response.xpath(
'//*[@itemprop="image"][1]/@src').extract()
return item

启动爬虫后,看到控制台输出如下信息,说明爬取成功

$scrapy crawl basic
DEBUG: Scraped from <200 http://...000.html>
{'address': [u'Angel, London'],
'description': [u'website ... offered'],
'image_urls': [u'../images/i01.jpg'],
'price': [u'334.39'],
'title': [u'set unique family well']}

将上面的输出保持到各种文件中:

scrapy crawl basic –o item.json
scrapy crawl basic –o item.jl
#json格式的文件会把整个json对象保存在一个巨大的数组里,意味着如果你要保存的数据量有1GB,那么在你解析这些数据之前,就必须用1GB的内存来保存整个文件。而jl格式会在每一行上放一个json对象,所以读取起来效率会更高 scrapy crawl basic –o item.xml
scrapy crawl basic –o item.csv
scrapy crawl basic –o ftp://user:pass@ftp.scrapybook.com/items.json 直接保存到ftp上

ItemLoader

对于上面混乱且难看的parse函数,可以使用Item Loader来处理,并且Item Loader提供更多的功能(http://doc.scrapy.org/en/latest/topics/loaders.html),最重要的是能够对通过xpath提取出来的信息进行处理,譬如去掉空格和替换字符等,然后将清洗后的数据再写入item中。对数据的清洗是通过processor来实现的,很常用的一个processor就是MapCompose()函数,该函数将python函数或者lambda表达式作为参数(参数个数无限制),然后按顺序执行这些函数来产生最终的结果。譬如MapCompose(unicode.strip, float)首先将xpath提取的信息去掉空格,再将其转换为float格式

basic.py源代码文件:

https://github.com/Kylinlin/scrapybook/blob/master/ch03%2Fproperties%2Fproperties%2Fspiders%2Fbasic.py

修改上面的basic.py文件,使得代码更加简洁和一目了然

import datetime
import urlparse
import socket
import scrapy from scrapy.loader.processors import MapCompose, Join
from scrapy.loader import ItemLoader from properties.items import PropertiesItem class BasicSpider(scrapy.Spider):
name = "basic"
allowed_domains = ["web"] # Start on a property page
start_urls = (
'http://web:9312/properties/property_000000.html',
) def parse(self, response):
""" This function parses a property page. @url http://web:9312/properties/property_000000.html
@returns items 1
@scrapes title price description address image_urls
@scrapes url project spider server date
""" # Create the loader using the response
l = ItemLoader(item=PropertiesItem(), response=response) # Load fields using XPath expressions
l.add_xpath('title', '//*[@itemprop="name"][1]/text()',
MapCompose(unicode.strip, unicode.title))
l.add_xpath('price', './/*[@itemprop="price"][1]/text()',
MapCompose(lambda i: i.replace(',', ''), float),
re='[,.0-9]+')
l.add_xpath('description', '//*[@itemprop="description"][1]/text()',
MapCompose(unicode.strip), Join())
l.add_xpath('address',
'//*[@itemtype="http://schema.org/Place"][1]/text()',
MapCompose(unicode.strip))
l.add_xpath('image_urls', '//*[@itemprop="image"][1]/@src',
MapCompose(lambda i: urlparse.urljoin(response.url, i))) # Housekeeping fields 可以通过add_value函数直接向item填充数据
l.add_value('url', response.url)
l.add_value('project', self.settings.get('BOT_NAME'))
l.add_value('spider', self.name)
l.add_value('server', socket.gethostname())
l.add_value('date', datetime.datetime.now()) return l.load_item()

注意在上面的parse函数中有这样的一段注释

""" This function parses a property page.

        @url http://web:9312/properties/property_000000.html
@returns items 1
@scrapes title price description address image_urls
@scrapes url project spider server date
"""

这些以@开头的称为contract,类似于单元测试,假如你在一个月前写了这个spider,现在想测试这个spider是否仍然正确运行,就可以使用这些contract。上面的这些contract的意思是:检查该url,你应该得到一个包含了下面列出来的字段的item

运行scrapy check来检查contract

$ scrapy check basic
----------------------------------------------------------------
Ran 3 contracts in 1.640s
OK

如果spider的代码出错了,或者xpath表达式已经过期了(网站发生了更新),那么就会得到测试失败的结果,虽然出错信息并不详尽,但这是最快的检查手段

Spider的运行原理

在上面用模板定义的spider十一个用来爬取特定网页的类,包括了如何执行爬取动作(譬如如何跟踪超链接)和如何从页面中提取信息。换句话说,spider就是你用来定义对某个特定网站的爬取动作的工具,他的爬取循环类似于这样:

1、 首先要将你指定的初始URL封装成Request对象,并且要指定在网页返回该请求的内容后应该用哪个函数来处理网页的内容。

默认情况下,会调用start_requests()函数,对start_urls中的URL分别生成一个Request对象,并且指定parse()函数作为回调函数(回调函数指的是callback变量指定的函数)

2、 在回调函数中,可以处理response变量,然后返回一个已经提取好数据的字典或者是一个Item对象,或者是Request对象(在这个Request对象中,也可以指定一个回调函数,同样地,处理完这个Request之后生成的response就会传送到回调函数中处理)

3、 在回调函数中,也可以提取网页内容,通常使用Selector(也可以使用BeautifulSoup,lxml或者其他你熟悉的机制)来生成包含了解析数据的item

4、 最后,这些从spider中返回的item通常会存入到数据库中,或者写入到文件中

即使上述流程适用于大部分的spider,但是仍然有不同的spider运行不同的默认流程,更多的信息就查阅这里:

http://doc.scrapy.org/en/1.0/topics/spiders.html?highlight=start_request#scrapy.spiders.Spider.start_requests

Learning Scrapy笔记(三)- Scrapy基础的更多相关文章

  1. 学习笔记三:基础篇Linux基础

    Linux基础 直接选择排序>快速排序>基数排序>归并排序 >堆排序>Shell排序>冒泡排序=冒泡排序2 =直接插入排序 一.Linux磁盘分区表示 Linux中 ...

  2. Java基础学习笔记三 Java基础语法

    Scanner类 Scanner类属于引用数据类型,先了解下引用数据类型. 引用数据类型的使用 与定义基本数据类型变量不同,引用数据类型的变量定义及赋值有一个相对固定的步骤或格式. 数据类型 变量名 ...

  3. deep learning 学习笔记(三) 线性回归学习速率优化寻找

    继续学习http://www.cnblogs.com/tornadomeet/archive/2013/03/15/2962116.html,上一节课学习速率是固定的,而这里我们的目的是找到一个比较好 ...

  4. Learning Scrapy笔记(六)- Scrapy处理JSON API和AJAX页面

    摘要:介绍了使用Scrapy处理JSON API和AJAX页面的方法 有时候,你会发现你要爬取的页面并不存在HTML源码,譬如,在浏览器打开http://localhost:9312/static/, ...

  5. Learning Scrapy笔记(零) - 前言

    我已经使用了scrapy有半年之多,但是却一直都感觉没有入门,网上关于scrapy的文章简直少得可怜,而官网上的文档(http://doc.scrapy.org/en/1.0/index.html)对 ...

  6. scrapy爬虫笔记(三)------写入源文件的爬取

    开始爬取网页:(2)写入源文件的爬取 为了使代码易于修改,更清晰高效的爬取网页,我们将代码写入源文件进行爬取. 主要分为以下几个步骤: 一.使用scrapy创建爬虫框架: 二.修改并编写源代码,确定我 ...

  7. scrapy学习笔记(三):使用item与pipeline保存数据

    scrapy下使用item才是正经方法.在item中定义需要保存的内容,然后在pipeline处理item,爬虫流程就成了这样: 抓取 --> 按item规则收集需要数据 -->使用pip ...

  8. 爬虫(九)scrapy框架简介和基础应用

    概要 scrapy框架介绍 环境安装 基础使用 一.什么是Scrapy? Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍.所谓的框架就是一个已经被集成了各种功能 ...

  9. 10.scrapy框架简介和基础应用

    今日概要 scrapy框架介绍 环境安装 基础使用 今日详情 一.什么是Scrapy? Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍.所谓的框架就是一个已经被 ...

随机推荐

  1. ORA-04031 With Leak in "OBJ STAT MEMO" Allocations Seen in V$SGASTAT on 10.2.0.5 (文档 ID 1350050.1)

    APPLIES TO: Oracle Server - Enterprise Edition - Version: 10.2.0.5<max_ver> and later   [Relea ...

  2. php实例根据ID删除mysql表中的数据

    在动态网站开发中,我们经常要根据ID删除表中的数据,例如用户删除帖子,就需要根据ID删除帖子.本文章向大家介绍php根据ID删除表中数据的实例,需要的朋友可以参考一下本文章的实例. php实例根据ID ...

  3. 01-事件处理简介/UIView拖拽

    1.ios当中常见的事件?         触摸事件        加速计事件         远程控制事件2.什么是响应者对象?     继承了UIResponds的对象我们称它为响应者对象 UIA ...

  4. VS2010 MSDN配置

    安装VS2010之后总是要装MSDN的,不然写起程序来还真不方便.前段时间换了电脑后,折腾了好久才把VS和MSDN装好,所以为了方便自己和别人特地把配置MSDN的详细步骤写出来: 1.         ...

  5. 问题:glGenBuffers()函数没有定义怎么办

    链接glew.lib库,#include <gl/glew.h>. glew是opengl 的扩展库

  6. 云计算PAAS平台测试设计之镜像管理

    下面是云计算PAAS平台页面概览: 今天我们要讲的是镜像管理页面的测试设计: 可以看到,这个页面主要有增删改查四个功能. 1. 查询镜像 (1)易用性:查看镜像查询界面,界面上各组件设计合理.美观.易 ...

  7. c# 调用 CRFs应用程序

    今天想用C#调用crfs,但是老出问题.原因有几点.第一,我对crf不理解,虽然我用cmd跑了一遍,但是根本不理解为什么,而且只是草草看了下参数该输入什么,只是了解了形式,没有了解实质.所以在调用的时 ...

  8. A+B问题通解_Pascal_C++_Java

    世界不断发展,各种电子设备不断变得更加迷你,代码却越写越长…… A+B Problem Input:Two integer A,B Output:The ans of A+B 1971年,Niklau ...

  9. 紧张:飞测独家のJmeter秘籍,限量发放(续篇2)

    飞测说:一些朋友问,我如何使用获取资料(点击这里获取)?小怪我花了点时间在这里介绍下该资料的功能和意义,另外也整理了一篇操作指引文档. 1.fiddler导出jmx格式的dll文件V4.0版本 功能: ...

  10. Flash Air 打包安卓 ane

    工具: 1.flash builder 2.adt打包工具 3.数字证书 一. 创建 jar 文件 1. 打开flash builder, 新建一个java 项目. 2.点击项目属性,选择Java构建 ...