官方文档 https://docs.scrapy.org/en/latest/topics/spiders.html#crawlspider
CrawlSpider定义了一组用以提取链接的规则,可以大大简化爬虫的写法。
rules
是一组Rule
对象。每条Rule
定义了抓取网页的方式。如果多条规则匹配到同一链接,根据定义规则的顺序,使用第一个链接。
parse_start_url(response)
用来处理start_urls
的响应,返回的结果必须是Item
对象,或Request
对象,或者是二者的可迭代对象。
爬取规则
Rule
的用法
scrapy.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
link_extractor
是链接抽取对象,它定义了如何抽取链接;
callback
是调回函数,注意不要使用parse
做调回函数;
cb_kwargs
是一个字典,可以将关键字参数传给调回函数;
follow
是一个布尔值,指定要不要抓取链接。如果callback
是None,则follow
默认是True
,否则默认为False
;
process_links
可以对link_extractor
提取出来的链接做处理,主要用于过滤;
process_request
是一个可调用函数,会处理这条Rule提取出来的每个请求,会返回request或None。
链接抽取
link_extractor
的用法
from scrapy.linkextractors import LinkExtractor
因为用法和LxmlLinkExtractor
相同,官网使用后者说明,LxmlLinkExtractor
是基于lxml的HTMLParser实现的:
class scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths=(), restrict_css=(), tags=('a', 'area'), attrs=('href', ), canonicalize=False, unique=True, process_value=None, strip=True)
allow
:(一个或一个列表)出链必须要匹配的正则表达式。如果allow为空,则匹配所有链接;
deny
:(一个或一个列表)出链必须要匹配的正则表达式,以做排除。优先于allow
。如果为空,则不排除任何链接;
allow_domains
:(一个或一个列表)提取链接的域名;
deny_domains
:(一个或一个列表)不提取链接的域名;
deny_extensions
:(一个或一个列表)要忽略的后缀,如果为空,则为包scrapy.linkextractors
中的列表IGNORED_EXTENSIONS
,如下所示:
IGNORED_EXTENSIONS = [ # 图片 'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif', 'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg', # 音频 'mp3', 'wma', 'ogg', 'wav', 'ra', 'aac', 'mid', 'au', 'aiff', # 视频 '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv', 'm4a', 'm4v', 'flv', # 办公软件 'xls', 'xlsx', 'ppt', 'pptx', 'pps', 'doc', 'docx', 'odt', 'ods', 'odg', 'odp', # 其它 'css', 'pdf', 'exe', 'bin', 'rss', 'zip', 'rar', ]
restrict_xpaths
:(一个或一个列表)xpath,定义了从响应文本的哪部分提取链接;
restrict_css
:(一个或一个列表)css,定义了从响应文本的哪部分提取链接;
tags
:(一个或一个列表)用以抽取链接的标签,默认是('a', 'area')
;
attrs
:(一个或一个列表)属性,定义了从响应文本的哪部分提取链接,默认是('href',)
;
canonicalize
:(布尔值)建议设为False;
unique
:(布尔值)是否过滤重复链接;
process_value
:(可调用对象)可以对标签和属性扫描结果做修改,下面是官网给的例子;
# 一个要提取的链接 <a href="javascript:goToPage('../other/page.html'); return false">Link text</a> # 要提取的是 “../other/page.html” def process_value(value): m = re.search("javascript:goToPage\('(.*?)'", value) if m: return m.group(1)
strip
:(布尔值)默认开启。
官网给的CrawlSpider的例子:
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') # 没有设置callback,则默认follow=True,继续抓取符合该条规则的所有链接 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
感觉还是xpath更好用,还是用麦田租房举例子:http://bj.maitian.cn/zfall/PG1
这样写规则就行了
rules = ( Rule(LinkExtractor(restrict_xpaths='//*[contains(@class,"down_page")]')), Rule(LinkExtractor(restrict_xpaths='//div[@class="list_title"]/h1/'), callback='parse_item') )