Scrapy的CrawlSpider用法

网络爬虫

浏览数:168

2019-11-1

AD:资源代下载服务

官方文档
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')
)

作者:SeanCheney