Scrapy学习笔记-Scrapy入门Spiders

Spiders是定义如何爬取某个站点(或一组站点)的类,包括如何执行爬网(即跟踪链接)以及如何从其页面中提取结构化数据(即抓取项)。 换句话说,Spider是您定义自定义行为的地方,该行为用于爬网和解析特定站点(或在某些情况下为一组站点)的页面。

对于spiders,抓取周期经历如下过程:

  1. 首先,生成初始请求以爬网第一个URL,然后指定要调用的回调函数,并从这些请求中下载响应。要执行的第一个请求是通过调用start_requests方法获得的,该方法(默认情况下)生成对start_urls中指定的URL的请求,并使用parse方法作为Requests的回调函数。
  2. 在回调函数中,您解析响应(网页)并返回包含提取数据的字典,Item对象,Request对象或这些对象的可迭代对象。这些请求还将包含一个回调(可能相同),然后由Scrapy下载,然后由指定的回调处理响应。
  3. 在回调函数中,通常使用选择器(但也可以使用BeautifulSoup,lxml或您喜欢的任何机制)来解析页面内容,并使用已解析的数据生成项目。
  4. 最后,通常将从蜘蛛返回的项目保存到数据库(在某些项目管道中)或使用Feed导出写入文件。
    即使这个周期(或多或少)适用于任何种类的蜘蛛,Scrapy中还是捆绑了不同种类的默认蜘蛛以用于不同目的。我们将在这里讨论这些类型。

scrapy.Spider

"""
Base class for Scrapy spiders
See documentation in docs/topics/spiders.rst
"""
import logging
import warnings

from scrapy import signals
from scrapy.http import Request
from scrapy.utils.trackref import object_ref
from scrapy.utils.url import url_is_from_spider
from scrapy.utils.deprecate import method_is_overridden

class Spider(object_ref):
    """Base class for scrapy spiders. All spiders must inherit from this
    class.
    """

    name = None
    custom_settings = None

    def __init__(self, name=None, **kwargs):
        if name is not None:
            self.name = name
        elif not getattr(self, 'name', None):
            raise ValueError("%s must have a name" % type(self).__name__)
        self.__dict__.update(kwargs)
        if not hasattr(self, 'start_urls'):
            self.start_urls = []

    @property
    def logger(self):
        logger = logging.getLogger(self.name)
        return logging.LoggerAdapter(logger, {'spider': self})

    def log(self, message, level=logging.DEBUG, **kw):
        """Log the given message at the given log level

        This helper wraps a log call to the logger within the spider, but you
        can use it directly (e.g. Spider.logger.info('msg')) or use any other
        Python logger too.
        """
        self.logger.log(level, message, **kw)


    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = cls(*args, **kwargs)
        spider._set_crawler(crawler)
        return spider


    def _set_crawler(self, crawler):
        self.crawler = crawler
        self.settings = crawler.settings
        crawler.signals.connect(self.close, signals.spider_closed)

    def start_requests(self):
        cls = self.__class__
        if not self.start_urls and hasattr(self, 'start_url'):
            raise AttributeError(
                "Crawling could not start: 'start_urls' not found "
                "or empty (but found 'start_url' attribute instead, "
                "did you miss an 's'?)")
        if method_is_overridden(cls, Spider, 'make_requests_from_url'):
            warnings.warn(
                "Spider.make_requests_from_url method is deprecated; it "
                "won't be called in future Scrapy releases. Please "
                "override Spider.start_requests method instead (see %s.%s)." % (
                    cls.__module__, cls.__name__
                ),
            )
            for url in self.start_urls:
                yield self.make_requests_from_url(url)
        else:
            for url in self.start_urls:
                yield Request(url, dont_filter=True)


    def make_requests_from_url(self, url):
        """ This method is deprecated. """
        return Request(url, dont_filter=True)

    def parse(self, response):
        raise NotImplementedError('{}.parse callback is not defined'.format(self.__class__.__name__))


    @classmethod
    def update_settings(cls, settings):
        settings.setdict(cls.custom_settings or {}, priority='spider')

    @classmethod
    def handles_request(cls, request):
        return url_is_from_spider(request.url, cls)

    @staticmethod
    def close(spider, reason):
        closed = getattr(spider, 'closed', None)
        if callable(closed):
            return closed(reason)

    def __str__(self):
        return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self))

    __repr__ = __str__



# Top-level imports
from scrapy.spiders.crawl import CrawlSpider, Rule  # noqa: F401
from scrapy.spiders.feed import XMLFeedSpider, CSVFeedSpider  # noqa: F401
from scrapy.spiders.sitemap import SitemapSpider  # noqa: F401

这是最简单的spider,也是所有其他蜘蛛都必须继承的蜘蛛(包括与Scrapy捆绑在一起的蜘蛛,以及您自己编写的蜘蛛)。 它不提供任何特殊功能。 它只是提供了默认的start_requests实现,该实现从start_urls蜘蛛属性发送请求,并为每个结果响应调用蜘蛛的方法解析。
name 一个字符串,它定义此蜘蛛的名称。 蜘蛛名称是由Scrapy查找(并实例化)蜘蛛的方式,因此它必须是唯一的。 但是,没有什么可以阻止您实例化同一蜘蛛的一个以上实例。 这是最重要的蜘蛛属性,它是必需的。如果蜘蛛抓取单个域,则通常的做法是使用该域命名蜘蛛,无论有无TLD。 因此,例如,爬网mywebsite.com的蜘蛛通常被称为mywebsite。
allowed_domains 包含此蜘蛛可以爬网的域的字符串的可选列表。 如果启用了OffsiteMiddleware,将不会跟踪对不属于此列表中指定的域名(或其子域)的URL的请求。假设您的目标网址为https://www.example.com/1.html,然后将“ example.com”添加到列表中。
start_urls 未指定特定URL时,爬网程序将开始从其爬网的URL列表。 因此,下载的第一页将是此处列出的页面。 随后的请求将根据起始URL中包含的数据连续生成。
custom_settings 运行此Spider时将从项目范围的配置中覆盖的设置字典。 由于必须在实例化之前更新设置,因此必须将其定义为类属性。有关可用内置设置的列表,请参阅:内置设置参考。
crawler 在初始化该类后,由from_crawler类方法设置此属性,并链接到此Spider实例绑定到的Crawler对象。爬网程序在项目中封装了许多组件以进行单项访问(例如扩展,中间件,信号管理器等)。 请参阅Crawler API进一步了解它们。
settings 运行此蜘蛛的配置。 这是一个“设置”实例,有关此主题的详细介绍,请参见“设置”主题。
logger 使用Spider的名称创建的Python记录器。 您可以使用它通过它发送日志消息,如从Spiders记录日志中所述。

from_crawler(crawler, *args, **kwargs) 这是Scrapy用于创建蜘蛛的类方法。
您可能不需要直接重写此方法,因为默认实现充当__init __方法的代理,并使用给定参数args和命名参数kwargs对其进行调用。不过,此方法会在新实例中设置搜寻器和设置属性,以便以后可以在Spider的代码内对其进行访问。
在这里插入图片描述

start_requests() 此方法必须返回带有第一个Request的Iterable,以对该蜘蛛进行爬网。 当蜘蛛打开进行抓取时,Scrapy会调用它。 Scrapy只调用一次,因此可以安全地将start_requests实现为生成器。默认实现为start_urls中的每个URL生成Request(url,dont_filter = True)。如果要更改用于开始抓取域的请求,则这是一种替代方法。 例如,如果您需要通过使用POST请求登录来开始,则可以执行以下操作:

class MySpider(scrapy.Spider):
    name = 'myspider'

    def start_requests(self):
        return [scrapy.FormRequest("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

parse(response) 当他们的请求未指定回调时,这是Scrapy用于处理已下载响应的默认回调。解析方法负责处理响应,并返回抓取的数据和/或更多要遵循的URL。 其他Requests回调与Spider类具有相同的要求。此方法以及任何其他Request回调都必须返回Request和/或dict或Item对象的可迭代对象。

log(message[, level, component]) 封装程序通过Spider的记录器发送日志消息,并保持向后兼容。 有关更多信息,请参见从蜘蛛记录。

closed(reason) 在蜘蛛关闭时调用。 此方法为spider_closed信号提供了前往signal.connect()的快捷方式。

举例

import scrapy
class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = [
        'http://www.example.com/1.html',
        'http://www.example.com/2.html',
        'http://www.example.com/3.html',
    ]

    def parse(self, response):
        self.logger.info('A response from %s just arrived!', response.url)
import scrapy

class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = [
        'http://www.example.com/1.html',
        'http://www.example.com/2.html',
        'http://www.example.com/3.html',
    ]

    def parse(self, response):
        for h3 in response.xpath('//h3').getall():
            yield {"title": h3}

        for href in response.xpath('//a/@href').getall():
            yield scrapy.Request(response.urljoin(href), self.parse)
import scrapy
from myproject.items import MyItem

class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']

    def start_requests(self):
        yield scrapy.Request('http://www.example.com/1.html', self.parse)
        yield scrapy.Request('http://www.example.com/2.html', self.parse)
        yield scrapy.Request('http://www.example.com/3.html', self.parse)

    def parse(self, response):
        for h3 in response.xpath('//h3').getall():
            yield MyItem(title=h3)

        for href in response.xpath('//a/@href').getall():
            yield scrapy.Request(response.urljoin(href), self.parse)

参数

蜘蛛可以接收修改其行为的参数。 蜘蛛参数的一些常见用法是定义起始URL或将爬网限制为网站的某些部分,但是它们可用于配置蜘蛛的任何功能。蜘蛛参数使用-a选项通过爬网命令传递。 例如:scrapy crawl myspider -a category=electronics
蜘蛛可以在其__init__方法中访问参数:

class MySpider(scrapy.Spider):
    name = 'myspider'

    def __init__(self, category=None, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.start_urls = ['http://www.example.com/categories/%s' % category]
        # ...

默认的__init__方法将采用任何蜘蛛参数,并将其作为属性复制到蜘蛛。 上面的示例也可以编写如下:

import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'

    def start_requests(self):
        yield scrapy.Request('http://www.example.com/categories/%s' % self.category)

请记住,蜘蛛参数只是字符串。 蜘蛛程序不会自行进行任何解析。 如果要从命令行设置start_urls属性,则必须使用ast.literal_eval或json.loads自己将其解析为列表,然后将其设置为属性。 否则,将导致在start_urls字符串(非常常见的python陷阱)上进行迭代,从而导致每个字符都被视为单独的url。

一个有效的用例是设置HttpAuthMiddleware或UserAgentMiddleware所使用的用户代理使用的httpauth凭据:scrapy crawl myspider -a http_user=myuser -a http_pass=mypassword -a user_agent=mybot

蜘蛛参数也可以通过Scrapyd schedule.json API传递

Generic Spiders

Scrapy附带了一些有用的通用蜘蛛,您可以使用它们进行继承。 他们的目的是为一些常见的抓取情况提供便利的功能,例如根据某些规则在网站上跟踪所有链接,从Sitemap进行爬网或解析XML / CSV Feed。
对于以下蜘蛛网中使用的示例,我们假设您有一个在myproject.items模块中声明了TestItem的项目:

import scrapy
class TestItem(scrapy.Item):
    id = scrapy.Field()
    name = scrapy.Field()
    description = scrapy.Field()

CrawlSpider class scrapy.spiders.CrawlSpider

这是用于爬网常规网站的最常用的蜘蛛,因为它通过定义一组规则为跟踪链接提供了一种便捷的机制。 它可能不是最适合您的特定网站或项目的方法,但是它在几种情况下都足够通用,因此您可以从中入手,并根据需要覆盖它以实现更多自定义功能,或者只是实施自己的Spider。

"""
This modules implements the CrawlSpider which is the recommended spider to use
for scraping typical web sites that requires crawling pages.

See documentation in docs/topics/spiders.rst
"""

import copy
import warnings

from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.http import Request, HtmlResponse
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import Spider
from scrapy.utils.python import get_func_args
from scrapy.utils.spider import iterate_spider_output


def _identity(x):
    return x


def _identity_process_request(request, response):
    return request


def _get_method(method, spider):
    if callable(method):
        return method
    elif isinstance(method, str):
        return getattr(spider, method, None)


_default_link_extractor = LinkExtractor()


[docs]class Rule(object):

    def __init__(self, link_extractor=None, callback=None, cb_kwargs=None, follow=None,
                 process_links=None, process_request=None, errback=None):
        self.link_extractor = link_extractor or _default_link_extractor
        self.callback = callback
        self.errback = errback
        self.cb_kwargs = cb_kwargs or {}
        self.process_links = process_links or _identity
        self.process_request = process_request or _identity_process_request
        self.process_request_argcount = None
        self.follow = follow if follow is not None else not callback

    def _compile(self, spider):
        self.callback = _get_method(self.callback, spider)
        self.errback = _get_method(self.errback, spider)
        self.process_links = _get_method(self.process_links, spider)
        self.process_request = _get_method(self.process_request, spider)
        self.process_request_argcount = len(get_func_args(self.process_request))
        if self.process_request_argcount == 1:
            msg = 'Rule.process_request should accept two arguments (request, response), accepting only one is deprecated'
            warnings.warn(msg, category=ScrapyDeprecationWarning, stacklevel=2)

    def _process_request(self, request, response):
        """
        Wrapper around the request processing function to maintain backward
        compatibility with functions that do not take a Response object
        """
        args = [request] if self.process_request_argcount == 1 else [request, response]
        return self.process_request(*args)



[docs]class CrawlSpider(Spider):

    rules = ()

    def __init__(self, *a, **kw):
        super(CrawlSpider, self).__init__(*a, **kw)
        self._compile_rules()

    def parse(self, response):
        return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)

[docs]    def parse_start_url(self, response):
        return []


    def process_results(self, response, results):
        return results

    def _build_request(self, rule_index, link):
        return Request(
            url=link.url,
            callback=self._callback,
            errback=self._errback,
            meta=dict(rule=rule_index, link_text=link.text),
        )

    def _requests_to_follow(self, response):
        if not isinstance(response, HtmlResponse):
            return
        seen = set()
        for rule_index, rule in enumerate(self._rules):
            links = [lnk for lnk in rule.link_extractor.extract_links(response)
                     if lnk not in seen]
            for link in rule.process_links(links):
                seen.add(link)
                request = self._build_request(rule_index, link)
                yield rule._process_request(request, response)

    def _callback(self, response):
        rule = self._rules[response.meta['rule']]
        return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)

    def _errback(self, failure):
        rule = self._rules[failure.request.meta['rule']]
        return self._handle_failure(failure, rule.errback)

    def _parse_response(self, response, callback, cb_kwargs, follow=True):
        if callback:
            cb_res = callback(response, **cb_kwargs) or ()
            cb_res = self.process_results(response, cb_res)
            for request_or_item in iterate_spider_output(cb_res):
                yield request_or_item

        if follow and self._follow_links:
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

    def _handle_failure(self, failure, errback):
        if errback:
            results = errback(failure) or ()
            for request_or_item in iterate_spider_output(results):
                yield request_or_item

    def _compile_rules(self):
        self._rules = []
        for rule in self.rules:
            self._rules.append(copy.copy(rule))
            self._rules[-1]._compile(self)

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(CrawlSpider, cls).from_crawler(crawler, *args, **kwargs)
        spider._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True)
        return spider

除了从Spider继承的属性(必须指定)之外,此类还支持一个新属性:
rules 这是一个(或多个)Rule对象的列表。 每个规则都定义了用于爬网的特定行为。 规则对象如下所述。 如果多个规则与同一链接匹配,则将按照在此属性中定义的顺序使用第一个规则。

classscrapy.spiders.Rule(link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None, errback=None)

link_extractor是一个链接提取器对象,它定义如何从每个已爬网页面提取链接。 每个产生的链接将用于生成一个Request对象,该对象将在其元词典中(在link_text键下)包含链接的文本。 如果省略,将使用不带参数创建的默认链接提取器,从而提取所有链接。
callback是使用指定的链接提取器提取的每个链接所调用的可调用字符串或字符串(在这种情况下,将使用来自该名称的Spider对象的方法)。 此回调将一个Response作为其第一个参数,并且必须返回单个实例或Item,dict和/或Request对象(或其任何子类)的可迭代对象。 如上所述,接收到的Response对象将在其元字典中(在link_text键下)包含生成请求的链接的文本。
编写爬网蜘蛛规则时,请避免将parse用作回调,因为CrawlSpider使用parse解析方法本身来实现其逻辑。 因此,如果您覆盖parse解析方法,则爬网蜘蛛将不再起作用。

cb_kwargs是一个字典,其中包含要传递给回调函数的关键字参数。

follow是一个布尔值,它指定是否应从使用此规则提取的每个响应中跟随链接。如果callback为None,则默认为True,否则默认为False。

process_links是可调用的,也可以是字符串(在这种情况下,将使用蜘蛛对象中具有该名称的方法),该字符串将针对使用指定的link_extractor从每个响应中提取的每个链接列表进行调用。这主要用于过滤目的。

process_request是可调用的(或字符串,在这种情况下,将使用来自具有该名称的蜘蛛对象的方法),该调用将被此规则提取的每个请求调用。该可调用对象应将所述请求作为第一个参数,并将其源自请求的响应作为第二个参数。它必须返回一个Request对象或None(以滤除该请求)。

如果在处理由规则生成的请求时引发任何异常,则errback是可调用的或字符串(在这种情况下,将使用来自具有该名称的Spider对象的方法)被调用。它接收一个Twisted Failure实例作为第一个参数。

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 = (
        # Extract links matching 'category.php' (but not matching 'subsection.php')
        # and follow links from them (since no callback means follow=True by default).
        Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),

        # Extract links matching 'item.php' and parse them with the spider's method 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()').get()
        item['description'] = response.xpath('//td[@id="item_description"]/text()').get()
        item['link_text'] = response.meta['link_text']
        return item

XMLFeedSpider class scrapy.spiders.XMLFeedSpider

XMLFeedSpider设计用于通过按特定节点名称对其进行迭代来解析XML feed。 可以从iternodes,xml和html中选择迭代器。 出于性能方面的考虑,建议使用iternodes迭代器,因为xml和html迭代器会立即生成整个DOM进行解析。 但是,在解析标记错误的XML时,使用html作为迭代器可能会很有用。

要设置迭代器和标记名称,必须定义以下类属性:
iterator 一个字符串,定义要使用的迭代器。 可以是:'iternodes’基于正则表达式的快速迭代器 ‘html’ 使用选择器的迭代器。 请记住,这使用DOM解析,并且必须将所有DOM加载到内存中,这对于大型Feed可能是个问题 ‘xml’ 使用选择器的迭代器。 请记住,这使用DOM解析,并且必须将所有DOM加载到内存中,这对于大型Feed可能是个问题

itertag 一个字符串,其中包含要迭代的节点(或元素)的名称

namespaces (prefix,uri)元组的列表,这些元组定义了该蜘蛛中将处理的该文档中可用的命名空间。 前缀和uri将用于使用register_namespace方法自动注册名称空间。然后,您可以在itertag属性中指定具有名称空间的节点。

class YourSpider(XMLFeedSpider):
    namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')]
    itertag = 'n:url'
    # ...

除了这些新属性之外,该蜘蛛程序还具有以下可重写方法:
adapt_response(response) 一种在蜘蛛开始解析之前从蜘蛛中间件接收响应的方法。 它可以用于在解析响应主体之前对其进行修改。 此方法接收响应,并且还返回响应(可以相同也可以是另一个)。
parse_node(response, selector) 对于与提供的标签名称(itertag)匹配的节点,调用此方法。 接收每个节点的响应和选择器。 必须重写此方法。 否则,您的蜘蛛将无法工作。 此方法必须返回Item对象,Request对象或包含其中任何一个的Iterable。
process_results(response, results) 蜘蛛返回的每个结果(项目或请求)都会调用此方法,该方法旨在执行将结果返回给框架核心之前所需的最后一次处理,例如设置项目ID。 它接收结果列表和产生这些结果的响应。 它必须返回结果列表(项目或请求)。

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'  # This is actually unnecessary, since it's the default value
    itertag = 'item'

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

        item = TestItem()
        item['id'] = node.xpath('@id').get()
        item['name'] = node.xpath('name').get()
        item['description'] = node.xpath('description').get()
        return item

基本上,我们要做的是创建一个蜘蛛,从指定的start_urls下载提要,然后遍历其每个item标签,将它们打印出来,并将一些随机数据存储在Item中。
在这里插入图片描述

CSVFeedSpider scrapy.spiders.CSVFeedSpider

除了在整个行而不是节点上进行迭代之外,此蜘蛛与XMLFeedSpider非常相似。 每次迭代中调用的方法是parse_row。
delimiter CSV文件中每个字段的分隔符字符串,默认为’,’(逗号)。
quotechar CSV文件中每个字段的带有附件字符的字符串默认为’“’(引号)。
headers CSV文件中列名称的列表。
parse_row(response, row) 接收每个CSV文件提供的(或检测到的)标头的响应和带有键的字典(代表每一行)。 该蜘蛛程序还为覆盖预处理和后期处理提供了覆盖Adapt_response和process_results方法的机会。

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

SitemapSpider scrapy.spiders.SitemapSpider

SitemapSpider允许您通过使用Sitemaps发现URL来爬网网站。它支持嵌套站点地图并从robots.txt发现站点地图URL。

sitemap_urls 指向您要抓取其网址的站点地图的网址列表。您还可以指向robots.txt,它将对其进行解析以从中提取站点地图网址。

sitemap_rules 元组列表(regex,callback),其中:regex是一个正则表达式,用于匹配从站点地图提取的网址。 regex可以是str或已编译的regex对象。callback是用于处理与正则表达式匹配的url的回调。 callback可以是字符串(指示Spider方法的名称)或可调用的。sitemap_rules = [('/product/', 'parse_product')] 规则将按顺序应用,并且仅使用第一个匹配的规则。如果省略此属性,则将使用解析回调处理在站点地图中找到的所有网址。

sitemap_follow 应遵循的站点地图正则表达式列表。 这仅适用于使用指向其他站点地图文件的站点地图索引文件的站点。默认情况下,将遵循所有站点地图。

sitemap_alternate_links 指定是否应遵循一个URL的备用链接。 这些是在同一网址块中传递的另一种语言的同一网站的链接。

<url>
    <loc>http://example.com/</loc>
    <xhtml:link rel="alternate" hreflang="de" href="http://example.com/de"/>
</url>

设置sitemap_alternate_links后,这将检索两个URL。 在禁用sitemap_alternate_links的情况下,仅会检索http://example.com/。默认设置为禁用sitemap_alternate_links。

sitemap_filter(entries) 这是一个筛选功能,可以覆盖该筛选功能,以根据其属性选择站点地图条目。

<url>
    <loc>http://example.com/</loc>
    <lastmod>2005-01-01</lastmod>
</url>

我们可以定义一个sitemap_filter函数来按日期过滤条目:

from scrapy.spiders import SitemapSpider
class FilteredSitemapSpider(SitemapSpider):
    name = 'filtered_sitemap_spider'
    allowed_domains = ['example.com']
    sitemap_urls = ['http://example.com/sitemap.xml']

    def sitemap_filter(self, entries):
        for entry in entries:
            date_time = datetime.strptime(entry['lastmod'], '%Y-%m-%d')
            if date_time.year >= 2005:
                yield entry

这将仅检索在2005年及其后年份修改的条目。条目是从站点地图文档中提取的字典对象。 通常,键是标签名称,值是其中的文本。
请务必注意:因为需要loc属性,所以将删除没有此标签的条目。备用链接与备用键一起存储在列表中(请参阅sitemap_alternate_links)。命名空间已删除,因此名为{namespace} tagname的lxml标记仅成为标记名。
如果省略此方法,将观察站点地图中找到的所有条目,同时观察其他属性及其设置。

最简单的示例:使用解析回调处理通过站点地图发现的所有网址:

from scrapy.spiders import SitemapSpider
class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/sitemap.xml']
    def parse(self, response):
        pass # ... scrape item here ...

使用某些回调处理某些网址,并使用不同的回调处理其他网址:

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/sitemap.xml']
    sitemap_rules = [
        ('/product/', 'parse_product'),
        ('/category/', 'parse_category'),
    ]
    def parse_product(self, response):
        pass # ... scrape product ...
    def parse_category(self, response):
        pass # ... scrape category ...

遵循robots.txt文件中定义的站点地图,并且仅遵循其网址包含/sitemap_shop的站点地图:

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/robots.txt']
    sitemap_rules = [
        ('/shop/', 'parse_shop'),
    ]
    sitemap_follow = ['/sitemap_shops']

    def parse_shop(self, response):
        pass # ... scrape shop here ...

将SitemapSpider与其他网址来源结合:

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/robots.txt']
    sitemap_rules = [
        ('/shop/', 'parse_shop'),
    ]
    other_urls = ['http://www.example.com/about']
    def start_requests(self):
        requests = list(super(MySpider, self).start_requests())
        requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls]
        return requests
    def parse_shop(self, response):
        pass # ... scrape shop here ...
    def parse_other(self, response):
        pass # ... scrape other here ...

Sitemap 可方便网站管理员通知搜索引擎他们网站上有哪些可供抓取的网页。最简单的 Sitemap 形式,就是XML 文件,在其中列出网站中的网址以及关于每个网址的其他元数据(上次更新的时间、更改的频率以及相对于网站上其他网址的重要程度为何等),以便搜索引擎可以更加智能地抓取网站。
Google SiteMap Protocol是Google自己推出的一种站点地图协议,此协议文件基于早期的robots.txt文件协议,并有所升级。在Google官方指南中指出加入了Google SiteMap文件的网站将更有利于Google网页爬行机器人的爬行索引,这样将提高索引网站内容的效率和准确度。文件协议应用了简单的XML格式,一共用到6个标签,其中关键标签包括链接地址、更新时间、更新频率和索引优先权。

参考sitemap百度百科

猜你喜欢

转载自blog.csdn.net/asmartkiller/article/details/105644360