python 高级爬虫_运维学python之爬虫高级篇(三)spider和items介绍

1 spiders

spiders是一个类,定义了如何去爬取一个网站(或一组网站),包括如何执行(跟踪链接)以及如何从他们的页面中提取结构化数据(例如抓取项目),换句话说,spiders是定义为特定站点爬取和解析页面的定制行为(或者,在某些情况下,是一组站点的定制行为)。

对于spiders来说,爬取的流程是这样的:

1.首先生成初始请求,以抓取第一个url,然后指定一个回调函数,并使用从这些请求下载的response作为参数调用;要执行的第一个请求是通过调用startr_request()方法获得的,该方法(默认情况下)为start_url中指定的url生成request,然后通过parse方法回调;

2.在回调函数中,parse方法解析response(web页面),并使用提取的数据、Item对象、request对象或这些对象的迭代对象。这些请求也将包含一个回调(可能是相同的),然后由Scrapy下载,然后由指定的回调处理;

3.在回调函数中,你可以使用 Selectors(也可以使用BeautifulSoup, lxml或其它你熟悉的方式)解析数据,并生成解析后的结果Items;

4.最后,从spiders返回的条目通常会持久化到数据库中(使用 Item Pipeline),或者使用Feed exports将其写入到文件中。

尽管这个流程适合于所有的spider,但是Scrapy里面为不同的使用目的实现了一些常见的Spider。下面我们把它们列出来。

1.2 基础spider

scrapy.Spider

class scrapy.spiders.Spider

这是最简单的爬虫,也是所有其他爬虫必须继承的(包括与scrapy捆绑在一起的爬虫,以及你自己编写的爬虫)。它没有提供任何特殊的功能。它只提供了一个默认的start_request()方法,它从start_urls的爬虫属性中发送请求,并为每个结果的响应调用parse解析。

常用属性和方法如下表:

名称

含义

name

spider必须要写明的属性,而且在整个项目中要唯一。

allowed_domains

一个可选的字符串列表,其中包含该爬行器允许爬行的域名,如果启用了offsiteMidware,不属于这个列表中指定的域名(或它们的子域)的请求将不会被跟踪。

start_urls

当没有指定特定的url时,将开始爬取的url列表。

start_requests()

这个方法必须返回一个可遍历的第一个请求,以便为这个spider爬取。

parse(response)

当它们的请求没有指定回调时的默认回调,用于处理下载的response

1.3 通用spider

scrapy附带了一些有用的通用spider,你可以用它来子类化你的蜘蛛spider。它们的目的是为一些常见的抓取案例提供方便的功能,比如根据某个规则跟踪站点上的所有链接,从站点地图爬行,或者解析xml/csv。

CrawlSpider

class scrapy.spiders.CrawlSpider

这是爬行有规则网站最常用的spider,因为它通过定义一组规则提供了一种方便的机制来跟踪链接,除了继承了spider的属性外,CrawlSpider提供了一个特殊的rule属性,rule是一个(或多个)规则对象的列表,每个规则都定义了爬行站点的特定行为,如果多个规则匹配相同的链接,那么第一个规则将根据该属性中定义的顺序使用。

示例如下:

import scrapy

from scrapy.spiders import CrawlSpider, Rule

from scrapy.linkextractors import LinkExtractor

class MySpider(CrawlSpider):

name = 'example.com'

allowed_domains = ['example.com']

start_urls = ['http://www.example.com']

rules = (

# 提取链接匹配'category.php' (但是不匹配 'subsection.php')

# 如果没有指定默认回调函数则按默认方式递归执行.

Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),

# 提取链接匹配 'item.php' 并且通过parse_item解析

Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),

)

def parse_item(self, response):

self.logger.info('Hi, this is an item page! %s', response.url)

item = scrapy.Item()

item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')

item['name'] = response.xpath('//td[@id="item_name"]/text()').extract()

item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()

return item

XMLFeedSpider

class scrapy.spiders.XMLFeedSpider

XMLFeedSpider是为解析XML而设计的,方法是通过一个特定的节点名对其进行遍历。迭代器可以从iternodes, xml, and html中选择。出于性能的考虑,建议使用iternodes迭代器,因为xml和html迭代器一次生成整个DOM,以便解析它。但是,使用html作为迭代器在解析XML时可能很有用。

代码示例如下:

from scrapy.spiders import XMLFeedSpider

from myproject.items import TestItem

class MySpider(XMLFeedSpider):

name = 'example.com'

allowed_domains = ['example.com']

start_urls = ['http://www.example.com/feed.xml']

# 这实际上是不必要的,因为它是默认值

iterator = 'iternodes'

itertag = 'item'

def parse_node(self, response, node):

self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.extract()))

item = TestItem()

item['id'] = node.xpath('@id').extract()

item['name'] = node.xpath('name').extract()

item['description'] = node.xpath('description').extract()

return item

基本上,我们所做的就是创建一个从给定的start_url中下载提要的spider,然后遍历每个条目标记,将它们打印出来,并在一个条目中存储一些随机的数据。

CSVFeedSpider

class scrapy.spiders.CSVFeedSpider

这个爬行器与xmlfeed非常相似,只是它遍历了行,而不是节点。每次迭代中调用的方法都是parse_row()。

示例代码:

from scrapy.spiders import CSVFeedSpider

from myproject.items import TestItem

class MySpider(CSVFeedSpider):

name = 'example.com'

allowed_domains = ['example.com']

start_urls = ['http://www.example.com/feed.csv']

delimiter = ';'

quotechar = "'"

headers = ['id', 'name', 'description']

def parse_row(self, response, row):

self.logger.info('Hi, this is a row!: %r', row)

item = TestItem()

item['id'] = row['id']

item['name'] = row['name']

item['description'] = row['description']

return item

2 Items

爬虫爬取的主要目标是从非结构化数据源中提取结构化数据,通常是web页面。作为Python语言,Scrapy spiders可以返回提取的数据。虽然方便而又熟悉,但Python却缺乏结构,特别是在一个包含许多spider的大型项目中在字段名中输入错误或返回不一致的数据。

为了定义常见的输出数据格式,scrapy提供了item类,Item对象是用来收集提取数据的简单容器。它们提供了一个类似于字典的API,提供了一种方便的语法,用于声明可用字段。

各种各样的scrapy组件使用由item提供的附加信息,查看已声明的字段,以找出导出的列,可以使用item字段元数据定制序列化,trackref跟踪项目实例以帮助发现内存泄漏。

1.2 定义Item

Item使用简单的类定义语法和字段对象声明。见下面例子:

import scrapy

class Product(scrapy.Item):

name = scrapy.Field()

price = scrapy.Field()

stock = scrapy.Field()

last_updated = scrapy.Field(serializer=str)

字段类型就是简单的scrapy.Field.

1.3 Item Fields

Field对象用于为每个字段指定元数据,上面列子中的serializer函数就说明了这一点。

您可以为每个字段指定任何类型的元数据,对Field对象的值没有限制。需要注意的是,用于声明该项的字段对象不会被分配为类属性。相反,可以通过Item.fields访问它们。

1.4 使用Item

下面是一些与项目一起执行的常见任务的例子,使用上面声明的产品项目。您会注意到这个API非常类似于API。

1.4.1 创建items

# 注意要先创建上面例子中的Product类

>>> product = Product(name='Desktop PC', price=1000)

>>> print product

Product(name='Desktop PC', price=1000)

1.4.2 获取Field值

>>> product['name']

Desktop PC

>>> product.get('name')

Desktop PC

>>> product['price']

1000

>>> product['last_updated']

Traceback (most recent call last):

...

KeyError: 'last_updated'

>>> product.get('last_updated', 'not set')

not set

>>> product['lala'] # getting unknown field

Traceback (most recent call last):

...

KeyError: 'lala'

>>> product.get('lala', 'unknown field')

'unknown field'

>>> 'name' in product

True

>>> 'last_updated' in product

False

>>> 'last_updated' in product.fields

True

>>> 'lala' in product.fields

False

1.4.3 设置Field值

>>> product['last_updated'] = 'today'

>>> product['last_updated']

today

>>> product['lala'] = 'test' # setting unknown field

Traceback (most recent call last):

...

KeyError: 'Product does not support field: lala'

1.4.4 获取所有内容

要获取所有内容,跟字典操作相同,如下:

>>> product.keys()

['price', 'name']

>>> product.items()

[('price', 1000), ('name', 'Desktop PC')]

1.4.5 其它常见命令

复制items

>>> product2 = Product(product)

>>> print product2

Product(name='Desktop PC', price=1000)

>>> product3 = product2.copy()

>>> print product3

Product(name='Desktop PC', price=1000)

从items创建字典

>>> dict(product) # create a dict from all populated values

{'price': 1000, 'name': 'Desktop PC'}

从字典创建items

>>> Product({'name': 'Laptop PC', 'price': 1500})

Product(price=1500, name='Laptop PC')

>>> Product({'name': 'Laptop PC', 'lala': 1500}) # warning: unknown field in dict

Traceback (most recent call last):

...

KeyError: 'Product does not support field: lala'

这篇主要让大家先了解scrapy的各部分概念及基本用法,后续实战项目时我们再来回头看,会更容易懂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值