Lzh on GitHub

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

对于爬虫,抓取周期大致如下:

  1. 您首先生成抓取初始 URL 的请求,并指定一个回调函数,该函数将在从这些请求下载响应后调用。
  2. 要执行的第一个请求是通过迭代 start() 方法获得的,该方法默认会为 start_urls 爬虫属性中的每个 URL 生成一个 Request 对象,并将 parse 方法设置为回调函数来处理每个 Response
  3. 在回调函数中,您解析响应(网页)并返回 item 对象Request 对象或这些对象的可迭代对象。这些 Request 也将包含一个回调(可能是同一个),然后将由 Scrapy 下载,然后由指定的回调处理其响应。
  4. 在回调函数中,您解析页面内容,通常使用 Selectors(但您也可以使用 BeautifulSoup、lxml 或您喜欢的任何机制),并使用解析的数据生成 Item。
  5. 最后,从爬虫返回的 Item 通常会持久化到数据库(在某个 Item Pipeline 中)或 使用 Feed 导出 写入文件。

尽管此周期(或多或少)适用于任何类型的爬虫,但 Scrapy 中捆绑了不同类型的默认爬虫,用于不同的目的。我们将在此处讨论这些类型。

scrapy.Spider

class scrapy.spiders.Spider

class scrapy.Spider(*args: Any, **kwargs: Any)[source]

任何爬虫都必须继承的基类。

它提供了一个默认的 start() 实现,该实现根据 start_urls 类属性发送请求,并为每个响应调用 parse() 方法。

name

一个字符串,定义此爬虫的名称。爬虫名称是 Scrapy 定位(和实例化)爬虫的方式,因此它必须是唯一的。但是,没有什么能阻止您实例化同一爬虫的多个实例。这是最重要的爬虫属性,并且是必需的。

如果爬虫抓取单个域,常见的做法是根据域名命名爬虫,无论是否带 TLD。因此,例如,一个抓取 mywebsite.com 的爬虫通常被称为 mywebsite

allowed_domains

一个可选的字符串列表,包含此爬虫允许抓取的域。如果启用了 OffsiteMiddleware,则不属于此列表中指定域名(或其子域)的 URL 请求将不会被跟踪。

假设您的目标 URL 是 https://www.example.com/1.html,那么将 'example.com' 添加到列表中。

start_urls: list[str]

起始 URL。参见 start()

custom_settings

一个字典,其中包含在运行此爬虫时将覆盖项目范围配置的设置。它必须定义为类属性,因为设置在实例化之前更新。

有关可用内置设置的列表,请参见:内置设置参考

crawler

此属性由 from_crawler() 类方法在初始化类后设置,并链接到此爬虫实例绑定的 Crawler 对象。

爬虫封装了项目中许多组件,以便进行单一入口访问(例如扩展、中间件、信号管理器等)。请参阅 Crawler API 了解更多信息。

settings

运行此爬虫的配置。这是一个 Settings 实例,有关此主题的详细介绍,请参见设置主题。

logger

使用爬虫的 name 创建的 Python 日志器。您可以使用它来发送日志消息,如 从爬虫记录日志 中所述。

state

一个字典,您可以用于在批处理之间保留一些爬虫状态。有关详细信息,请参阅保持批处理之间的持久状态

from_crawler(crawler, *args, **kwargs)[source]

这是 Scrapy 用于创建爬虫的类方法。

您可能不需要直接重写此方法,因为默认实现充当 __init__() 方法的代理,使用给定的参数 args 和命名参数 kwargs 调用它。

尽管如此,此方法会在新实例中设置 crawlersettings 属性,以便以后可以在爬虫代码中访问它们。

版本 2.11 中的变化:现在可以在此方法中修改 crawler.settings 中的设置,如果您想根据参数修改它们,这会很方便。因此,这些设置不是最终值,因为它们以后可能会被附加组件等修改。出于同样的原因,大多数 Crawler 属性此时未初始化。

最终设置和已初始化的 Crawler 属性可在 start() 方法、engine_started 信号的处理程序以及之后使用。

参数:

  • crawler(Crawler 实例)——爬虫将绑定的爬虫
  • args(list)——传递给 __init__() 方法的参数
  • kwargs(dict)——传递给 __init__() 方法的关键字参数

classmethod update_settings(settings)[source]

update_settings() 方法用于修改爬虫的设置,并在爬虫实例初始化期间调用。

它将一个 Settings 对象作为参数,可以添加或更新爬虫的配置值。此方法是类方法,这意味着它在 Spider 类上调用,并允许爬虫的所有实例共享相同的配置。

虽然可以在 custom_settings 中设置每个爬虫的设置,但使用 update_settings() 允许您根据其他设置、爬虫属性或其他因素动态添加、删除或更改设置,并使用除 'spider' 之外的设置优先级。此外,通过重写它很容易在子类中扩展 update_settings(),而使用 custom_settings 做到这一点可能会很困难。

例如,假设爬虫需要修改 FEEDS

import scrapy

class MySpider(scrapy.Spider):
    name = "myspider"
    custom_feed = {
        "/home/user/documents/items.json": {
            "format": "json",
            "indent": 4,
        }
    }

    @classmethod
    def update_settings(cls, settings):
        super().update_settings(settings)
        settings.setdefault("FEEDS", {}).update(cls.custom_feed)

async start() -> AsyncIterator[Any][source]

生成要发送的初始 Request 对象。

版本 2.13 新增。

例如:

from scrapy import Request, Spider

class MySpider(Spider):
    name = "myspider"

    async def start(self):
        yield Request("https://toscrape.com/")

默认实现从 start_urls 读取 URL,并为每个 URL 生成一个 dont_filter 启用的请求。它在功能上等同于:

async def start(self):
    for url in self.start_urls:
        yield Request(url, dont_filter=True)

您还可以生成 Item。例如:

async def start(self):
    yield {"foo": "bar"}

为了编写在低于 2.13 的 Scrapy 版本上工作的爬虫,还需要定义一个返回可迭代对象的同步 start_requests() 方法。例如:

def start_requests(self):
    yield Request("https://toscrape.com/")

另请参阅

起始请求

parse(response)[source]

这是 Scrapy 用于处理下载响应的默认回调,当它们的请求未指定回调时。

parse 方法负责处理响应并返回抓取的数据和/或要跟踪的更多 URL。其他 Request 回调与 Spider 类具有相同的要求。

此方法以及任何其他 Request 回调都必须返回一个 Request 对象、一个 item 对象、一个 Request 对象和/或 item 对象的可迭代对象,或者 None

参数:

  • response(Response)——要解析的响应

log(message[, level, component])[source]

通过爬虫的 logger 发送日志消息的包装器,保留用于向后兼容。有关详细信息,请参阅从爬虫记录日志

closed(reason)

当爬虫关闭时调用。此方法为 spider_closed 信号提供了 signals.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)

从单个回调返回多个请求和 Item:

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)

除了 start_urls,您还可以直接使用 start();为了使数据更具结构化,您可以使用 Item 对象:

import scrapy
from myproject.items import MyItem

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

    async def start(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 或将抓取限制到网站的特定部分,但它们可用于配置爬虫的任何功能。

爬虫参数通过 crawl 命令使用 -a 选项传递。例如:

scrapy crawl myspider -a category=electronics

爬虫可以在它们的 __init__ 方法中访问参数:

import scrapy

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

    def __init__(self, category=None, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.start_urls = [f"http://www.example.com/categories/{category}"]
        # ...

默认的 __init__ 方法将获取任何爬虫参数并将其复制到爬虫作为属性。上面的示例也可以写成如下:

import scrapy

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

    async def start(self):
        yield scrapy.Request(f"http://www.example.com/categories/{self.category}")

如果您从脚本运行 Scrapy,您可以在调用 CrawlerProcess.crawlCrawlerRunner.crawl 时指定爬虫参数:

process = CrawlerProcess()
process.crawl(MySpider, category="electronics")

请记住,爬虫参数只是字符串。爬虫不会自行进行任何解析。如果您要从命令行设置 start_urls 属性,则必须使用 ast.literal_eval()json.loads() 之类的工具将其解析为列表,然后将其设置为属性。否则,您将导致迭代 start_urls 字符串(一个非常常见的 Python 陷阱),导致每个字符被视为单独的 URL。

一个有效的用例是设置 HttpAuthMiddleware 使用的 HTTP 认证凭据或 UserAgentMiddleware 使用的用户代理:

scrapy crawl myspider -a http_user=myuser -a http_pass=mypassword -a user_agent=mybot

爬虫参数也可以通过 Scrapyd 的 schedule.json API 传递。请参阅 Scrapyd 文档

起始请求

起始请求是从爬虫的 start() 方法或爬虫中间件process_start() 方法生成的 Request 对象。

另请参阅

起始请求顺序

延迟起始请求迭代

您可以按如下方式重写 start() 方法,以便在有计划请求时暂停其迭代:

async def start(self):
    async for item_or_request in super().start():
        if self.crawler.engine.needs_backout():
            await self.crawler.signals.wait_for(signals.scheduler_empty)
        yield item_or_request

这有助于最大限度地减少调度程序中任何给定时间的请求数量,从而最大限度地减少资源使用(内存或磁盘,具体取决于 JOBDIR)。

通用爬虫

Scrapy 附带了一些有用的通用爬虫,您可以从中继承您的爬虫。它们旨在为一些常见的抓取情况提供便捷的功能,例如根据某些规则跟踪站点上的所有链接,从 Sitemaps 爬取,或解析 XML/CSV 源。

对于以下爬虫中使用的示例,我们假设您有一个项目,其中在 myproject.items 模块中声明了一个 TestItem

import scrapy

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

CrawlSpider

class scrapy.spiders.CrawlSpider[source]

这是用于爬取常规网站最常用的爬虫,因为它通过定义一组规则提供了方便的跟踪链接机制。它可能不是最适合您的特定网站或项目,但它对于多种情况来说足够通用,因此您可以从它开始,并根据需要覆盖它以实现更多自定义功能,或者只是实现您自己的爬虫。

除了从 Spider 继承的属性(您必须指定)之外,此类别支持一个新属性:

rules

这是一个包含一个(或多个)Rule 对象的列表。每个 Rule 都定义了爬取站点的特定行为。Rule 对象如下所述。如果多个规则匹配同一个链接,将使用第一个匹配的规则,根据它们在此属性中定义的顺序。

此爬虫还公开了一个可重写的方法:

parse_start_url(response, **kwargs)[source]

此方法为爬虫 start_urls 属性中为 URL 生成的每个响应调用。它允许解析初始响应,并且必须返回一个 item 对象、一个 Request 对象或包含其中任何一个的可迭代对象。

爬取规则

class scrapy.spiders.Rule(link_extractor: LinkExtractor | None = None, callback: CallbackT | str | None = None, cb_kwargs: dict[str, Any] | None = None, follow: bool | None = None, process_links: ProcessLinksT | str | None = None, process_request: ProcessRequestT | str | None = None, errback: Callable[[Failure], Any] | str | None = None)[source]

  • link_extractor 是一个 Link Extractor 对象,它定义了如何从每个爬取的页面中提取链接。每个生成的链接将用于生成一个 Request 对象,该对象将在其 meta 字典(在 link_text 键下)中包含链接的文本。如果省略,将使用不带参数创建的默认链接提取器,导致所有链接都被提取。
  • callback 是一个可调用对象或一个字符串(在这种情况下将使用爬虫对象中同名的方法),用于为使用指定链接提取器提取的每个链接调用。此回调接收一个 Response 作为其第一个参数,并且必须返回一个或多个 item 对象和/或 Request 对象(或它们的任何子类)的单个实例或可迭代对象。如上所述,接收到的 Response 对象将在其 meta 字典(在 link_text 键下)中包含生成 Request 的链接的文本。
  • cb_kwargs 是一个字典,包含要传递给回调函数的关键字参数。
  • follow 是一个布尔值,指定是否应从此规则提取的每个响应中跟踪链接。如果 callbackNone,则 follow 默认为 True,否则默认为 False
  • process_links 是一个可调用对象,或一个字符串(在这种情况下将使用爬虫对象中同名的方法),它将用于处理使用指定的 link_extractor 从每个响应中提取的每个链接列表。这主要用于过滤目的。
  • process_request 是一个可调用对象(或一个字符串,在这种情况下将使用爬虫对象中同名的方法),它将为此规则提取的每个 Request 调用。此可调用对象应将所述请求作为第一个参数,并将生成请求的 Response 作为第二个参数。它必须返回一个 Request 对象或 None(以过滤掉请求)。
  • errback 是一个可调用对象或一个字符串(在这种情况下将使用爬虫对象中同名的方法),如果处理此规则生成的请求时引发任何异常,则调用它。它接收一个 Twisted Failure 实例作为第一个参数。

警告

由于其内部实现,在编写基于 CrawlSpider 的爬虫时,您必须显式地为新请求设置回调;否则可能会出现意外行为。

版本 2.0 新增:errback 参数。

CrawlSpider 示例

现在让我们看一个带有规则的 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 = (
        # 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=(r"category\.php",), deny=(r"subsection\.php",))),
        # Extract links matching 'item.php' and parse them with the spider's method parse_item
        Rule(LinkExtractor(allow=(r"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"]
        url = response.xpath('//td[@id="additional_data"]/@href').get()
        return response.follow(
            url, self.parse_additional_page, cb_kwargs=dict(item=item)
        )

    def parse_additional_page(self, response, item):
        item["additional_data"] = response.xpath(
            '//p[@id="additional_data"]/text()'
        ).get()
        return item

这个爬虫将开始抓取 example.com 的主页,收集类别链接和 Item 链接,并使用 parse_item 方法解析后者。对于每个 Item 响应,将使用 XPath 从 HTML 中提取一些数据,并用它填充一个 Item

XMLFeedSpider

class scrapy.spiders.XMLFeedSpider[source]

XMLFeedSpider 旨在通过按特定节点名称迭代 XML 源来解析它们。迭代器可以从 iternodesxmlhtml 中选择。建议使用 iternodes 迭代器以提高性能,因为 xmlhtml 迭代器会一次性生成整个 DOM 以进行解析。但是,在解析包含不良标记的 XML 时,使用 html 作为迭代器可能会很有用。

要设置迭代器和标签名称,您必须定义以下类属性:

iterator

一个字符串,定义要使用的迭代器。它可以是以下之一:

  • 'iternodes' - 基于正则表达式的快速迭代器
  • 'html' - 使用 Selector 的迭代器。请记住,这使用 DOM 解析,并且必须将所有 DOM 加载到内存中,这对于大型源来说可能是一个问题
  • 'xml' - 使用 Selector 的迭代器。请记住,这使用 DOM 解析,并且必须将所有 DOM 加载到内存中,这对于大型源来说可能是一个问题

默认为:'iternodes'

itertag

一个字符串,包含要迭代的节点(或元素)的名称。例如:

itertag = 'product'
namespaces

一个由 (prefix, uri) 元组组成的列表,用于定义该文档中可用的命名空间,这些命名空间将由该爬虫处理。prefixuri 将用于使用 register_namespace() 方法自动注册命名空间。

然后,您可以在 itertag 属性中指定带有命名空间的节点。

示例:

class YourSpider(XMLFeedSpider):

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

除了这些新属性之外,此爬虫还具有以下可重写方法:

adapt_response(response)[source]

一个方法,在响应从爬虫中间件到达后立即接收响应,在爬虫开始解析它之前。它可以用于在解析响应体之前修改它。此方法接收一个响应并返回一个响应(可以是同一个或另一个)。

parse_node(response, selector)[source]

此方法为与提供的标签名称 (itertag) 匹配的节点调用。接收响应和每个节点的 Selector。覆盖此方法是强制性的。否则,您的爬虫将无法工作。此方法必须返回一个 item 对象、一个 Request 对象或包含其中任何一个的可迭代对象。

process_results(response, results)[source]

此方法为爬虫返回的每个结果(Item 或 Request)调用,旨在在将结果返回给框架核心之前执行任何最后的处理,例如设置 Item ID。它接收结果列表和生成这些结果的响应。它必须返回结果列表(Item 或 Request)。

警告

由于其内部实现,在编写基于 XMLFeedSpider 的爬虫时,您必须显式地为新请求设置回调;否则可能会出现意外行为。

XMLFeedSpider 示例

这些爬虫非常易于使用,让我们看一个例子:

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 下载一个 feed,然后迭代它的每个 item 标签,打印它们,并将一些随机数据存储在 Item 中。

CSVFeedSpider

class scrapy.spiders.CSVFeedSpider[source]

此爬虫与 XMLFeedSpider 非常相似,不同之处在于它迭代的是行而不是节点。每次迭代中调用的方法是 parse_row()

delimiter

一个字符串,表示 CSV 文件中每个字段的分隔符。默认为 ','(逗号)。

quotechar

一个字符串,表示 CSV 文件中每个字段的包围字符。默认为 '"'(引号)。

headers

CSV 文件中列名的列表。

parse_row(response, row)[source]

接收一个响应和一个字典(表示每行),其中包含 CSV 文件中每个提供(或检测到)的标题的键。此爬虫还提供了重写 adapt_responseprocess_results 方法的机会,用于预处理和后处理。

CSVFeedSpider 示例

让我们看一个与上一个类似的示例,但使用 CSVFeedSpider

from scrapy.spiders import CSVFeedSpider
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

class scrapy.spiders.SitemapSpider[source]

SitemapSpider 允许您通过使用 Sitemaps 发现 URL 来抓取网站。

它支持嵌套站点地图和从 robots.txt 发现站点地图 URL。

sitemap_urls

指向您要抓取其 URL 的站点地图的 URL 列表。

您还可以指向 robots.txt,它将被解析以从中提取站点地图 URL。

sitemap_rules

一个元组列表 (regex, callback),其中:

  • regex 是一个正则表达式,用于匹配从站点地图中提取的 URL。regex 可以是字符串或编译后的正则表达式对象。
  • callback 是用于处理匹配正则表达式的 URL 的回调。callback 可以是字符串(表示爬虫方法的名称)或可调用对象。

例如:

sitemap_rules = [('/product/', 'parse_product')]

规则按顺序应用,只有第一个匹配的规则将被使用。

如果您省略此属性,则站点地图中找到的所有 URL 都将使用 parse 回调进行处理。

sitemap_follow

应跟踪的站点地图的正则表达式列表。这仅适用于使用站点地图索引文件指向其他站点地图文件的网站。

默认情况下,所有站点地图都会被跟踪。

指定是否应跟踪同一 URL 的备用链接。这些是同一网站中不同语言的链接,在同一 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)[source]

这是一个过滤函数,可以重写它以根据其属性选择站点地图条目。

例如:

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

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

from datetime import datetime
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 年及以后修改的 entries

Entries 是从站点地图文档中提取的字典对象。通常,键是标签名称,值是其中的文本。

需要注意的重要事项是:

  • 由于 loc 属性是必需的,因此没有此标签的条目将被丢弃
  • 备用链接存储在一个名为 alternate 的键的列表中(参见 sitemap_alternate_links
  • 命名空间被移除,因此名为 {namespace}tagname 的 lxml 标签只变为 tagname

如果您省略此方法,则站点地图中找到的所有条目都将被处理,并遵守其他属性及其设置。

SitemapSpider 示例

最简单的示例:使用 parse 回调处理通过站点地图发现的所有 URL:

from scrapy.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ["http://www.example.com/sitemap.xml"]

    def parse(self, response):
        pass  # ... scrape item here ...

使用特定回调处理某些 URL,并使用不同回调处理其他 URL:

from scrapy.spiders import SitemapSpider

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 文件中定义的站点地图,并且只跟踪 URL 包含 /sitemap_shop 的站点地图:

from scrapy.spiders import SitemapSpider

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 与其他 URL 源结合使用:

from scrapy.spiders import SitemapSpider

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

    other_urls = ["http://www.example.com/about"]

    async def start(self):
        async for item_or_request in super().start():
            yield item_or_request
        for url in self.other_urls:
            yield Request(url, self.parse_other)

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

    def parse_other(self, response):
        pass  # ... scrape other here ...