CrawlSpider
、LinkExtractors
、Rule
是scrapy
框架中的类,其中CrawlSpider
是Spider
的派生类,具有更多的方法和功能,LinkExtractor
类是用作提取链接的,Rule
表示的是爬取的规则。
CrawlSpider
是Spider
的派生类,Spider
类的设计原则是只爬取start_urls
中的url
,而CrawlSpider
类定义了一些规则(rules
)来提供跟进链接(link
)的方便机制,从爬取的网页中获取link
并继续爬取的工作更适合。
CrawlSpider除了Spider继承过来的属性外,还提供了一个新的属性:
rules
包含一个或多个Rule
对象的集合。每个Rule
对爬取网站的动作定义了特定规则。Rule
对象会在下面介绍。
如果多个Rule
匹配了相同的链接,则根据他们在本属性中被定义的顺序,第一个会被使用。
CrawlSpider也提供了一个可复写的方法:
parse_start_url(response)
当start_url的请求返回时,该方法被调用。该方法分析最初的返回值并必须返回一个Item
对象或一个Request
对象或者一个可迭代的包含二者的对象
当编写爬虫规则时,请避免使用parse
作为回调函数。 由于CrawlSpider
使用parse
方法来实现其逻辑,如果 您覆盖了parse
方法,CrawlSpider
将会运行失败。
class scrapy.linkextractors.LinkExtractor
LinkExtractor
是从网页(scrapy.http.Response
)中抽取会被follow
的链接的对象。
LinkExtractor
在CrawlSpider
类(在Scrapy
可用)中使用, 通过一套规则,但你也可以用它在你的Spider
中,即使你不是从CrawlSpider
继承的子类, 因为它的目的很简单: 提取链接。
每个LinkExtractor有唯一的公共方法是 extract_links(),它接收一个 Response 对象,并返回一个 scrapy.link.Link 对象。
Link Extractors要实例化一次,并且 extract_links 方法会根据不同的 response 调用多次提取链接。
class scrapy.linkextractors.LinkExtractor(
allow = (),
deny = (),
allow_domains = (),
deny_domains = (),
deny_extensions = None,
restrict_xpaths = (),
tags = ('a','area'),
attrs = ('href'),
canonicalize = True,
unique = True,
process_value = None
)
主要参数:
allow
:满足括号中”正则表达式”的值会被提取,如果为空,则全部匹配。
deny
:与这个正则表达式(或正则表达式列表)不匹配的url一定不提取
allow_domains
:会被提取的连接的domains
deny_domains
:一定不会被提取链接的domains。
restrict_xpaths
:使用xpath表达式,和allow共同作用过滤链接。
Rule
对象是一个爬取规则的类。
其类的定义如下:
class scrapy.contrib.spiders.Rule(link_extractor,callback=None,cb_kwargs=None,follow=None,process_links=None,process_request=None)
link_extractor
:是一个Link Extractor对象。其定义了如何从爬取到的页面提取链接。
callback
:是一个callable
或string
(该Spider
中同名的函数将会被调用)。从link_extractor
中每获取到链接时将会调用该函数。该回调函数接收一个response
作为其第一个参数,并返回一个包含Item
以及Request
对象(或者这两者的子类)的列表。
cb_kwargs
:包含传递给回调函数的参数(keyword argument)的字典。
follow
:是一个boolean
值,指定了根据该规则从response
提取的链接是否需要跟进。如果callback
为None
,follow
默认设置True
,否则默认False
。
process_links
:是一个callable
或string
(该Spider
中同名的函数将会被调用)。从link_extrator
中获取到链接列表时将会调用该函数。该方法主要是用来过滤。
process_request
:是一个callable
或string
(该spider
中同名的函数都将会被调用)。该规则提取到的每个request
时都会调用该函数。该函数必须返回一个request
或者None
。用来过滤request
。
CrawlSpider以58租房 上海
为例,爬取的数据有标题,房子,地址,价格等
。具体看下面代码:
在项目的父目录创建项目,执行如下命令:
scrapy startproject zufang58
在items.py
创建一个Item,默认会创建一个ZufangItem
类,在ZufangItem
类中定义字段
import scrapy
class Zufang58Item(scrapy.Item):
# 标题
title = scrapy.Field()
# 房间
room = scrapy.Field()
# 区域
zone = scrapy.Field()
# 地址
address = scrapy.Field()
# 价格
money = scrapy.Field()
# 发布信息的类型,品牌公寓,经纪人,个人
type = scrapy.Field()
在spiders目录创建一个zufang58_spider.py
文件,在文件中定义一个名为ZuFang58Spider
继承CrawlSpider
,代码如下。
from scrapy.spider import CrawlSpider, Rule
from scrapy.linkextractor import LinkExtractor
from zufang58.items import Zufang58Item
class ZuFang58Spider(CrawlSpider):
# spider的唯一名称
name = 'zufang58'
# 开始爬取的url
start_urls = ["http://sh.58.com/chuzu/"]
# 从页面需要提取的url 链接(link)
links = LinkExtractor(allow="sh.58.com/chuzu/pn\d+")
# 设置解析link的规则,callback是指解析link返回的响应数据的的方法
rules = [Rule(link_extractor=links, callback="parseContent", follow=True)]
def parseContent(self, response):
"""
解析响应的数据,获取需要的数据字段
:param response: 响应的数据
:return:
"""
# 根节点 //ul[@class="listUl"]/li[@logr]
# title: .//div[@class="des"]/h2/a/text()
# room: .//div[@class="des"]/p[@class="room"]/text()
# zone: .//div[@class="des"]/p[@class="add"]/a[1]/text()
# address: .//div[@class="des"]/p[@class="add"]/a[last()]/text()
# money: .//div[@class="money"]/b/text()
# type: # .//div[@class="des"]/p[last()]/@class # 如果是add,room .//div[@class="des"]/div[@class="jjr"]/@class
for element in response.xpath('//ul[@class="listUl"]/li[@logr]'):
title = element.xpath('.//div[@class="des"]/h2/a/text()')[0].extract().strip()
room = element.xpath('.//div[@class="des"]/p[@class="room"]')[0].extract()
zone = element.xpath('.//div[@class="des"]/p[@class="add"]/a[1]/text()')[0].extract()
address = element.xpath('.//div[@class="des"]/p[@class="add"]/a[last()]/text()')[0].extract()
money = element.xpath('.//div[@class="money"]/b/text()')[0].extract()
type = element.xpath('.//div[@class="des"]/p[last()]/@class')[0].extract()
if type == "add" or type == "room":
type = element.xpath('.//div[@class="des"]/div[@class="jjr"]/@class')[0].extract()
item = Zufang58Item()
item['title'] = title
item['room'] = room
item['zone'] = zone
item['address'] = address
item['money'] = money
item['type'] = type
yield item
在pipeline.py文件中,创建Zufang58Pipeline
类,实现process_item()
方法。如:
class Zufang58Pipeline(object):
def __init__(self):
self.file = open('zufang58.json', mode='w', encoding='utf-8')
def process_item(self, item, spider):
jsondata = json.dumps(dict(item), ensure_ascii=False) + "\n"
self.file.write(jsondata)
return item
def close_spider(self, spider):
self.file.close()
DEFAULT_REQUEST_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
...
ITEM_PIPELINES = {
'zufang58.pipelines.Zufang58Pipeline': 300,
}
scrapy crawl zufang58
我们可以在控制台中可以看到有很多的log输出。如果我们想把log保存到文件。可以在setting.py配置。
Scrapy
提供5层logging
级别:
CRITICAL
:严重错误(critical)ERROR
:一般错误(regular errors)WARNING
:警告信息(warning messages)INFO
:一般信息(informational messages)DEBUG
: 调试信息(debugging messages) 通过在setting.py
中进行以下设置可以被用来配置logging
:
LOG_ENABLED
默认: True
,启用loggingLOG_ENCODING
默认: utf-8
,logging使用的编码LOG_FILE
默认: None
,在当前目录里创建logging输出文件的文件名LOG_LEVEL
默认: DEBUG
,log的最低级别LOG_STDOUT
默认: False
,如果为 True,进程所有的标准输出(及错误)将会被重定向到log中。例如,执行 print “hello” ,其将会在Scrapy log中显示。在settings.py配置logging
LOG_FILE = 'zufang58.log'
LOG_LEVEL = 'DEBUG'
就可以将log输出到zufang58.log
文件中。