Fetch a sitemap from a URL and process its content.
(
http_client: HttpClient,
source: SitemapSource,
depth: int,
visited_sitemap_urls: set[str],
sources: list[SitemapSource],
retries_left: int,
*,
proxy_info: ProxyInfo | None = None,
timeout: timedelta | None = None,
emit_nested_sitemaps: bool,
enqueue_strategy: EnqueueStrategy,
)
| 336 | |
| 337 | |
| 338 | async def _fetch_and_process_sitemap( |
| 339 | http_client: HttpClient, |
| 340 | source: SitemapSource, |
| 341 | depth: int, |
| 342 | visited_sitemap_urls: set[str], |
| 343 | sources: list[SitemapSource], |
| 344 | retries_left: int, |
| 345 | *, |
| 346 | proxy_info: ProxyInfo | None = None, |
| 347 | timeout: timedelta | None = None, |
| 348 | emit_nested_sitemaps: bool, |
| 349 | enqueue_strategy: EnqueueStrategy, |
| 350 | ) -> AsyncGenerator[SitemapUrl | NestedSitemap, None]: |
| 351 | """Fetch a sitemap from a URL and process its content.""" |
| 352 | if 'url' not in source: |
| 353 | return |
| 354 | |
| 355 | sitemap_url = source['url'] |
| 356 | |
| 357 | while retries_left > 0: |
| 358 | retries_left -= 1 |
| 359 | try: |
| 360 | async with http_client.stream( |
| 361 | sitemap_url, method='GET', headers=SITEMAP_HEADERS, proxy_info=proxy_info, timeout=timeout |
| 362 | ) as response: |
| 363 | # Determine content type and compression |
| 364 | content_type = response.headers.get('content-type', '') |
| 365 | |
| 366 | decoder = getincrementaldecoder('utf-8')(errors='replace') |
| 367 | |
| 368 | # Create appropriate parser |
| 369 | parser = _get_parser(content_type, sitemap_url) |
| 370 | decompressor = None |
| 371 | try: |
| 372 | # Process chunks as they arrive |
| 373 | first_chunk = True |
| 374 | async for raw_chunk in response.read_stream(): |
| 375 | # Check if the first chunk is a valid gzip header |
| 376 | if first_chunk and raw_chunk.startswith(b'\x1f\x8b'): |
| 377 | decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16) |
| 378 | first_chunk = False |
| 379 | |
| 380 | chunk = decompressor.decompress(raw_chunk) if decompressor else raw_chunk |
| 381 | text_chunk = decoder.decode(chunk) |
| 382 | async for item in parser.process_chunk(text_chunk): |
| 383 | async for result in _process_sitemap_item( |
| 384 | item, |
| 385 | source, |
| 386 | depth, |
| 387 | visited_sitemap_urls, |
| 388 | sources, |
| 389 | emit_nested_sitemaps=emit_nested_sitemaps, |
| 390 | enqueue_strategy=enqueue_strategy, |
| 391 | ): |
| 392 | if result: |
| 393 | yield result |
| 394 | |
| 395 | # Process any remaining content |
no test coverage detected