graph-crawler 5.2.0__tar.gz → 5.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- graph_crawler-5.2.1/CHANGELOG.md +244 -0
- graph_crawler-5.2.1/CODE_STYLE.md +1473 -0
- graph_crawler-5.2.1/LICENSE +21 -0
- graph_crawler-5.2.1/MANIFEST.in +19 -0
- graph_crawler-5.2.1/PKG-INFO +370 -0
- graph_crawler-5.2.1/README.md +249 -0
- graph_crawler-5.2.1/graph_crawler/__init__.py +478 -0
- graph_crawler-5.2.1/graph_crawler/__version__.py +7 -0
- graph_crawler-5.2.1/graph_crawler/ai/__init__.py +49 -0
- graph_crawler-5.2.1/graph_crawler/api/__init__.py +24 -0
- graph_crawler-5.2.1/graph_crawler/api/_core.py +281 -0
- graph_crawler-5.2.1/graph_crawler/api/_distributed.py +174 -0
- graph_crawler-5.2.1/graph_crawler/api/_shared.py +120 -0
- graph_crawler-5.2.1/graph_crawler/api/_sitemap_distributed.py +244 -0
- graph_crawler-5.2.1/graph_crawler/api/async_.py +325 -0
- graph_crawler-5.2.1/graph_crawler/api/cli.py +440 -0
- graph_crawler-5.2.1/graph_crawler/api/client/__init__.py +8 -0
- graph_crawler-5.2.1/graph_crawler/api/client/client.py +498 -0
- graph_crawler-5.2.1/graph_crawler/api/history_manager.py +82 -0
- graph_crawler-5.2.1/graph_crawler/api/project_init.py +194 -0
- graph_crawler-5.2.1/graph_crawler/api/server/__init__.py +18 -0
- graph_crawler-5.2.1/graph_crawler/api/server/crawl_monitor.py +145 -0
- graph_crawler-5.2.1/graph_crawler/api/server/dashboard.py +221 -0
- graph_crawler-5.2.1/graph_crawler/api/server/rest_api.py +704 -0
- graph_crawler-5.2.1/graph_crawler/api/server/webhooks.py +421 -0
- graph_crawler-5.2.1/graph_crawler/api/server/websocket_manager.py +89 -0
- graph_crawler-5.2.1/graph_crawler/api/stats_collector.py +115 -0
- graph_crawler-5.2.1/graph_crawler/api/sync.py +491 -0
- graph_crawler-5.2.1/graph_crawler/application/__init__.py +38 -0
- graph_crawler-5.2.1/graph_crawler/application/bootstrap.py +209 -0
- graph_crawler-5.2.1/graph_crawler/application/context/__init__.py +31 -0
- graph_crawler-5.2.1/graph_crawler/application/context/dependency_registry.py +354 -0
- graph_crawler-5.2.1/graph_crawler/application/context/graph_context.py +217 -0
- graph_crawler-5.2.1/graph_crawler/application/context/merge_context.py +221 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/__init__.py +67 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/edge_dto.py +25 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/graph_dto.py +27 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/mappers/__init__.py +14 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/mappers/edge_mapper.py +149 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/mappers/graph_mapper.py +614 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/mappers/node_data_codec.py +190 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/mappers/node_mapper.py +387 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/node_dto.py +27 -0
- graph_crawler-5.2.1/graph_crawler/application/dto/utils.py +272 -0
- graph_crawler-5.2.1/graph_crawler/application/services/__init__.py +60 -0
- graph_crawler-5.2.1/graph_crawler/application/services/application_container.py +208 -0
- graph_crawler-5.2.1/graph_crawler/application/services/driver_factory.py +147 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/__init__.py +26 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/base_exporter.py +150 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/csv_exporter.py +318 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/edge_exporter.py +432 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/excel_exporter.py +301 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/jsonl_exporter.py +290 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/node_exporter.py +283 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/parquet_exporter.py +248 -0
- graph_crawler-5.2.1/graph_crawler/application/services/exporters/sql_exporter.py +267 -0
- graph_crawler-5.2.1/graph_crawler/application/services/finalize.py +115 -0
- graph_crawler-5.2.1/graph_crawler/application/services/low_memory_graph_saver.py +339 -0
- graph_crawler-5.2.1/graph_crawler/application/services/resource_budget.py +179 -0
- graph_crawler-5.2.1/graph_crawler/application/services/scheduling/__init__.py +12 -0
- graph_crawler-5.2.1/graph_crawler/application/services/scheduling/rule_based_scheduler.py +113 -0
- graph_crawler-5.2.1/graph_crawler/application/services/storage_factory.py +195 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/__init__.py +11 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/__init__.py +81 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/adaptive_throttler.py +374 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/async_bridge.py +45 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/base_spider.py +156 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/celery_batch_spider.py +658 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/celery_spider.py +448 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/checkpoint.py +421 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/crawl_coordinator.py +1044 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/dead_letter_queue.py +413 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/domain_rate_limiter.py +262 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/filters/__init__.py +10 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/filters/base.py +74 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/filters/domain_filter.py +195 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/filters/domain_patterns.py +30 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/filters/path_filter.py +95 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/incremental_strategy.py +239 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/link_processor.py +908 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/multiprocess_spider.py +511 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/node_scanner.py +808 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/parsers/__init__.py +6 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/parsers/base.py +73 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/parsers/html_parser.py +154 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/progress_tracker.py +235 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/scheduler.py +747 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/serialization_mixin.py +218 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/sitemap_parser.py +662 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/sitemap_processor.py +401 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/sitemap_spider.py +608 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/spider.py +811 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/spider_lifecycle.py +108 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/crawling/worker_pool.py +154 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/graph_export.py +504 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/graph_merge/__init__.py +33 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/graph_merge/graph_operations.py +632 -0
- graph_crawler-5.2.1/graph_crawler/application/use_cases/graph_merge/merge_strategies.py +348 -0
- graph_crawler-5.2.1/graph_crawler/data/__init__.py +28 -0
- graph_crawler-5.2.1/graph_crawler/data/backends/__init__.py +21 -0
- graph_crawler-5.2.1/graph_crawler/data/backends/memory.py +486 -0
- graph_crawler-5.2.1/graph_crawler/data/backends/sqlite.py +1866 -0
- graph_crawler-5.2.1/graph_crawler/data/interfaces.py +575 -0
- graph_crawler-5.2.1/graph_crawler/domain/__init__.py +62 -0
- graph_crawler-5.2.1/graph_crawler/domain/context/__init__.py +14 -0
- graph_crawler-5.2.1/graph_crawler/domain/context/crawl_context.py +531 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/__init__.py +32 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/edge.py +345 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/edge_analysis.py +223 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/graph.py +4120 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/graph_operations.py +33 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/graph_statistics.py +13 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/merge_strategies.py +36 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/node.py +692 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/redirect_mode.py +23 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/registries.py +237 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/sitemap_node.py +74 -0
- graph_crawler-5.2.1/graph_crawler/domain/entities/strategies.py +202 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/__init__.py +163 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/base.py +58 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/crawl.py +123 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/edge.py +46 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/event_bus.py +251 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/events.py +313 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/fetch.py +123 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/idempotent_subscriber.py +120 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/legacy_type_map.py +45 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/llm.py +158 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/node.py +124 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/plugin.py +96 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/scheduler.py +102 -0
- graph_crawler-5.2.1/graph_crawler/domain/events/storage.py +168 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/__init__.py +111 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/adapter.py +29 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/control_channel.py +371 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/crawl_context.py +49 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/distributed_spider.py +63 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/driver.py +88 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/event_bus.py +61 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/exporters.py +83 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/filter.py +19 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/merge_context.py +58 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/node_interfaces.py +376 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/parser.py +110 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/plugin_manager.py +53 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/processor.py +11 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/scanner.py +57 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/scheduler.py +43 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/scheduling/__init__.py +40 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/scheduling/frontier.py +97 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/scheduling/scheduler.py +107 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/spider.py +63 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/stop_condition.py +211 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/storage/__init__.py +43 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/storage/base.py +70 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/storage/eviction.py +102 -0
- graph_crawler-5.2.1/graph_crawler/domain/interfaces/storage/queue.py +234 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/__init__.py +216 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/adjacency_maintenance.py +95 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/cycle_detection.py +92 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/degree_ranking.py +47 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/depth_context.py +123 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/display_title.py +47 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/duplicate_detection.py +141 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/duplicate_selector.py +127 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/duplicate_stats.py +63 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/edge_filter.py +82 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/edge_statistics.py +110 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/eviction_policy.py +83 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/graph_query_cascade.py +178 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/graph_statistics.py +186 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/graph_traversal.py +150 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/language_versions.py +73 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/lsh_index.py +99 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/minimap_builder.py +147 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/node_content_resolver.py +128 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/node_view_builder.py +163 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/pagination_guards.py +136 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/predicate_ops.py +77 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/schema_filter.py +138 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/search_haystack.py +102 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/simhash_clustering.py +96 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/simhash_fallback.py +59 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/similarity_ranking.py +62 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/text_search.py +157 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/url_clustering.py +88 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/url_deduplication.py +101 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/url_normalizer.py +108 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/url_rule_matcher.py +103 -0
- graph_crawler-5.2.1/graph_crawler/domain/services/url_tree_builder.py +197 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/__init__.py +88 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/configs.py +884 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/domain_patterns.py +71 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/fetch_options.py +57 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/html_document.py +59 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/lifecycle.py +30 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/models.py +1316 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/redirect_hop.py +49 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/scheduling/__init__.py +23 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/scheduling/crawl_request.py +153 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/scheduling/retry_policy.py +109 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/settings.py +350 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/url_normalization.py +496 -0
- graph_crawler-5.2.1/graph_crawler/domain/value_objects/views.py +293 -0
- graph_crawler-5.2.1/graph_crawler/extensions/__init__.py +1 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/__init__.py +65 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/base.py +147 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/cache_middleware.py +277 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/chain.py +159 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/error_recovery_middleware.py +442 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/logging_middleware.py +108 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/proxy_health.py +144 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/proxy_middleware.py +208 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/proxy_models.py +84 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/proxy_selection.py +87 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/rate_limit_middleware.py +262 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/request_response_middleware.py +476 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/retry_middleware.py +279 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/robots_cache.py +85 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/robots_middleware.py +110 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/robots_validator.py +60 -0
- graph_crawler-5.2.1/graph_crawler/extensions/middleware/user_agent_middleware.py +251 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/__init__.py +57 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/builtin/__init__.py +7 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/builtin/stats_export_plugin.py +98 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/crawl_engine/__init__.py +24 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/crawl_engine/base.py +155 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/crawl_engine/priority_provider.py +247 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/crawl_engine/smart_crawl.py +306 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/__init__.py +128 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/anti_bot_detection.py +52 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/anti_bot_playwright.py +85 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/anti_bot_scripts.py +133 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/anti_bot_stealth.py +177 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/base.py +121 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/captcha/__init__.py +22 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/captcha/detector.py +94 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/captcha/models.py +74 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/captcha/plugin.py +228 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/engine/captcha/services.py +389 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/__init__.py +86 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/base.py +432 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/content_extractors/__init__.py +15 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/content_extractors/base.py +82 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/content_extractors/goose3_extractor.py +80 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/content_extractors/newspaper_extractor.py +93 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/content_extractors/plugin.py +132 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/content_extractors/readability_extractor.py +91 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/defaults.py +32 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/extractors/__init__.py +30 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/extractors/email_extractor.py +146 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/extractors/phone_extractor.py +136 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/extractors/price_extractor.py +137 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/links.py +184 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/markdown_plugin.py +249 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/metadata.py +391 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/smart_page_finder.py +749 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/__init__.py +51 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/constants.py +27 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/exceptions.py +18 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/extractor.py +361 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/options.py +62 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/parsers/__init__.py +25 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/parsers/base.py +43 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/parsers/jsonld.py +331 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/parsers/microdata.py +117 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/parsers/opengraph.py +66 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/parsers/rdfa.py +122 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/parsers/twitter.py +66 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/plugin.py +132 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/structured_data/result.py +233 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/text.py +76 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/node/url_normalizer.py +363 -0
- graph_crawler-5.2.1/graph_crawler/extensions/plugins/registry.py +97 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/__init__.py +1 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/adapters/__init__.py +60 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/adapters/base.py +498 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/adapters/selectolax_adapter.py +234 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/__init__.py +37 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/celery_app.py +202 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/celery_batch.py +284 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/celery_job_task.py +415 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/celery_unified.py +419 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/config.py +201 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/easy_crawler.py +279 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/messaging/worker_api.py +607 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/__init__.py +135 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/auto_storage.py +336 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/base.py +111 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/eviction.py +100 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/graph_repository.py +401 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/json/__init__.py +10 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/json_storage.py +375 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/lmdb_eviction_storage.py +403 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/memory/__init__.py +1 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/memory_dedup_store.py +91 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/memory_frontier.py +180 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/memory_politeness_store.py +88 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/memory_storage.py +166 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/mongodb_storage.py +383 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/naming_strategy.py +174 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/postgresql_storage.py +449 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/protocols/__init__.py +1 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/redis_dedup_store.py +119 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/redis_politeness_store.py +122 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/repository.py +130 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/sqlite/__init__.py +10 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/sqlite_eviction_storage.py +918 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/sqlite_storage.py +775 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/__init__.py +47 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/file_job_storage.py +245 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/file_queue_storage.py +248 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/memory_job_storage.py +94 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/memory_queue_storage.py +117 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/postgresql_job_storage.py +317 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/postgresql_queue_storage.py +364 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/persistence/unified/unified_storage.py +244 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/__init__.py +135 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/__init__.py +38 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/config.py +47 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/context.py +55 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/driver.py +724 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/driver_curl_cffi.py +407 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/plugins/__init__.py +48 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle.py +484 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle_adaptive.py +1435 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/plugins/headers.py +69 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/plugins/http_cache.py +321 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/plugins/rate_limiter.py +96 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/plugins/retry.py +316 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/async_http/stages.py +33 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/base.py +324 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/base_plugin.py +151 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/compression/__init__.py +23 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/compression/strategy.py +219 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/connection_pool.py +349 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/context.py +114 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/core/__init__.py +15 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/core/base_async.py +378 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/core/body_decoder.py +26 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/core/mixins.py +258 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/core/redirect_utils.py +168 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/escalation.py +937 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/factory.py +210 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/__init__.py +19 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/adaptive_semaphore.py +65 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/batch_scheduler.py +764 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/browser_factory.py +576 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/browser_profile.py +718 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/config.py +84 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/context.py +46 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/driver.py +80 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/engine.py +465 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/fetch_metrics.py +115 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/net/__init__.py +41 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/net/geoip.py +136 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/net/proxy_pool.py +225 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/net/rate_limiter.py +139 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/page_fetch.py +896 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/__init__.py +71 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/_network_record.py +66 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/captcha_detector.py +315 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/captcha_solver.py +108 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/cookie_consent.py +565 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/form_filler.py +177 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/human_bezier.py +297 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/network_log.py +366 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/ram_adaptive.py +208 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/screenshot.py +169 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/plugins/user_profile.py +556 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/pool_lifecycle.py +658 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/pooled_driver.py +698 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/stages.py +35 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/playwright/stealth_hints.py +153 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/plugin_manager.py +316 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/protocols.py +118 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/undetected/__init__.py +8 -0
- graph_crawler-5.2.1/graph_crawler/infrastructure/transport/undetected/async_driver.py +465 -0
- graph_crawler-5.2.1/graph_crawler/native/README.md +110 -0
- graph_crawler-5.2.1/graph_crawler/native/__init__.py +200 -0
- graph_crawler-5.2.1/graph_crawler/native/bloom_filter.pyx +255 -0
- graph_crawler-5.2.1/graph_crawler/native/html_parser.pyx +262 -0
- graph_crawler-5.2.1/graph_crawler/native/setup.py +101 -0
- graph_crawler-5.2.1/graph_crawler/native/url_utils.pyx +209 -0
- graph_crawler-5.2.1/graph_crawler/observability/__init__.py +62 -0
- graph_crawler-5.2.1/graph_crawler/observability/decorators/__init__.py +11 -0
- graph_crawler-5.2.1/graph_crawler/observability/decorators/cache.py +126 -0
- graph_crawler-5.2.1/graph_crawler/observability/decorators/log.py +56 -0
- graph_crawler-5.2.1/graph_crawler/observability/decorators/retry.py +121 -0
- graph_crawler-5.2.1/graph_crawler/observability/decorators/timing.py +43 -0
- graph_crawler-5.2.1/graph_crawler/observability/error_tracing.py +363 -0
- graph_crawler-5.2.1/graph_crawler/observability/extensions/__init__.py +18 -0
- graph_crawler-5.2.1/graph_crawler/observability/extensions/memory_guard.py +237 -0
- graph_crawler-5.2.1/graph_crawler/observability/extensions/state_manager.py +319 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/__init__.py +33 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/base.py +82 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/base_metrics_listener.py +18 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/crawl_listener.py +28 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/dlq_listener.py +215 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/error_listener.py +18 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/logging_listener.py +88 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/metrics_listener.py +109 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/node_listener.py +33 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/plugin_listener.py +28 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/storage_listener.py +21 -0
- graph_crawler-5.2.1/graph_crawler/observability/listeners/url_listener.py +29 -0
- graph_crawler-5.2.1/graph_crawler/observability/metrics/__init__.py +23 -0
- graph_crawler-5.2.1/graph_crawler/observability/metrics/memory_profiler.py +508 -0
- graph_crawler-5.2.1/graph_crawler/observability/metrics/metrics_collector.py +408 -0
- graph_crawler-5.2.1/graph_crawler/observability/metrics/prometheus_metrics.py +293 -0
- graph_crawler-5.2.1/graph_crawler/observability/metrics_core.py +395 -0
- graph_crawler-5.2.1/graph_crawler/observability/structured_logging.py +240 -0
- graph_crawler-5.2.1/graph_crawler/observability/tracing.py +291 -0
- graph_crawler-5.2.1/graph_crawler/optimizations/__init__.py +89 -0
- graph_crawler-5.2.1/graph_crawler/optimizations/generators.py +477 -0
- graph_crawler-5.2.1/graph_crawler/optimizations/memory_slots.py +641 -0
- graph_crawler-5.2.1/graph_crawler/optimizations/simhash_numba.py +284 -0
- graph_crawler-5.2.1/graph_crawler/shared/__init__.py +25 -0
- graph_crawler-5.2.1/graph_crawler/shared/constants.py +938 -0
- graph_crawler-5.2.1/graph_crawler/shared/dto/__init__.py +38 -0
- graph_crawler-5.2.1/graph_crawler/shared/dto/edge_dto.py +52 -0
- graph_crawler-5.2.1/graph_crawler/shared/dto/graph_dto.py +97 -0
- graph_crawler-5.2.1/graph_crawler/shared/dto/node_dto.py +193 -0
- graph_crawler-5.2.1/graph_crawler/shared/error_handling/__init__.py +15 -0
- graph_crawler-5.2.1/graph_crawler/shared/error_handling/error_handler.py +333 -0
- graph_crawler-5.2.1/graph_crawler/shared/exceptions.py +394 -0
- graph_crawler-5.2.1/graph_crawler/shared/platform/__init__.py +125 -0
- graph_crawler-5.2.1/graph_crawler/shared/platform/adaptive_resolver.py +414 -0
- graph_crawler-5.2.1/graph_crawler/shared/platform/config.py +635 -0
- graph_crawler-5.2.1/graph_crawler/shared/platform/detector.py +334 -0
- graph_crawler-5.2.1/graph_crawler/shared/platform/diagnostics.py +660 -0
- graph_crawler-5.2.1/graph_crawler/shared/platform/metrics.py +299 -0
- graph_crawler-5.2.1/graph_crawler/shared/security/__init__.py +22 -0
- graph_crawler-5.2.1/graph_crawler/shared/security/url_sanitizer.py +100 -0
- graph_crawler-5.2.1/graph_crawler/shared/security/url_validator.py +299 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/__init__.py +212 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/async_compat.py +140 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/bloom_filter.py +373 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/captcha/__init__.py +36 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/captcha/base.py +92 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/captcha/manager.py +474 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/celery_config.py +332 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/celery_helpers.py +153 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/cgroup_limits.py +227 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/content_decoder.py +150 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/distributed_rate_limiter.py +265 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/distributed_rate_limiter_backends.py +284 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/dns_cache.py +370 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/enterprise_ua_generator.py +294 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/event_publisher_mixin.py +188 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/fast_json.py +240 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/fingerprint.py +36 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/fingerprint_data.py +99 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/fingerprint_generators.py +128 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/fingerprint_profile.py +121 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/fingerprint_stealth.py +105 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/html_utils.py +118 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/id_generator.py +195 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/memory_optimizer.py +536 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/rate_limiter.py +185 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/regex_validator.py +966 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/shadow_dom.py +36 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/text_utils.py +387 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/url_patterns.py +135 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/url_utils.py +595 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/user_agent_rotator.py +333 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/validation_helpers.py +225 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/visualization.py +134 -0
- graph_crawler-5.2.1/graph_crawler/shared/utils/visualization_core.py +566 -0
- graph_crawler-5.2.1/graph_crawler/tools/__init__.py +1 -0
- graph_crawler-5.2.1/graph_crawler/tools/db_cleanup.py +263 -0
- graph_crawler-5.2.1/graph_crawler.egg-info/PKG-INFO +370 -0
- graph_crawler-5.2.1/graph_crawler.egg-info/SOURCES.txt +477 -0
- graph_crawler-5.2.1/pyproject.toml +301 -0
- graph_crawler-5.2.1/setup.cfg +4 -0
- graph_crawler-5.2.0/CHANGELOG.md +0 -3
- graph_crawler-5.2.0/CODE_STYLE.md +0 -1473
- graph_crawler-5.2.0/LICENSE +0 -21
- graph_crawler-5.2.0/MANIFEST.in +0 -19
- graph_crawler-5.2.0/PKG-INFO +0 -366
- graph_crawler-5.2.0/README.md +0 -245
- graph_crawler-5.2.0/graph_crawler/__init__.py +0 -478
- graph_crawler-5.2.0/graph_crawler/__version__.py +0 -7
- graph_crawler-5.2.0/graph_crawler/ai/__init__.py +0 -49
- graph_crawler-5.2.0/graph_crawler/api/__init__.py +0 -24
- graph_crawler-5.2.0/graph_crawler/api/_core.py +0 -281
- graph_crawler-5.2.0/graph_crawler/api/_distributed.py +0 -174
- graph_crawler-5.2.0/graph_crawler/api/_shared.py +0 -120
- graph_crawler-5.2.0/graph_crawler/api/_sitemap_distributed.py +0 -244
- graph_crawler-5.2.0/graph_crawler/api/async_.py +0 -325
- graph_crawler-5.2.0/graph_crawler/api/cli.py +0 -440
- graph_crawler-5.2.0/graph_crawler/api/client/__init__.py +0 -8
- graph_crawler-5.2.0/graph_crawler/api/client/client.py +0 -498
- graph_crawler-5.2.0/graph_crawler/api/history_manager.py +0 -82
- graph_crawler-5.2.0/graph_crawler/api/project_init.py +0 -194
- graph_crawler-5.2.0/graph_crawler/api/server/__init__.py +0 -18
- graph_crawler-5.2.0/graph_crawler/api/server/crawl_monitor.py +0 -145
- graph_crawler-5.2.0/graph_crawler/api/server/dashboard.py +0 -221
- graph_crawler-5.2.0/graph_crawler/api/server/rest_api.py +0 -704
- graph_crawler-5.2.0/graph_crawler/api/server/webhooks.py +0 -421
- graph_crawler-5.2.0/graph_crawler/api/server/websocket_manager.py +0 -89
- graph_crawler-5.2.0/graph_crawler/api/stats_collector.py +0 -115
- graph_crawler-5.2.0/graph_crawler/api/sync.py +0 -491
- graph_crawler-5.2.0/graph_crawler/application/__init__.py +0 -38
- graph_crawler-5.2.0/graph_crawler/application/bootstrap.py +0 -209
- graph_crawler-5.2.0/graph_crawler/application/context/__init__.py +0 -31
- graph_crawler-5.2.0/graph_crawler/application/context/dependency_registry.py +0 -354
- graph_crawler-5.2.0/graph_crawler/application/context/graph_context.py +0 -217
- graph_crawler-5.2.0/graph_crawler/application/context/merge_context.py +0 -221
- graph_crawler-5.2.0/graph_crawler/application/dto/__init__.py +0 -67
- graph_crawler-5.2.0/graph_crawler/application/dto/edge_dto.py +0 -25
- graph_crawler-5.2.0/graph_crawler/application/dto/graph_dto.py +0 -27
- graph_crawler-5.2.0/graph_crawler/application/dto/mappers/__init__.py +0 -14
- graph_crawler-5.2.0/graph_crawler/application/dto/mappers/edge_mapper.py +0 -149
- graph_crawler-5.2.0/graph_crawler/application/dto/mappers/graph_mapper.py +0 -614
- graph_crawler-5.2.0/graph_crawler/application/dto/mappers/node_data_codec.py +0 -190
- graph_crawler-5.2.0/graph_crawler/application/dto/mappers/node_mapper.py +0 -387
- graph_crawler-5.2.0/graph_crawler/application/dto/node_dto.py +0 -27
- graph_crawler-5.2.0/graph_crawler/application/dto/utils.py +0 -272
- graph_crawler-5.2.0/graph_crawler/application/services/__init__.py +0 -60
- graph_crawler-5.2.0/graph_crawler/application/services/application_container.py +0 -208
- graph_crawler-5.2.0/graph_crawler/application/services/driver_factory.py +0 -147
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/__init__.py +0 -26
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/base_exporter.py +0 -150
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/csv_exporter.py +0 -318
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/edge_exporter.py +0 -432
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/excel_exporter.py +0 -301
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/jsonl_exporter.py +0 -290
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/node_exporter.py +0 -283
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/parquet_exporter.py +0 -248
- graph_crawler-5.2.0/graph_crawler/application/services/exporters/sql_exporter.py +0 -267
- graph_crawler-5.2.0/graph_crawler/application/services/finalize.py +0 -115
- graph_crawler-5.2.0/graph_crawler/application/services/low_memory_graph_saver.py +0 -339
- graph_crawler-5.2.0/graph_crawler/application/services/resource_budget.py +0 -179
- graph_crawler-5.2.0/graph_crawler/application/services/scheduling/__init__.py +0 -12
- graph_crawler-5.2.0/graph_crawler/application/services/scheduling/rule_based_scheduler.py +0 -113
- graph_crawler-5.2.0/graph_crawler/application/services/storage_factory.py +0 -195
- graph_crawler-5.2.0/graph_crawler/application/use_cases/__init__.py +0 -11
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/__init__.py +0 -81
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/adaptive_throttler.py +0 -374
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/async_bridge.py +0 -45
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/base_spider.py +0 -156
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/celery_batch_spider.py +0 -658
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/celery_spider.py +0 -448
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/checkpoint.py +0 -421
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/crawl_coordinator.py +0 -1044
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/dead_letter_queue.py +0 -413
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/domain_rate_limiter.py +0 -262
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/filters/__init__.py +0 -10
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/filters/base.py +0 -74
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/filters/domain_filter.py +0 -195
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/filters/domain_patterns.py +0 -30
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/filters/path_filter.py +0 -95
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/incremental_strategy.py +0 -239
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/link_processor.py +0 -908
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/multiprocess_spider.py +0 -511
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/node_scanner.py +0 -808
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/parsers/__init__.py +0 -6
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/parsers/base.py +0 -73
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/parsers/html_parser.py +0 -154
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/progress_tracker.py +0 -235
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/scheduler.py +0 -747
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/serialization_mixin.py +0 -218
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/sitemap_parser.py +0 -662
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/sitemap_processor.py +0 -401
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/sitemap_spider.py +0 -608
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/spider.py +0 -811
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/spider_lifecycle.py +0 -108
- graph_crawler-5.2.0/graph_crawler/application/use_cases/crawling/worker_pool.py +0 -154
- graph_crawler-5.2.0/graph_crawler/application/use_cases/graph_export.py +0 -504
- graph_crawler-5.2.0/graph_crawler/application/use_cases/graph_merge/__init__.py +0 -33
- graph_crawler-5.2.0/graph_crawler/application/use_cases/graph_merge/graph_operations.py +0 -632
- graph_crawler-5.2.0/graph_crawler/application/use_cases/graph_merge/merge_strategies.py +0 -348
- graph_crawler-5.2.0/graph_crawler/data/__init__.py +0 -28
- graph_crawler-5.2.0/graph_crawler/data/backends/__init__.py +0 -21
- graph_crawler-5.2.0/graph_crawler/data/backends/memory.py +0 -486
- graph_crawler-5.2.0/graph_crawler/data/backends/sqlite.py +0 -1866
- graph_crawler-5.2.0/graph_crawler/data/interfaces.py +0 -575
- graph_crawler-5.2.0/graph_crawler/domain/__init__.py +0 -62
- graph_crawler-5.2.0/graph_crawler/domain/context/__init__.py +0 -14
- graph_crawler-5.2.0/graph_crawler/domain/context/crawl_context.py +0 -531
- graph_crawler-5.2.0/graph_crawler/domain/entities/__init__.py +0 -32
- graph_crawler-5.2.0/graph_crawler/domain/entities/edge.py +0 -345
- graph_crawler-5.2.0/graph_crawler/domain/entities/edge_analysis.py +0 -223
- graph_crawler-5.2.0/graph_crawler/domain/entities/graph.py +0 -4120
- graph_crawler-5.2.0/graph_crawler/domain/entities/graph_operations.py +0 -33
- graph_crawler-5.2.0/graph_crawler/domain/entities/graph_statistics.py +0 -13
- graph_crawler-5.2.0/graph_crawler/domain/entities/merge_strategies.py +0 -36
- graph_crawler-5.2.0/graph_crawler/domain/entities/node.py +0 -692
- graph_crawler-5.2.0/graph_crawler/domain/entities/redirect_mode.py +0 -23
- graph_crawler-5.2.0/graph_crawler/domain/entities/registries.py +0 -237
- graph_crawler-5.2.0/graph_crawler/domain/entities/sitemap_node.py +0 -74
- graph_crawler-5.2.0/graph_crawler/domain/entities/strategies.py +0 -202
- graph_crawler-5.2.0/graph_crawler/domain/events/__init__.py +0 -163
- graph_crawler-5.2.0/graph_crawler/domain/events/base.py +0 -58
- graph_crawler-5.2.0/graph_crawler/domain/events/crawl.py +0 -123
- graph_crawler-5.2.0/graph_crawler/domain/events/edge.py +0 -46
- graph_crawler-5.2.0/graph_crawler/domain/events/event_bus.py +0 -251
- graph_crawler-5.2.0/graph_crawler/domain/events/events.py +0 -313
- graph_crawler-5.2.0/graph_crawler/domain/events/fetch.py +0 -123
- graph_crawler-5.2.0/graph_crawler/domain/events/idempotent_subscriber.py +0 -120
- graph_crawler-5.2.0/graph_crawler/domain/events/legacy_type_map.py +0 -45
- graph_crawler-5.2.0/graph_crawler/domain/events/llm.py +0 -158
- graph_crawler-5.2.0/graph_crawler/domain/events/node.py +0 -124
- graph_crawler-5.2.0/graph_crawler/domain/events/plugin.py +0 -96
- graph_crawler-5.2.0/graph_crawler/domain/events/scheduler.py +0 -102
- graph_crawler-5.2.0/graph_crawler/domain/events/storage.py +0 -168
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/__init__.py +0 -111
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/adapter.py +0 -29
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/control_channel.py +0 -371
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/crawl_context.py +0 -49
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/distributed_spider.py +0 -63
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/driver.py +0 -88
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/event_bus.py +0 -61
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/exporters.py +0 -83
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/filter.py +0 -19
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/merge_context.py +0 -58
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/node_interfaces.py +0 -376
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/parser.py +0 -110
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/plugin_manager.py +0 -53
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/processor.py +0 -11
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/scanner.py +0 -57
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/scheduler.py +0 -43
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/scheduling/__init__.py +0 -40
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/scheduling/frontier.py +0 -97
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/scheduling/scheduler.py +0 -107
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/spider.py +0 -63
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/stop_condition.py +0 -211
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/storage/__init__.py +0 -43
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/storage/base.py +0 -70
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/storage/eviction.py +0 -102
- graph_crawler-5.2.0/graph_crawler/domain/interfaces/storage/queue.py +0 -234
- graph_crawler-5.2.0/graph_crawler/domain/services/__init__.py +0 -216
- graph_crawler-5.2.0/graph_crawler/domain/services/adjacency_maintenance.py +0 -95
- graph_crawler-5.2.0/graph_crawler/domain/services/cycle_detection.py +0 -92
- graph_crawler-5.2.0/graph_crawler/domain/services/degree_ranking.py +0 -47
- graph_crawler-5.2.0/graph_crawler/domain/services/depth_context.py +0 -123
- graph_crawler-5.2.0/graph_crawler/domain/services/display_title.py +0 -47
- graph_crawler-5.2.0/graph_crawler/domain/services/duplicate_detection.py +0 -141
- graph_crawler-5.2.0/graph_crawler/domain/services/duplicate_selector.py +0 -127
- graph_crawler-5.2.0/graph_crawler/domain/services/duplicate_stats.py +0 -63
- graph_crawler-5.2.0/graph_crawler/domain/services/edge_filter.py +0 -82
- graph_crawler-5.2.0/graph_crawler/domain/services/edge_statistics.py +0 -110
- graph_crawler-5.2.0/graph_crawler/domain/services/eviction_policy.py +0 -83
- graph_crawler-5.2.0/graph_crawler/domain/services/graph_query_cascade.py +0 -178
- graph_crawler-5.2.0/graph_crawler/domain/services/graph_statistics.py +0 -186
- graph_crawler-5.2.0/graph_crawler/domain/services/graph_traversal.py +0 -150
- graph_crawler-5.2.0/graph_crawler/domain/services/language_versions.py +0 -73
- graph_crawler-5.2.0/graph_crawler/domain/services/lsh_index.py +0 -99
- graph_crawler-5.2.0/graph_crawler/domain/services/minimap_builder.py +0 -147
- graph_crawler-5.2.0/graph_crawler/domain/services/node_content_resolver.py +0 -128
- graph_crawler-5.2.0/graph_crawler/domain/services/node_view_builder.py +0 -163
- graph_crawler-5.2.0/graph_crawler/domain/services/pagination_guards.py +0 -136
- graph_crawler-5.2.0/graph_crawler/domain/services/predicate_ops.py +0 -77
- graph_crawler-5.2.0/graph_crawler/domain/services/schema_filter.py +0 -138
- graph_crawler-5.2.0/graph_crawler/domain/services/search_haystack.py +0 -102
- graph_crawler-5.2.0/graph_crawler/domain/services/simhash_clustering.py +0 -96
- graph_crawler-5.2.0/graph_crawler/domain/services/simhash_fallback.py +0 -59
- graph_crawler-5.2.0/graph_crawler/domain/services/similarity_ranking.py +0 -62
- graph_crawler-5.2.0/graph_crawler/domain/services/text_search.py +0 -157
- graph_crawler-5.2.0/graph_crawler/domain/services/url_clustering.py +0 -88
- graph_crawler-5.2.0/graph_crawler/domain/services/url_deduplication.py +0 -101
- graph_crawler-5.2.0/graph_crawler/domain/services/url_normalizer.py +0 -108
- graph_crawler-5.2.0/graph_crawler/domain/services/url_rule_matcher.py +0 -103
- graph_crawler-5.2.0/graph_crawler/domain/services/url_tree_builder.py +0 -197
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/__init__.py +0 -88
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/configs.py +0 -884
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/domain_patterns.py +0 -71
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/fetch_options.py +0 -57
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/html_document.py +0 -59
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/lifecycle.py +0 -30
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/models.py +0 -1316
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/redirect_hop.py +0 -49
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/scheduling/__init__.py +0 -23
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/scheduling/crawl_request.py +0 -153
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/scheduling/retry_policy.py +0 -109
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/settings.py +0 -350
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/url_normalization.py +0 -496
- graph_crawler-5.2.0/graph_crawler/domain/value_objects/views.py +0 -293
- graph_crawler-5.2.0/graph_crawler/extensions/__init__.py +0 -1
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/__init__.py +0 -65
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/base.py +0 -147
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/cache_middleware.py +0 -277
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/chain.py +0 -159
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/error_recovery_middleware.py +0 -442
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/logging_middleware.py +0 -108
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/proxy_health.py +0 -144
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/proxy_middleware.py +0 -208
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/proxy_models.py +0 -84
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/proxy_selection.py +0 -87
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/rate_limit_middleware.py +0 -262
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/request_response_middleware.py +0 -476
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/retry_middleware.py +0 -279
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/robots_cache.py +0 -85
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/robots_middleware.py +0 -110
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/robots_validator.py +0 -60
- graph_crawler-5.2.0/graph_crawler/extensions/middleware/user_agent_middleware.py +0 -251
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/__init__.py +0 -57
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/builtin/__init__.py +0 -7
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/builtin/stats_export_plugin.py +0 -98
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/crawl_engine/__init__.py +0 -24
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/crawl_engine/base.py +0 -155
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/crawl_engine/priority_provider.py +0 -247
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/crawl_engine/smart_crawl.py +0 -306
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/__init__.py +0 -128
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/anti_bot_detection.py +0 -52
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/anti_bot_playwright.py +0 -85
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/anti_bot_scripts.py +0 -133
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/anti_bot_stealth.py +0 -177
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/base.py +0 -121
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/captcha/__init__.py +0 -22
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/captcha/detector.py +0 -94
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/captcha/models.py +0 -74
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/captcha/plugin.py +0 -228
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/engine/captcha/services.py +0 -389
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/__init__.py +0 -86
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/base.py +0 -432
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/content_extractors/__init__.py +0 -15
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/content_extractors/base.py +0 -82
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/content_extractors/goose3_extractor.py +0 -80
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/content_extractors/newspaper_extractor.py +0 -93
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/content_extractors/plugin.py +0 -132
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/content_extractors/readability_extractor.py +0 -91
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/defaults.py +0 -32
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/extractors/__init__.py +0 -30
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/extractors/email_extractor.py +0 -146
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/extractors/phone_extractor.py +0 -136
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/extractors/price_extractor.py +0 -137
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/links.py +0 -184
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/markdown_plugin.py +0 -249
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/metadata.py +0 -391
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/smart_page_finder.py +0 -749
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/__init__.py +0 -51
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/constants.py +0 -27
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/exceptions.py +0 -18
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/extractor.py +0 -361
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/options.py +0 -62
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/parsers/__init__.py +0 -25
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/parsers/base.py +0 -43
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/parsers/jsonld.py +0 -331
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/parsers/microdata.py +0 -117
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/parsers/opengraph.py +0 -66
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/parsers/rdfa.py +0 -122
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/parsers/twitter.py +0 -66
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/plugin.py +0 -132
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/structured_data/result.py +0 -233
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/text.py +0 -76
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/node/url_normalizer.py +0 -363
- graph_crawler-5.2.0/graph_crawler/extensions/plugins/registry.py +0 -97
- graph_crawler-5.2.0/graph_crawler/infrastructure/__init__.py +0 -1
- graph_crawler-5.2.0/graph_crawler/infrastructure/adapters/__init__.py +0 -60
- graph_crawler-5.2.0/graph_crawler/infrastructure/adapters/base.py +0 -498
- graph_crawler-5.2.0/graph_crawler/infrastructure/adapters/selectolax_adapter.py +0 -234
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/__init__.py +0 -37
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/celery_app.py +0 -202
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/celery_batch.py +0 -284
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/celery_job_task.py +0 -415
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/celery_unified.py +0 -419
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/config.py +0 -201
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/easy_crawler.py +0 -279
- graph_crawler-5.2.0/graph_crawler/infrastructure/messaging/worker_api.py +0 -607
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/__init__.py +0 -135
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/auto_storage.py +0 -336
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/base.py +0 -111
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/eviction.py +0 -100
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/graph_repository.py +0 -401
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/json/__init__.py +0 -10
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/json_storage.py +0 -375
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/lmdb_eviction_storage.py +0 -403
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/memory/__init__.py +0 -1
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/memory_dedup_store.py +0 -91
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/memory_frontier.py +0 -180
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/memory_politeness_store.py +0 -88
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/memory_storage.py +0 -166
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/mongodb_storage.py +0 -383
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/naming_strategy.py +0 -174
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/postgresql_storage.py +0 -449
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/protocols/__init__.py +0 -1
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/redis_dedup_store.py +0 -119
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/redis_politeness_store.py +0 -122
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/repository.py +0 -130
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/sqlite/__init__.py +0 -10
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/sqlite_eviction_storage.py +0 -918
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/sqlite_storage.py +0 -775
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/__init__.py +0 -47
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/file_job_storage.py +0 -245
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/file_queue_storage.py +0 -248
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/memory_job_storage.py +0 -94
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/memory_queue_storage.py +0 -117
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/postgresql_job_storage.py +0 -317
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/postgresql_queue_storage.py +0 -364
- graph_crawler-5.2.0/graph_crawler/infrastructure/persistence/unified/unified_storage.py +0 -244
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/__init__.py +0 -135
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/__init__.py +0 -38
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/config.py +0 -47
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/context.py +0 -55
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/driver.py +0 -724
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/driver_curl_cffi.py +0 -407
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/plugins/__init__.py +0 -48
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle.py +0 -484
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle_adaptive.py +0 -1435
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/plugins/headers.py +0 -69
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/plugins/http_cache.py +0 -321
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/plugins/rate_limiter.py +0 -96
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/plugins/retry.py +0 -316
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/async_http/stages.py +0 -33
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/base.py +0 -324
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/base_plugin.py +0 -151
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/compression/__init__.py +0 -23
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/compression/strategy.py +0 -219
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/connection_pool.py +0 -349
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/context.py +0 -114
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/core/__init__.py +0 -15
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/core/base_async.py +0 -378
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/core/body_decoder.py +0 -26
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/core/mixins.py +0 -258
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/core/redirect_utils.py +0 -168
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/escalation.py +0 -937
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/factory.py +0 -210
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/__init__.py +0 -19
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/adaptive_semaphore.py +0 -65
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/batch_scheduler.py +0 -764
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/browser_factory.py +0 -576
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/browser_profile.py +0 -718
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/config.py +0 -84
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/context.py +0 -46
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/driver.py +0 -80
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/engine.py +0 -465
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/fetch_metrics.py +0 -115
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/net/__init__.py +0 -41
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/net/geoip.py +0 -136
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/net/proxy_pool.py +0 -225
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/net/rate_limiter.py +0 -139
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/page_fetch.py +0 -864
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/__init__.py +0 -67
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/_network_record.py +0 -59
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/captcha_detector.py +0 -315
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/captcha_solver.py +0 -108
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/cookie_consent.py +0 -565
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/form_filler.py +0 -177
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/human_bezier.py +0 -297
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/network_log.py +0 -348
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/ram_adaptive.py +0 -208
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/screenshot.py +0 -169
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/plugins/user_profile.py +0 -556
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/pool_lifecycle.py +0 -658
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/pooled_driver.py +0 -698
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/stages.py +0 -35
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/playwright/stealth_hints.py +0 -153
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/plugin_manager.py +0 -316
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/protocols.py +0 -118
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/undetected/__init__.py +0 -8
- graph_crawler-5.2.0/graph_crawler/infrastructure/transport/undetected/async_driver.py +0 -465
- graph_crawler-5.2.0/graph_crawler/native/README.md +0 -110
- graph_crawler-5.2.0/graph_crawler/native/__init__.py +0 -200
- graph_crawler-5.2.0/graph_crawler/native/bloom_filter.pyx +0 -255
- graph_crawler-5.2.0/graph_crawler/native/html_parser.pyx +0 -262
- graph_crawler-5.2.0/graph_crawler/native/setup.py +0 -101
- graph_crawler-5.2.0/graph_crawler/native/url_utils.pyx +0 -209
- graph_crawler-5.2.0/graph_crawler/observability/__init__.py +0 -62
- graph_crawler-5.2.0/graph_crawler/observability/decorators/__init__.py +0 -11
- graph_crawler-5.2.0/graph_crawler/observability/decorators/cache.py +0 -126
- graph_crawler-5.2.0/graph_crawler/observability/decorators/log.py +0 -56
- graph_crawler-5.2.0/graph_crawler/observability/decorators/retry.py +0 -121
- graph_crawler-5.2.0/graph_crawler/observability/decorators/timing.py +0 -43
- graph_crawler-5.2.0/graph_crawler/observability/error_tracing.py +0 -363
- graph_crawler-5.2.0/graph_crawler/observability/extensions/__init__.py +0 -18
- graph_crawler-5.2.0/graph_crawler/observability/extensions/memory_guard.py +0 -237
- graph_crawler-5.2.0/graph_crawler/observability/extensions/state_manager.py +0 -319
- graph_crawler-5.2.0/graph_crawler/observability/listeners/__init__.py +0 -33
- graph_crawler-5.2.0/graph_crawler/observability/listeners/base.py +0 -82
- graph_crawler-5.2.0/graph_crawler/observability/listeners/base_metrics_listener.py +0 -18
- graph_crawler-5.2.0/graph_crawler/observability/listeners/crawl_listener.py +0 -28
- graph_crawler-5.2.0/graph_crawler/observability/listeners/dlq_listener.py +0 -215
- graph_crawler-5.2.0/graph_crawler/observability/listeners/error_listener.py +0 -18
- graph_crawler-5.2.0/graph_crawler/observability/listeners/logging_listener.py +0 -88
- graph_crawler-5.2.0/graph_crawler/observability/listeners/metrics_listener.py +0 -109
- graph_crawler-5.2.0/graph_crawler/observability/listeners/node_listener.py +0 -33
- graph_crawler-5.2.0/graph_crawler/observability/listeners/plugin_listener.py +0 -28
- graph_crawler-5.2.0/graph_crawler/observability/listeners/storage_listener.py +0 -21
- graph_crawler-5.2.0/graph_crawler/observability/listeners/url_listener.py +0 -29
- graph_crawler-5.2.0/graph_crawler/observability/metrics/__init__.py +0 -23
- graph_crawler-5.2.0/graph_crawler/observability/metrics/memory_profiler.py +0 -508
- graph_crawler-5.2.0/graph_crawler/observability/metrics/metrics_collector.py +0 -408
- graph_crawler-5.2.0/graph_crawler/observability/metrics/prometheus_metrics.py +0 -293
- graph_crawler-5.2.0/graph_crawler/observability/metrics_core.py +0 -395
- graph_crawler-5.2.0/graph_crawler/observability/structured_logging.py +0 -240
- graph_crawler-5.2.0/graph_crawler/observability/tracing.py +0 -291
- graph_crawler-5.2.0/graph_crawler/optimizations/__init__.py +0 -89
- graph_crawler-5.2.0/graph_crawler/optimizations/generators.py +0 -477
- graph_crawler-5.2.0/graph_crawler/optimizations/memory_slots.py +0 -641
- graph_crawler-5.2.0/graph_crawler/optimizations/simhash_numba.py +0 -284
- graph_crawler-5.2.0/graph_crawler/shared/__init__.py +0 -25
- graph_crawler-5.2.0/graph_crawler/shared/constants.py +0 -938
- graph_crawler-5.2.0/graph_crawler/shared/dto/__init__.py +0 -38
- graph_crawler-5.2.0/graph_crawler/shared/dto/edge_dto.py +0 -52
- graph_crawler-5.2.0/graph_crawler/shared/dto/graph_dto.py +0 -97
- graph_crawler-5.2.0/graph_crawler/shared/dto/node_dto.py +0 -193
- graph_crawler-5.2.0/graph_crawler/shared/error_handling/__init__.py +0 -15
- graph_crawler-5.2.0/graph_crawler/shared/error_handling/error_handler.py +0 -333
- graph_crawler-5.2.0/graph_crawler/shared/exceptions.py +0 -394
- graph_crawler-5.2.0/graph_crawler/shared/platform/__init__.py +0 -125
- graph_crawler-5.2.0/graph_crawler/shared/platform/adaptive_resolver.py +0 -414
- graph_crawler-5.2.0/graph_crawler/shared/platform/config.py +0 -635
- graph_crawler-5.2.0/graph_crawler/shared/platform/detector.py +0 -334
- graph_crawler-5.2.0/graph_crawler/shared/platform/diagnostics.py +0 -660
- graph_crawler-5.2.0/graph_crawler/shared/platform/metrics.py +0 -299
- graph_crawler-5.2.0/graph_crawler/shared/security/__init__.py +0 -22
- graph_crawler-5.2.0/graph_crawler/shared/security/url_sanitizer.py +0 -100
- graph_crawler-5.2.0/graph_crawler/shared/security/url_validator.py +0 -299
- graph_crawler-5.2.0/graph_crawler/shared/utils/__init__.py +0 -212
- graph_crawler-5.2.0/graph_crawler/shared/utils/async_compat.py +0 -140
- graph_crawler-5.2.0/graph_crawler/shared/utils/bloom_filter.py +0 -373
- graph_crawler-5.2.0/graph_crawler/shared/utils/captcha/__init__.py +0 -36
- graph_crawler-5.2.0/graph_crawler/shared/utils/captcha/base.py +0 -92
- graph_crawler-5.2.0/graph_crawler/shared/utils/captcha/manager.py +0 -474
- graph_crawler-5.2.0/graph_crawler/shared/utils/celery_config.py +0 -332
- graph_crawler-5.2.0/graph_crawler/shared/utils/celery_helpers.py +0 -153
- graph_crawler-5.2.0/graph_crawler/shared/utils/cgroup_limits.py +0 -227
- graph_crawler-5.2.0/graph_crawler/shared/utils/content_decoder.py +0 -150
- graph_crawler-5.2.0/graph_crawler/shared/utils/distributed_rate_limiter.py +0 -265
- graph_crawler-5.2.0/graph_crawler/shared/utils/distributed_rate_limiter_backends.py +0 -284
- graph_crawler-5.2.0/graph_crawler/shared/utils/dns_cache.py +0 -370
- graph_crawler-5.2.0/graph_crawler/shared/utils/enterprise_ua_generator.py +0 -294
- graph_crawler-5.2.0/graph_crawler/shared/utils/event_publisher_mixin.py +0 -188
- graph_crawler-5.2.0/graph_crawler/shared/utils/fast_json.py +0 -240
- graph_crawler-5.2.0/graph_crawler/shared/utils/fingerprint.py +0 -36
- graph_crawler-5.2.0/graph_crawler/shared/utils/fingerprint_data.py +0 -99
- graph_crawler-5.2.0/graph_crawler/shared/utils/fingerprint_generators.py +0 -128
- graph_crawler-5.2.0/graph_crawler/shared/utils/fingerprint_profile.py +0 -121
- graph_crawler-5.2.0/graph_crawler/shared/utils/fingerprint_stealth.py +0 -105
- graph_crawler-5.2.0/graph_crawler/shared/utils/html_utils.py +0 -118
- graph_crawler-5.2.0/graph_crawler/shared/utils/id_generator.py +0 -195
- graph_crawler-5.2.0/graph_crawler/shared/utils/memory_optimizer.py +0 -536
- graph_crawler-5.2.0/graph_crawler/shared/utils/rate_limiter.py +0 -185
- graph_crawler-5.2.0/graph_crawler/shared/utils/regex_validator.py +0 -966
- graph_crawler-5.2.0/graph_crawler/shared/utils/text_utils.py +0 -387
- graph_crawler-5.2.0/graph_crawler/shared/utils/url_patterns.py +0 -135
- graph_crawler-5.2.0/graph_crawler/shared/utils/url_utils.py +0 -595
- graph_crawler-5.2.0/graph_crawler/shared/utils/user_agent_rotator.py +0 -333
- graph_crawler-5.2.0/graph_crawler/shared/utils/validation_helpers.py +0 -225
- graph_crawler-5.2.0/graph_crawler/shared/utils/visualization.py +0 -134
- graph_crawler-5.2.0/graph_crawler/shared/utils/visualization_core.py +0 -566
- graph_crawler-5.2.0/graph_crawler/tools/__init__.py +0 -1
- graph_crawler-5.2.0/graph_crawler/tools/db_cleanup.py +0 -263
- graph_crawler-5.2.0/graph_crawler.egg-info/PKG-INFO +0 -366
- graph_crawler-5.2.0/graph_crawler.egg-info/SOURCES.txt +0 -476
- graph_crawler-5.2.0/pyproject.toml +0 -301
- graph_crawler-5.2.0/setup.cfg +0 -4
- {graph_crawler-5.2.0 → graph_crawler-5.2.1}/graph_crawler.egg-info/dependency_links.txt +0 -0
- {graph_crawler-5.2.0 → graph_crawler-5.2.1}/graph_crawler.egg-info/entry_points.txt +0 -0
- {graph_crawler-5.2.0 → graph_crawler-5.2.1}/graph_crawler.egg-info/requires.txt +0 -0
- {graph_crawler-5.2.0 → graph_crawler-5.2.1}/graph_crawler.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 5.2.1 — 2026-06
|
|
4
|
+
|
|
5
|
+
### Fixed (freelance cases 33/34 — `ai-graph-crawler/docs/FREELANCE_CASES.md`)
|
|
6
|
+
- **Captured XHR/fetch traffic could not be replayed outside the browser.** `NetworkLogPlugin` recorded the
|
|
7
|
+
URL and method of a request but not its body, so every POST/GraphQL endpoint (robota.ua lists vacancies via
|
|
8
|
+
`POST dracula.robota.ua/?q=getPublishedVacanciesList`) was unusable: a GET of the same URL returns 400.
|
|
9
|
+
Records now carry `post_data` and (on `response`) `request_headers`.
|
|
10
|
+
- **GraphQL responses overwrote each other.** `body_ref` was `sha1(url|status|content-type)` — all operations
|
|
11
|
+
POSTed to one `/graphql` URL shared a key and only the last body survived. The key now includes method and
|
|
12
|
+
request body.
|
|
13
|
+
- **JSON family by default.** The capture allow-list matched exact MIME types only; `application/graphql-
|
|
14
|
+
response+json`, `problem+json`, `vnd.api+json`, `text/json` were dropped. Without an explicit
|
|
15
|
+
`capture_content_types` every `*/json` and `*+json` type is captured (RFC 6839). Default `max_body_kb` 64 → 256
|
|
16
|
+
(listing APIs routinely exceed 64 KB).
|
|
17
|
+
- **Shadow DOM was invisible.** `page.content()` serializes only light DOM: content of open shadow roots (web
|
|
18
|
+
components, embedded price widgets) never reached the node. When a page has open shadow roots, the browser
|
|
19
|
+
driver serializes it with `Element.getHTML({shadowRoots})` and expands the declarative shadow roots into their
|
|
20
|
+
hosts (`shared/utils/shadow_dom.expose_shadow_roots`) — Lexbor, like the HTML spec, does not descend into
|
|
21
|
+
`<template>` content, so a plain declarative-shadow-DOM serialization would still hide it from selectors and link
|
|
22
|
+
extraction. Pages without shadow roots are untouched.
|
|
23
|
+
- `tests/unit/domain/entities/test_graph_new_features.py` still expected the `DeprecationWarning` that
|
|
24
|
+
`export_nodes()` stopped emitting in 4aab7525; it now asserts the opposite.
|
|
25
|
+
|
|
26
|
+
### Fixed (real-site audit, round 2 — `docs/REAL_SITE_TESTS.md` §1.2)
|
|
27
|
+
- **Ctrl+C during `crawl()` hung until the crawl-level timeout** (28 s with `timeout=25`; forever without
|
|
28
|
+
one). `asyncio.wait_for` in Python 3.11 swallows the outer cancellation when the awaited coroutine finishes
|
|
29
|
+
at the same moment, so some workers survived `KeyboardInterrupt` and kept crawling. `NodeScanner` and the
|
|
30
|
+
escalation tier budget now use `asyncio.timeout()`; `CrawlCoordinator` cancels its workers on
|
|
31
|
+
`CancelledError`. Ctrl+C now returns in ~0.3 s.
|
|
32
|
+
- **`same_domain=False` was ignored** — without `allowed_domains` the `DomainFilter` default
|
|
33
|
+
(`domain+subdomains`) still applied and external links never entered the graph. Now maps to `allowed_domains=["*"]`.
|
|
34
|
+
- **`graph.metadata["stop_reason"]` was `None` after `timeout=` / `max_pages`** — only stop conditions were
|
|
35
|
+
recorded. Now `"timeout"`, `"max_pages"` or `"limit"`.
|
|
36
|
+
- **Network errors were invisible on the node**: a DNS/connection failure left `response_status=None`,
|
|
37
|
+
`scanned=True` and no message; `get_failed_nodes()` returned `[]`. The error text is now in
|
|
38
|
+
`node.metadata["error"]`, the HTTP status (if any) is kept, and `get_failed_nodes()` with default
|
|
39
|
+
arguments includes network-error nodes.
|
|
40
|
+
- **`storage="json", storage_config={"path": "site.json"}` was silently ignored** (file written to
|
|
41
|
+
`crawler_data/json/graph.json`). `path` is now honoured, like for sqlite (`JSONStorage(file_name=)`).
|
|
42
|
+
- `Graph.export_nodes()` / `Graph.export_edges()` are no longer deprecated: they are the public one-liners the
|
|
43
|
+
README shows and now delegate to `GraphExportUseCase` silently (no `DeprecationWarning`).
|
|
44
|
+
- `tests/manual/real_sites/run_all.py -j N` runs scenarios in parallel; `tests/manual/real_sites/test_user_cases.py`
|
|
45
|
+
— 23 pytest user scenarios on Wikipedia / robota.ua / GitHub / example.com, each hard-capped at 40 s.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- **Engine contract verified end-to-end** (audit `06_browser_engine.md` §4, now closed). `tests/transport/
|
|
49
|
+
test_engine_contract.py` drives the real `PlaywrightDriver.fetch()` through three engines registered via the
|
|
50
|
+
public `register_engine()` on a recording fake SDK: the call sequence is byte-for-byte identical across
|
|
51
|
+
engines, stealth is injected iff `provides_stealth is False`, and `executable_path`/`ignore_default_args`/
|
|
52
|
+
launch args come only from the engine. No runtime code changed.
|
|
53
|
+
- **`LexborDocument.clean_text()` no longer re-parses the page** (audit `01_parser_audit.md` §4 "parse once",
|
|
54
|
+
`00_interim_analysis.md` §3.4). To strip `script/style/noscript/svg/head` without mutating the shared tree it
|
|
55
|
+
serialised the document and built a second `LexborHTMLParser` — i.e. every page with the default
|
|
56
|
+
`TextExtractorPlugin` was parsed twice (`count_parses.py`: 2.0 → **1.0** per page; with `MarkdownPlugin`
|
|
57
|
+
1 parse + 1 clone). It now uses `tree.clone()`. `docs/audit/benchmarks/count_parses.py` works without
|
|
58
|
+
bs4/lxml and counts `generate_from_tree` clones.
|
|
59
|
+
- **One `ContentDecoder` for every HTTP tier** (audit `docs/audit/01_parser_audit.md` §5 "no parser accepts
|
|
60
|
+
bytes"). `AsyncDriver` (aiohttp) and `AsyncCurlCffiDriver` (curl_cffi) no longer rely on the client's own
|
|
61
|
+
`response.text`/`.text()`: they read the raw body and decode it through `ContentDecoder`
|
|
62
|
+
(`Content-Type` charset → `<meta charset>` → BOM → chardet → strict utf-8). Pages whose charset is only
|
|
63
|
+
declared in `<meta>` (e.g. windows-1251 without a header) were previously decoded as utf-8 by aiohttp,
|
|
64
|
+
failed, and silently became `html=None` with a "successful" 200. An undecodable body is now reported as
|
|
65
|
+
`FetchResponse.error` (`"ContentDecoder: cannot decode body …"`) with the status code preserved;
|
|
66
|
+
`ConnectionPoolManager.fetch_text()` goes through the same decoder. `FetchResponse.html` is a strict
|
|
67
|
+
`str` field — passing `bytes` raises `ValidationError` instead of being coerced. Browser tiers
|
|
68
|
+
(Playwright `page.content()`, nodriver `tab.get_content()`) already return `str`. Contract test:
|
|
69
|
+
`tests/transport/test_html_is_str_contract.py` (driver matrix returns `str`; cp1251 via meta/header;
|
|
70
|
+
binary → error).
|
|
71
|
+
- **Lazy public facade** (audit `docs/audit/04_dependency_map.md` §5 п.3). `graph_crawler/__init__.py` now
|
|
72
|
+
eagerly imports only `crawl`, `async_crawl`, `Graph`, `Node`, `save_graph`, `load_graph`,
|
|
73
|
+
`BaseStopCondition`; every other name in `__all__` (drivers, storages, exceptions, settings, views,
|
|
74
|
+
celery tasks, …) resolves on first access via module `__getattr__` and is cached. `aiohttp` is no longer
|
|
75
|
+
loaded by `import graph_crawler`. `bootstrap()` no longer calls `collect_system_metrics()`
|
|
76
|
+
(`psutil.cpu_percent(interval=0.1)` blocked import for 100 ms for a DEBUG line). Import time here:
|
|
77
|
+
470 ms → 228 ms. Optional names (`PlaywrightDriver`, `celery`, `EasyDistributedCrawler`, …) still return
|
|
78
|
+
`None` without their extra.
|
|
79
|
+
- **Escalation re-probe replays the solving tier's User-Agent** (audit `03_escalation.md` §3/§6).
|
|
80
|
+
Playwright and nodriver now export `navigator.userAgent` as `extras["user_agent"]`;
|
|
81
|
+
`SessionState.absorb` records it (pinned once the session is solved, like `impersonate`/`proxy`) and
|
|
82
|
+
`EscalatingDriver._fetch_tier` sends it as `extra_headers={"User-Agent": …}` to HTTP/TLS tiers together
|
|
83
|
+
with the stored cookies. `cf_clearance` is bound to UA+IP+JA4, so a re-probe on Tier 1 with aiohttp's
|
|
84
|
+
default UA was rejected and the host never descended from the browser tier.
|
|
85
|
+
|
|
86
|
+
### Removed
|
|
87
|
+
- **`NodePluginContext.parser`** (audit `01_parser_audit.md` §4 "parse once"). Node plugins now read the
|
|
88
|
+
single Lexbor tree through the `HTMLDocument`/`HTMLNode` protocols: `LinkExtractorPlugin`
|
|
89
|
+
(`doc.css("a[href]")`, `doc.base_href()`), `MetadataExtractorPlugin`, `TextExtractorPlugin`
|
|
90
|
+
(`doc.clean_text()`, new in the protocol), `StructuredDataPlugin` (OG/Twitter/Microdata/RDFa parsers take
|
|
91
|
+
an `HTMLDocument`; `StructuredDataExtractor.extract(html=, doc=)`), `Email`/`PhoneExtractorPlugin`.
|
|
92
|
+
Migration: `context.parser.find_all(sel)` → `context.html_tree.css(sel)`, `.find()` → `.css_first()`,
|
|
93
|
+
`el.get_attribute()` → `el.attr()`. Fixed along the way in `LexborNode`: `attr()` returns `""` (not
|
|
94
|
+
`None`) for valueless boolean attributes such as `itemscope`, so nested Microdata/RDFa items are now
|
|
95
|
+
detected; `css()`/`css_first()` return descendants only (selectolax included the node itself, which made
|
|
96
|
+
Microdata recurse to `max_nesting_depth`).
|
|
97
|
+
- **`PooledPlaywrightDriver` legacy batch path** (audit `06_browser_engine.md` §3): `batch_legacy.py`
|
|
98
|
+
(`LegacyBatch._fetch_batch_legacy`, `_fetch_chain`) is gone. `persistent_browser=False` keeps its
|
|
99
|
+
"launch/stop per batch" semantics through the pool path: after a batch, once no fetch is in flight, the
|
|
100
|
+
pool and the engine session are closed (`_close_pool()` + `_stop_persistent_session()`, shared with
|
|
101
|
+
`close()`). Dead `self.playwright`/`self.browsers` cleanup removed from `close()`.
|
|
102
|
+
- **Escalation 6.0 (audit `docs/audit/03_escalation.md`, Vector 2).** `classify_block()` rewritten to the
|
|
103
|
+
6.0 decision table: challenge/captcha vendor headers first, then unambiguous body captcha/challenge
|
|
104
|
+
markers (ahead of vendor hard-block headers), then short/blocking-page widgets, status-based verdicts
|
|
105
|
+
and empty-2xx. A bare `401/403/405` with no vendor markers is no longer a block. The classifier corpus
|
|
106
|
+
(`docs/audit/benchmarks/classifier_corpus.py`) goes 25/37 → **37/37**.
|
|
107
|
+
- `needs_browser` heuristic (SPA shell: little visible text + SPA root / `<noscript>` JS hint / no
|
|
108
|
+
`<a href>`) is now the default `EscalationPolicy.needs_browser`; on a clean HTTP/TLS response it jumps
|
|
109
|
+
straight to the first browser tier (`escalation_reason="needs_browser"`).
|
|
110
|
+
- Per-tier `TierTimeouts` + `escalation_deadline_s` (60s) budget: a tier is skipped (last response
|
|
111
|
+
returned, browser never started) when the remaining budget is below its `min_budget`; each tier fetch
|
|
112
|
+
is wrapped in `asyncio.wait_for`. New `PER_NODE_FETCH_TIMEOUT` constant with a validator warning.
|
|
113
|
+
- Cross-tier session: `SessionState` / `HostSessionStore` carry solved cookies (`cf_clearance`, `__cf_bm`,
|
|
114
|
+
`datadome`, …) forward and back down to cheaper tiers on re-probe; `impersonate`/`proxy` are pinned once
|
|
115
|
+
a session is solved. curl_cffi pins the impersonate fingerprint; Playwright/nodriver export context
|
|
116
|
+
cookies via `extras["cookies"]`.
|
|
117
|
+
- `extras` contract: every driver stamps `channel`/`driver`/`engine` (via `BaseDriver`/`BaseAsyncDriver`
|
|
118
|
+
`_stamp_extras` + `_finalize_response`) even outside escalation.
|
|
119
|
+
- New Prometheus metrics `crawl_fetch_duration_seconds{channel,engine}`, `crawl_escalations_total`,
|
|
120
|
+
`crawl_escalation_deadline_hits_total`.
|
|
121
|
+
|
|
122
|
+
- **HTML parsing: Lexbor (selectolax) is the only core parser** (audit `docs/audit/01_parser_audit.md`).
|
|
123
|
+
`beautifulsoup4`, `lxml`, `lxml_html_clean` removed from `[project].dependencies`;
|
|
124
|
+
`BeautifulSoupAdapter`, `LxmlAdapter`, `ScrapyAdapter` deleted. New `HTMLDocument` / `HTMLNode`
|
|
125
|
+
protocols in `domain/value_objects/html_document.py`, implemented by `LexborDocument` in
|
|
126
|
+
`infrastructure/adapters/selectolax_adapter.py`. `<template>` is renamed to `gc-template` before
|
|
127
|
+
parsing so Vue/React SSR links inside templates are not lost. `IParser.parse()` returns `HTMLDocument`;
|
|
128
|
+
`NodePluginContext.html_tree` is now a `LexborDocument`. `get_parser()` accepts `auto|selectolax|lexbor`.
|
|
129
|
+
- `HTMLUtils.extract_links/extract_text/extract_metadata` accept an `HTMLDocument` (string input still
|
|
130
|
+
works but is deprecated).
|
|
131
|
+
- `SitemapParser.parse_large_sitemap_streaming()` uses stdlib `iterparse` by default; lxml is an
|
|
132
|
+
optional fast-path via the new extra `sitemap-fast`.
|
|
133
|
+
|
|
134
|
+
- **`html2md-clean` moved to the optional extra `markdown`** (`pip install "graph-crawler[markdown]"`);
|
|
135
|
+
`MarkdownGenerator/MarkdownOptions/MarkdownResult` re-exports in `graph_crawler.shared.utils` are lazy.
|
|
136
|
+
`MarkdownPlugin` feeds the already-parsed Lexbor tree to html2md-clean 0.5 (`generate_from_tree`) —
|
|
137
|
+
one parse per page instead of 2–4. `import graph_crawler` no longer loads bs4/lxml.
|
|
138
|
+
|
|
139
|
+
- **Dependency map 6.0** (audit `docs/audit/04_dependency_map.md`). Core is now 10 packages: `requests`,
|
|
140
|
+
`httpx`, `pydantic-settings`, `pybloom-live`, `fastapi`, `tenacity`, `stop-words`, `tiktoken`,
|
|
141
|
+
`markdown-it-py` removed from `[project].dependencies`. New extras: `browser` (`playwright` kept as alias),
|
|
142
|
+
`server` (fastapi/uvicorn/websockets), `text` (tiktoken/stop-words), `captcha`; `markdown` also pulls
|
|
143
|
+
`markdown-it-py`; `all` is recursive. Extras `cloudscraper` and `undetected-sync` dropped.
|
|
144
|
+
Extra-gated imports are lazy and fail fast with `requires extra '<name>'`; `transport.PlaywrightDriver/
|
|
145
|
+
RequestsDriver/CloudscraperDriver/RequestsSessionAdapter` are lazy re-exports (ImportError instead of `None`).
|
|
146
|
+
`CrawlerSettings` keeps `GC_*`/`__`/`.env` without pydantic-settings; `CrawlerConfig` is a plain `BaseModel`.
|
|
147
|
+
|
|
148
|
+
- **Transport eradication 6.0** (audit `docs/audit/02_codebase_audit.md`). Deleted: sync drivers
|
|
149
|
+
(`RequestsDriver`, `CloudscraperDriver`, `UndetectedChromeDriver`, `BotasaurusDriver`, `BaseSyncDriver`),
|
|
150
|
+
`AsyncDriverHTTP2` (httpx), `AsyncCloudscraperDriver`, `tls_client.py`, `StealthHTTPDriver`,
|
|
151
|
+
`session_manager/session_adapters/session_protocol`, `shared/utils/captcha_bypass.py`,
|
|
152
|
+
`shared/utils/proxy_manager.py`, packages `transport/http` and `transport/browser`.
|
|
153
|
+
`DriverType` is now `aiohttp | tls | playwright | nodriver | escalating` (+ `asyncio` alias);
|
|
154
|
+
strings `http`/`async`/`asyncio` → `aiohttp` and `stealth`/`curl_cffi` → `tls` are accepted for one
|
|
155
|
+
release with `DeprecationWarning`. One `AsyncDriver` (former `driver_adaptive.py` is now
|
|
156
|
+
`async_http/driver.py`); request hints (`referer`, `extra_headers`, `cookies`) are honoured.
|
|
157
|
+
`requests` is gone from the package: proxy health-check, CAPTCHA solvers/bypass and `SitemapParser`
|
|
158
|
+
use aiohttp (`SitemapParser.parse_sitemap/parse_from_robots` are `asyncio.run` wrappers,
|
|
159
|
+
`http_client=` is deprecated and ignored). `BloomFilter` is pure-python (xxhash) — `pybloom-live`
|
|
160
|
+
no longer needed.
|
|
161
|
+
`import graph_crawler` no longer loads any extra (guarded by `tests/unit/test_import_surface.py`), 3.8 s → 1.7 s here.
|
|
162
|
+
Follow-up (02 §6 close-out): `shared/constants.py` no longer imports aiohttp — `br`/`zstd` are advertised
|
|
163
|
+
by `transport.compression.runtime_browser_headers()` only when the runtime can decode them;
|
|
164
|
+
one driver registry — `application.services.driver_factory` delegates to
|
|
165
|
+
`transport.factory.DriverFactory` (`register_factory`, `registered_names`); `SitemapParser(driver=)`
|
|
166
|
+
fetches robots.txt/sitemaps through the crawl `IDriver` (same tier chain), `SitemapSpider` passes its
|
|
167
|
+
driver, aiohttp is used directly only for binary `.gz`; `tests/transport/test_all_drivers_report_redirects.py`
|
|
168
|
+
is an `IDriver` acceptance matrix (aiohttp / tls / fake playwright / fake nodriver / escalating).
|
|
169
|
+
|
|
170
|
+
- **Escalation (audit `docs/audit/03_escalation.md` §6/§7)**: `EscalationPolicy.reprobe_interval` (5 min) —
|
|
171
|
+
one request per interval re-probes tier 0 for a host remembered on a higher tier (no herd of browser
|
|
172
|
+
re-escalations after TTL); `EscalationPolicy.max_hosts` (10k) — `HostTierMemory` is an LRU and drops
|
|
173
|
+
per-host locks together with entries. In strict mode (`GC_ENGINE_STRICT`) an `ImportError` raised *during*
|
|
174
|
+
`fetch` (lazy browser start without the SDK) now propagates instead of being turned into a network error.
|
|
175
|
+
|
|
176
|
+
- **`extras` contract persisted (audit `docs/audit/05_migration_guide.md` §4).** New
|
|
177
|
+
`FetchResponse.fetch_provenance()` / `FETCH_EXTRAS_KEYS`: a JSON-safe slice
|
|
178
|
+
(`bot_block_status, channel, driver, engine, escalations` + `escalation_reason`; cookies/impersonate dropped).
|
|
179
|
+
`NodeScanner` stores it in `node.metadata["fetch"]` for every response, including blocked/error ones, so it
|
|
180
|
+
survives JSON/SQLite/MongoDB/PostgreSQL storage. Contract test `tests/transport/test_extras_contract.py`.
|
|
181
|
+
- `docs/audit/05_migration_guide.md` — 5.2 → 6.0 migration guide (extras, drivers, parser, settings, sitemap, checklist).
|
|
182
|
+
|
|
183
|
+
### Fixed
|
|
184
|
+
- Transport `extras` (`bot_block_status`, tier, escalations) were dropped after fetch and never reached the
|
|
185
|
+
node or storage; for blocked pages nothing was transferred at all.
|
|
186
|
+
- `SmartPageFinder` read `html_tree.text` as a property; with Lexbor it is a method — page text was
|
|
187
|
+
silently dropped.
|
|
188
|
+
- `AsyncUndetectedDriver` accepts a plain `dict` config (`AsyncUndetectedConfig.from_mapping`) — building
|
|
189
|
+
the `nodriver` tier through `DriverFactory.create(DriverType.NODRIVER, config={...})` (as `EscalatingDriver`
|
|
190
|
+
does) raised `AttributeError`.
|
|
191
|
+
|
|
192
|
+
## 5.2.0 — 2026-06
|
|
193
|
+
|
|
194
|
+
### Added
|
|
195
|
+
- `infrastructure/transport/escalation.py`: `classify_block()` (Cloudflare / Akamai / DataDome /
|
|
196
|
+
PerimeterX / Incapsula markers, 403/429/503, empty 200), `EscalationPolicy`, `EscalationTier`,
|
|
197
|
+
`EscalatingDriver` — chain http → tls → browser → undetected with `max_tier`.
|
|
198
|
+
`driver="escalating"` works in `crawl()` / `async_crawl()` / `Crawler` / CLI.
|
|
199
|
+
- `HostTierMemory`: adaptive per-host tier memory — TTL from the moment of decision
|
|
200
|
+
(`GC_TIER_TTL`, default 1200 s), invalidation when the remembered tier gets blocked,
|
|
201
|
+
one escalation per host at a time (per-host lock). Per process.
|
|
202
|
+
- Strict engine mode: `GC_ENGINE_STRICT=1`, `{"browser_engine": {"strict": True}}` or
|
|
203
|
+
`driver_config={"engine_strict": True}` — `ImportError` instead of a silent fallback
|
|
204
|
+
`cloakbrowser → patchright → playwright` or a skipped escalation tier.
|
|
205
|
+
- Browser engine registry in `playwright/engine.py`: `register_engine()`, `resolve_engine()`,
|
|
206
|
+
`registered_engines()`. Built-in engines `cloakbrowser` → `patchright` → `playwright` with
|
|
207
|
+
automatic fail-open. `GC_BROWSER_ENGINE` env selects the engine when config has none.
|
|
208
|
+
`PlaywrightBrowserEngine.effective_name` / `fallback_reason`.
|
|
209
|
+
- `FetchResponse.extras` contract: `bot_block_status`, `channel`, `driver`, `engine`, `escalations`.
|
|
210
|
+
- `DriverType.TLS`, `NODRIVER`, `UNDETECTED`, `BOTASAURUS`, `ESCALATING`; `DriverFactory.create()`
|
|
211
|
+
accepts extra constructor kwargs (`policy=`).
|
|
212
|
+
- Extras: `tls`, `stealth`, `cloak`, `undetected`, `undetected-sync`, `antidetect`, `cloudscraper`, `system`.
|
|
213
|
+
- `README.md`, `CHANGELOG.md`.
|
|
214
|
+
|
|
215
|
+
### Changed
|
|
216
|
+
- `normalize_protocol` defaults to `False`: `http://` and `https://` are different URLs.
|
|
217
|
+
The crawler follows the real redirect instead of rewriting the scheme itself, so
|
|
218
|
+
http-only hosts stay reachable. Enable it explicitly to merge both schemes on dedup.
|
|
219
|
+
- `Graph.handle_redirect()` stores the alias as the real `Location` the server sent
|
|
220
|
+
(provenance); the normalized form is used only to find and merge nodes.
|
|
221
|
+
- Single `DriverType` enum (`transport/base.py`); `factory.py` re-exports it.
|
|
222
|
+
- `cloudscraper` moved from required dependencies to extra `cloudscraper`.
|
|
223
|
+
- `psutil` is optional (`system` extra); `MemoryGuard` imports it lazily.
|
|
224
|
+
- `requires-python = ">=3.11"` (upper bound removed; classifiers 3.11–3.14).
|
|
225
|
+
- `pytest` runs offline by default (`-m 'not manual'`, no coverage in `addopts`).
|
|
226
|
+
Network / real-site tests live in `tests/manual/` and run with `pytest -m manual tests/manual`.
|
|
227
|
+
- Project URLs point to the GitLab repository.
|
|
228
|
+
|
|
229
|
+
### Fixed
|
|
230
|
+
- `pooled_driver`: bounded walk over `redirected_from` (infinite loop on objects without a
|
|
231
|
+
`None` terminator); cookies are no longer added twice to a fresh browser.
|
|
232
|
+
- Tests synced with the code: redirect aliases, `html2md-clean` 0.4.0 API, `crawl_coordinator`
|
|
233
|
+
`per_host_max_in_flight`, `.gitignore` lookup at the repository root, `tools/db_cleanup.py`
|
|
234
|
+
CLI allow-listed for `print`. Playwright fake tests skip when `playwright` is not installed.
|
|
235
|
+
|
|
236
|
+
### Removed
|
|
237
|
+
- `tests/345.py`, `tests/ДОДАТКОВІ_ТЕСТИ.py`, `tests/manual_4a_games_test.py`, `tests/google_maps_results.json`.
|
|
238
|
+
- `EXTRACTION_AUDIT.md` and other analysis / plan documents that described work, not the code.
|
|
239
|
+
- `graph_crawler/data/ARCHITECTURE.md`, `MIGRATION_50_STEPS.md`, `REFACTORING_PLAN.md`, `mkdocs.yml`
|
|
240
|
+
(finished plans / config without content).
|
|
241
|
+
|
|
242
|
+
## 5.1.0
|
|
243
|
+
|
|
244
|
+
Previous release (sync-first API, Playwright pool, adaptive HTTP drivers, storage backends).
|