(三) Spider
Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类。
其包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item 的方法。
Spider的创建
为了创建一个Spider,您必须继承 scrapy.Spider
类, 且定义以下三个属性:
-
name
: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。 -
start_urls
: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。 -
parse()
是spider的一个方法。 被调用时,每个初始URL完成下载后生成的Response
对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的Request
对象。
Spider示例
示例1:
import scrapy
class MySpider(scrapy.Spider):
name = '[example.com](http://example.com/)'
allowed_domains = ['[example.com](http://example.com/)']
start_urls = [
'[http://www.example.com/1.html](http://www.example.com/1.html)',
'[http://www.example.com/2.html](http://www.example.com/2.html)',
'[http://www.example.com/3.html](http://www.example.com/3.html)',
]
def parse(self, response):
self.log('A response from %s just arrived!' % response.url)
示例2:
import scrapy
from myproject.items import MyItem
class MySpider(scrapy.Spider):
name = '[example.com](http://example.com/)'
allowed_domains = ['[example.com](http://example.com/)']
start_urls = [
'[http://www.example.com/1.html](http://www.example.com/1.html)',
'[http://www.example.com/2.html](http://www.example.com/2.html)',
'[http://www.example.com/3.html](http://www.example.com/3.html)',
]
def parse(self, response):
sel = scrapy.Selector(response)
for h3 in response.xpath('//h3').extract():
yield MyItem(title=h3)
for url in response.xpath('//a/@href').extract():
yield scrapy.Request(url, callback=self.parse)
Spider的业务循环
对spider来说,爬取的循环类似下文:
-
以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。
spider中初始的request是通过调用
start_requests()
来获取的。start_requests()
读取start_urls
中的URL, 并以parse
为回调函数生成Request
。 在回调函数内分析返回的(网页)内容,返回
Item
对象或者Request
或者一个包括二者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。
最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。
虽然该循环对任何类型的spider都(多少)适用,但Scrapy仍然为了不同的需求提供了多种默认spider。
Spider类其他属性方法
allowed_domains
可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware
启用时, 域名不在列表中的URL不会被跟进。
start_requests()
该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request。
当spider启动爬取并且未制定URL时,该方法被调用。 当指定了URL时,make_requests_from_url()
将被调用来创建Request对象。 该方法仅仅会被Scrapy调用一次,因此您可以将其实现为生成器。
该方法的默认实现是使用 start_urls
的url生成Request。
如果您想要修改最初爬取某个网站的Request对象,您可以重写(override)该方法。 例如,如果您需要在启动时以POST登录某个网站,你可以这么写:
def start_requests(self):
return [scrapy.FormRequest("[http://www.example.com/login](http://www.example.com/login)",
formdata={'user': 'john', 'pass': 'secret'},
callback=self.logged_in)]
def logged_in(self, response):
# here you would extract links to follow and return Requests for
# each of them, with another callback
pass
make_requests_from_url(url)
该方法接受一个URL并返回用于爬取的 Request
对象。 该方法在初始化request时被 start_requests()
调用,也被用于转化url为request。
默认未被复写(overridden)的情况下,该方法返回的Request对象中, parse()
作为回调函数,dont_filter参数也被设置为开启。 (详情参见 Request
).
closed(reason)
当spider关闭时,该函数被调用。 该方法提供了一个替代调用signals.connect()来监听 spider_closed
信号的快捷方式。
Spider子类
CrawlSpider
class scrapy.contrib.spiders.CrawlSpider
爬取一般网站常用的spider。其定义了一些规则(rule)来提供跟进link的方便的机制。 也许该spider并不是完全适合您的特定网站或项目,但其对很多情况都使用。 因此您可以以其为起点,根据需求修改部分方法。当然您也可以实现自己的spider。
XMLFeedSpider
class scrapy.contrib.spiders.XMLFeedSpider
XMLFeedSpider被设计用于通过迭代各个节点来分析XML源(XML feed)。 迭代器可以从 iternodes , xml , html 选择。 鉴于 xml 以及 html 迭代器需要先读取所有DOM再分析而引起的性能问题, 一般还是推荐使用 iternodes 。 不过使用 html 作为迭代器能有效应对错误的XML。
CSVFeedSpider
class scrapy.contrib.spiders.CSVFeedSpider
该spider除了其按行遍历而不是节点之外其他和XMLFeedSpider十分类似。 而其在每次迭代时调用的是 parse_row()
。
SitemapSpider
class scrapy.contrib.spiders.SitemapSpider
SitemapSpider使您爬取网站时可以通过 Sitemaps 来发现爬取的URL。
其支持嵌套的sitemap,并能从 robots.txt 中获取sitemap的url。
下一篇: day15