Parse sitemap(s) and yield URLs found in them. This function coordinates the process of fetching and parsing sitemaps, handling both URL-based and raw content sources. It follows nested sitemaps up to the specified maximum depth. Default `ParseSitemapOptions.enqueue_strategy` is `s
(
initial_sources: list[SitemapSource],
http_client: HttpClient | None = None,
proxy_info: ProxyInfo | None = None,
options: ParseSitemapOptions | None = None,
)
| 463 | |
| 464 | |
| 465 | async def parse_sitemap( |
| 466 | initial_sources: list[SitemapSource], |
| 467 | http_client: HttpClient | None = None, |
| 468 | proxy_info: ProxyInfo | None = None, |
| 469 | options: ParseSitemapOptions | None = None, |
| 470 | ) -> AsyncGenerator[SitemapUrl | NestedSitemap, None]: |
| 471 | """Parse sitemap(s) and yield URLs found in them. |
| 472 | |
| 473 | This function coordinates the process of fetching and parsing sitemaps, |
| 474 | handling both URL-based and raw content sources. It follows nested sitemaps |
| 475 | up to the specified maximum depth. |
| 476 | |
| 477 | Default `ParseSitemapOptions.enqueue_strategy` is `same-hostname` which will skip cross-host URLs. |
| 478 | Use strategy `all` to process all links. |
| 479 | """ |
| 480 | # Set default options |
| 481 | options = options or {} |
| 482 | emit_nested_sitemaps = options.get('emit_nested_sitemaps', False) |
| 483 | max_depth = options.get('max_depth', float('inf')) |
| 484 | sitemap_retries = options.get('sitemap_retries', 3) |
| 485 | timeout = options.get('timeout', timedelta(seconds=30)) |
| 486 | enqueue_strategy = options.get('enqueue_strategy', 'same-hostname') |
| 487 | |
| 488 | # Setup working state |
| 489 | sources = list(initial_sources) |
| 490 | visited_sitemap_urls: set[str] = set() |
| 491 | |
| 492 | # Process sources until the queue is empty |
| 493 | while sources: |
| 494 | source = sources.pop(0) |
| 495 | depth = source.get('depth', 0) |
| 496 | |
| 497 | # Skip if we've reached max depth |
| 498 | if depth > max_depth: |
| 499 | logger.debug(f'Skipping sitemap {source.get("url", "")} - exceeded max depth {max_depth}') |
| 500 | continue |
| 501 | |
| 502 | # Process based on source type |
| 503 | if source['type'] == 'raw': |
| 504 | async for result in _process_raw_source( |
| 505 | source, |
| 506 | depth, |
| 507 | visited_sitemap_urls, |
| 508 | sources, |
| 509 | emit_nested_sitemaps=emit_nested_sitemaps, |
| 510 | enqueue_strategy=enqueue_strategy, |
| 511 | ): |
| 512 | yield result |
| 513 | |
| 514 | elif source['type'] == 'url' and 'url' in source: |
| 515 | # Add to visited set before processing to avoid duplicates |
| 516 | if http_client is None: |
| 517 | raise RuntimeError('HttpClient must be provided for URL-based sitemap sources.') |
| 518 | |
| 519 | visited_sitemap_urls.add(source['url']) |
| 520 | |
| 521 | async for result in _fetch_and_process_sitemap( |
| 522 | http_client, |