graph-crawler 5.3.2__tar.gz → 5.3.3__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.3.3/CHANGELOG.md +396 -0
- graph_crawler-5.3.3/LICENSE +21 -0
- graph_crawler-5.3.3/MANIFEST.in +16 -0
- graph_crawler-5.3.3/PKG-INFO +531 -0
- graph_crawler-5.3.3/README.md +410 -0
- graph_crawler-5.3.3/graph_crawler/__init__.py +496 -0
- graph_crawler-5.3.3/graph_crawler/__version__.py +8 -0
- graph_crawler-5.3.3/graph_crawler/ai/__init__.py +50 -0
- graph_crawler-5.3.3/graph_crawler/api/__init__.py +28 -0
- graph_crawler-5.3.3/graph_crawler/api/_core.py +285 -0
- graph_crawler-5.3.3/graph_crawler/api/_distributed.py +172 -0
- graph_crawler-5.3.3/graph_crawler/api/_shared.py +110 -0
- graph_crawler-5.3.3/graph_crawler/api/_sitemap_distributed.py +238 -0
- graph_crawler-5.3.3/graph_crawler/api/async_.py +325 -0
- graph_crawler-5.3.3/graph_crawler/api/cli.py +440 -0
- graph_crawler-5.3.3/graph_crawler/api/client/__init__.py +8 -0
- graph_crawler-5.3.3/graph_crawler/api/client/client.py +473 -0
- graph_crawler-5.3.3/graph_crawler/api/history_manager.py +55 -0
- graph_crawler-5.3.3/graph_crawler/api/project_init.py +196 -0
- graph_crawler-5.3.3/graph_crawler/api/server/__init__.py +18 -0
- graph_crawler-5.3.3/graph_crawler/api/server/crawl_monitor.py +145 -0
- graph_crawler-5.3.3/graph_crawler/api/server/dashboard.py +221 -0
- graph_crawler-5.3.3/graph_crawler/api/server/rest_api.py +704 -0
- graph_crawler-5.3.3/graph_crawler/api/server/webhooks.py +421 -0
- graph_crawler-5.3.3/graph_crawler/api/server/websocket_manager.py +89 -0
- graph_crawler-5.3.3/graph_crawler/api/stats_collector.py +88 -0
- graph_crawler-5.3.3/graph_crawler/api/sync.py +540 -0
- graph_crawler-5.3.3/graph_crawler/application/__init__.py +38 -0
- graph_crawler-5.3.3/graph_crawler/application/bootstrap.py +211 -0
- graph_crawler-5.3.3/graph_crawler/application/context/__init__.py +31 -0
- graph_crawler-5.3.3/graph_crawler/application/context/dependency_registry.py +354 -0
- graph_crawler-5.3.3/graph_crawler/application/context/graph_context.py +217 -0
- graph_crawler-5.3.3/graph_crawler/application/context/merge_context.py +221 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/__init__.py +67 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/edge_dto.py +25 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/graph_dto.py +27 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/mappers/__init__.py +14 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/mappers/edge_mapper.py +149 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/mappers/graph_mapper.py +622 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/mappers/node_data_codec.py +190 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/mappers/node_mapper.py +417 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/node_dto.py +27 -0
- graph_crawler-5.3.3/graph_crawler/application/dto/utils.py +272 -0
- graph_crawler-5.3.3/graph_crawler/application/services/__init__.py +60 -0
- graph_crawler-5.3.3/graph_crawler/application/services/application_container.py +208 -0
- graph_crawler-5.3.3/graph_crawler/application/services/driver_factory.py +147 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/__init__.py +26 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/base_exporter.py +150 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/csv_exporter.py +318 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/edge_exporter.py +432 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/excel_exporter.py +301 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/jsonl_exporter.py +290 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/node_exporter.py +284 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/parquet_exporter.py +248 -0
- graph_crawler-5.3.3/graph_crawler/application/services/exporters/sql_exporter.py +267 -0
- graph_crawler-5.3.3/graph_crawler/application/services/finalize.py +115 -0
- graph_crawler-5.3.3/graph_crawler/application/services/low_memory_graph_saver.py +337 -0
- graph_crawler-5.3.3/graph_crawler/application/services/resource_budget.py +179 -0
- graph_crawler-5.3.3/graph_crawler/application/services/scheduling/__init__.py +12 -0
- graph_crawler-5.3.3/graph_crawler/application/services/scheduling/rule_based_scheduler.py +105 -0
- graph_crawler-5.3.3/graph_crawler/application/services/storage_factory.py +195 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/__init__.py +11 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/__init__.py +81 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/adaptive_throttler.py +373 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/async_bridge.py +45 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/base_spider.py +155 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/celery_batch_spider.py +656 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/celery_spider.py +445 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/checkpoint.py +421 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/crawl_coordinator.py +1049 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/dead_letter_queue.py +413 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/domain_rate_limiter.py +262 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/filters/__init__.py +10 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/filters/base.py +74 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/filters/domain_filter.py +195 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/filters/domain_patterns.py +30 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/filters/path_filter.py +95 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/incremental_strategy.py +239 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/link_processor.py +885 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/multiprocess_spider.py +511 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/node_scanner.py +867 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/parsers/__init__.py +6 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/parsers/base.py +73 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/parsers/html_parser.py +154 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/progress_tracker.py +235 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/scheduler.py +757 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/serialization_mixin.py +218 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/sitemap_parser.py +657 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/sitemap_processor.py +401 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/sitemap_spider.py +608 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/spider.py +819 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/spider_lifecycle.py +108 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/crawling/worker_pool.py +154 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/graph_export.py +504 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/graph_merge/__init__.py +33 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/graph_merge/graph_operations.py +632 -0
- graph_crawler-5.3.3/graph_crawler/application/use_cases/graph_merge/merge_strategies.py +348 -0
- graph_crawler-5.3.3/graph_crawler/data/__init__.py +28 -0
- graph_crawler-5.3.3/graph_crawler/data/backends/__init__.py +21 -0
- graph_crawler-5.3.3/graph_crawler/data/backends/memory.py +486 -0
- graph_crawler-5.3.3/graph_crawler/data/backends/sqlite.py +1866 -0
- graph_crawler-5.3.3/graph_crawler/data/interfaces.py +563 -0
- graph_crawler-5.3.3/graph_crawler/domain/__init__.py +62 -0
- graph_crawler-5.3.3/graph_crawler/domain/context/__init__.py +14 -0
- graph_crawler-5.3.3/graph_crawler/domain/context/crawl_context.py +531 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/__init__.py +32 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/edge.py +345 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/edge_analysis.py +223 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/graph.py +4169 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/graph_operations.py +30 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/graph_statistics.py +10 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/merge_strategies.py +33 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/node.py +810 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/redirect_mode.py +23 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/registries.py +223 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/sitemap_node.py +74 -0
- graph_crawler-5.3.3/graph_crawler/domain/entities/strategies.py +202 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/__init__.py +162 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/base.py +60 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/crawl.py +112 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/edge.py +43 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/event_bus.py +250 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/events.py +313 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/fetch.py +120 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/idempotent_subscriber.py +120 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/legacy_type_map.py +45 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/llm.py +148 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/node.py +111 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/plugin.py +92 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/scheduler.py +98 -0
- graph_crawler-5.3.3/graph_crawler/domain/events/storage.py +161 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/__init__.py +111 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/adapter.py +29 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/control_channel.py +371 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/crawl_context.py +49 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/distributed_spider.py +62 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/driver.py +87 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/event_bus.py +61 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/exporters.py +69 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/filter.py +19 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/merge_context.py +52 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/node_interfaces.py +389 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/parser.py +88 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/plugin_manager.py +53 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/processor.py +11 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/scanner.py +57 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/scheduler.py +43 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/scheduling/__init__.py +40 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/scheduling/frontier.py +97 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/scheduling/scheduler.py +107 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/spider.py +63 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/stop_condition.py +211 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/storage/__init__.py +43 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/storage/base.py +68 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/storage/eviction.py +98 -0
- graph_crawler-5.3.3/graph_crawler/domain/interfaces/storage/queue.py +234 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/__init__.py +216 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/adjacency_maintenance.py +95 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/cycle_detection.py +92 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/degree_ranking.py +47 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/depth_context.py +123 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/display_title.py +47 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/duplicate_detection.py +141 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/duplicate_selector.py +127 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/duplicate_stats.py +63 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/edge_filter.py +82 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/edge_statistics.py +110 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/eviction_policy.py +83 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/graph_query_cascade.py +178 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/graph_statistics.py +186 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/graph_traversal.py +150 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/language_versions.py +73 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/lsh_index.py +99 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/minimap_builder.py +147 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/node_content_resolver.py +128 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/node_view_builder.py +163 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/pagination_guards.py +136 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/predicate_ops.py +77 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/schema_filter.py +138 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/search_haystack.py +102 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/simhash_clustering.py +96 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/simhash_fallback.py +59 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/similarity_ranking.py +62 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/text_search.py +157 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/url_clustering.py +88 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/url_deduplication.py +101 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/url_normalizer.py +117 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/url_rule_matcher.py +111 -0
- graph_crawler-5.3.3/graph_crawler/domain/services/url_tree_builder.py +197 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/__init__.py +88 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/configs.py +891 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/domain_patterns.py +71 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/fetch_options.py +57 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/html_document.py +59 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/lifecycle.py +30 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/models.py +1315 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/page_actions.py +72 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/redirect_hop.py +49 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/scheduling/__init__.py +23 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/scheduling/crawl_request.py +153 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/scheduling/retry_policy.py +109 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/settings.py +350 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/url_normalization.py +497 -0
- graph_crawler-5.3.3/graph_crawler/domain/value_objects/views.py +293 -0
- graph_crawler-5.3.3/graph_crawler/extensions/__init__.py +1 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/__init__.py +65 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/base.py +136 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/cache_middleware.py +277 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/chain.py +155 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/error_recovery_middleware.py +442 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/logging_middleware.py +108 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/proxy_health.py +141 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/proxy_middleware.py +209 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/proxy_models.py +80 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/proxy_selection.py +87 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/rate_limit_middleware.py +262 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/request_response_middleware.py +476 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/retry_middleware.py +279 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/robots_cache.py +85 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/robots_middleware.py +110 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/robots_validator.py +60 -0
- graph_crawler-5.3.3/graph_crawler/extensions/middleware/user_agent_middleware.py +251 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/__init__.py +57 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/builtin/__init__.py +7 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/builtin/stats_export_plugin.py +99 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/crawl_engine/__init__.py +24 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/crawl_engine/base.py +155 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/crawl_engine/priority_provider.py +247 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/crawl_engine/smart_crawl.py +296 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/__init__.py +128 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/anti_bot_detection.py +55 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/anti_bot_playwright.py +88 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/anti_bot_scripts.py +136 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/anti_bot_stealth.py +177 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/base.py +121 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/captcha/__init__.py +22 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/captcha/detector.py +94 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/captcha/models.py +74 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/captcha/plugin.py +228 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/engine/captcha/services.py +389 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/__init__.py +86 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/base.py +520 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/content_extractors/__init__.py +15 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/content_extractors/base.py +82 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/content_extractors/goose3_extractor.py +80 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/content_extractors/newspaper_extractor.py +93 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/content_extractors/plugin.py +132 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/content_extractors/readability_extractor.py +91 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/defaults.py +32 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/extractors/__init__.py +30 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/extractors/email_extractor.py +146 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/extractors/phone_extractor.py +136 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/extractors/price_extractor.py +137 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/links.py +184 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/markdown_plugin.py +249 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/metadata.py +384 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/smart_page_finder.py +749 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/__init__.py +51 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/constants.py +27 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/exceptions.py +18 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/extractor.py +361 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/options.py +62 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/parsers/__init__.py +25 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/parsers/base.py +43 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/parsers/jsonld.py +331 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/parsers/microdata.py +117 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/parsers/opengraph.py +66 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/parsers/rdfa.py +122 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/parsers/twitter.py +66 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/plugin.py +132 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/structured_data/result.py +233 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/text.py +76 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/node/url_normalizer.py +363 -0
- graph_crawler-5.3.3/graph_crawler/extensions/plugins/registry.py +97 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/__init__.py +1 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/adapters/__init__.py +60 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/adapters/base.py +498 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/adapters/selectolax_adapter.py +233 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/__init__.py +37 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/celery_app.py +202 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/celery_batch.py +284 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/celery_job_task.py +415 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/celery_unified.py +419 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/config.py +201 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/easy_crawler.py +279 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/messaging/worker_api.py +607 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/__init__.py +135 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/auto_storage.py +336 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/base.py +111 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/eviction.py +100 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/graph_repository.py +401 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/json/__init__.py +10 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/json_storage.py +375 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/lmdb_eviction_storage.py +401 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/memory/__init__.py +1 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/memory_dedup_store.py +90 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/memory_frontier.py +180 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/memory_politeness_store.py +88 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/memory_storage.py +166 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/mongodb_storage.py +383 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/naming_strategy.py +174 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/postgresql_storage.py +449 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/protocols/__init__.py +1 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/redis_dedup_store.py +119 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/redis_politeness_store.py +122 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/repository.py +130 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/sqlite/__init__.py +10 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/sqlite_eviction_storage.py +918 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/sqlite_storage.py +775 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/__init__.py +47 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/file_job_storage.py +245 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/file_queue_storage.py +248 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/memory_job_storage.py +94 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/memory_queue_storage.py +117 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/postgresql_job_storage.py +317 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/postgresql_queue_storage.py +364 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/persistence/unified/unified_storage.py +244 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/__init__.py +135 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/__init__.py +38 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/config.py +47 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/context.py +55 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/driver.py +724 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/driver_curl_cffi.py +407 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/plugins/__init__.py +48 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle.py +484 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle_adaptive.py +1435 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/plugins/headers.py +69 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/plugins/http_cache.py +321 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/plugins/rate_limiter.py +96 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/plugins/retry.py +316 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/async_http/stages.py +33 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/base.py +349 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/base_plugin.py +151 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/compression/__init__.py +23 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/compression/strategy.py +219 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/connection_pool.py +349 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/context.py +114 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/core/__init__.py +15 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/core/base_async.py +378 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/core/body_decoder.py +26 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/core/mixins.py +258 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/core/redirect_utils.py +168 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/escalation.py +996 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/factory.py +210 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/__init__.py +19 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/adaptive_semaphore.py +65 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/batch_scheduler.py +764 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/browser_factory.py +580 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/browser_profile.py +718 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/config.py +84 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/context.py +46 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/driver.py +80 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/engine.py +480 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/fetch_metrics.py +115 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/net/__init__.py +41 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/net/geoip.py +136 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/net/proxy_pool.py +225 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/net/rate_limiter.py +139 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/page_actions.py +186 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/page_fetch.py +968 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/__init__.py +71 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/_network_record.py +66 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/captcha_detector.py +315 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/captcha_solver.py +108 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/cookie_consent.py +565 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/form_filler.py +177 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/human_bezier.py +297 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/network_log.py +406 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/ram_adaptive.py +208 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/screenshot.py +169 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/plugins/user_profile.py +556 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/pool_lifecycle.py +658 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/pooled_driver.py +706 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/stages.py +35 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/playwright/stealth_hints.py +153 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/plugin_manager.py +316 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/protocols.py +132 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/undetected/__init__.py +8 -0
- graph_crawler-5.3.3/graph_crawler/infrastructure/transport/undetected/async_driver.py +465 -0
- graph_crawler-5.3.3/graph_crawler/native/__init__.py +199 -0
- graph_crawler-5.3.3/graph_crawler/native/bloom_filter.pyx +255 -0
- graph_crawler-5.3.3/graph_crawler/native/html_parser.pyx +262 -0
- graph_crawler-5.3.3/graph_crawler/native/setup.py +103 -0
- graph_crawler-5.3.3/graph_crawler/native/url_utils.pyx +209 -0
- graph_crawler-5.3.3/graph_crawler/observability/__init__.py +62 -0
- graph_crawler-5.3.3/graph_crawler/observability/decorators/__init__.py +11 -0
- graph_crawler-5.3.3/graph_crawler/observability/decorators/cache.py +126 -0
- graph_crawler-5.3.3/graph_crawler/observability/decorators/log.py +56 -0
- graph_crawler-5.3.3/graph_crawler/observability/decorators/retry.py +121 -0
- graph_crawler-5.3.3/graph_crawler/observability/decorators/timing.py +43 -0
- graph_crawler-5.3.3/graph_crawler/observability/error_tracing.py +361 -0
- graph_crawler-5.3.3/graph_crawler/observability/extensions/__init__.py +18 -0
- graph_crawler-5.3.3/graph_crawler/observability/extensions/memory_guard.py +237 -0
- graph_crawler-5.3.3/graph_crawler/observability/extensions/state_manager.py +319 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/__init__.py +33 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/base.py +82 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/base_metrics_listener.py +18 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/crawl_listener.py +28 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/dlq_listener.py +215 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/error_listener.py +18 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/logging_listener.py +88 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/metrics_listener.py +109 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/node_listener.py +33 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/plugin_listener.py +28 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/storage_listener.py +21 -0
- graph_crawler-5.3.3/graph_crawler/observability/listeners/url_listener.py +29 -0
- graph_crawler-5.3.3/graph_crawler/observability/metrics/__init__.py +23 -0
- graph_crawler-5.3.3/graph_crawler/observability/metrics/memory_profiler.py +508 -0
- graph_crawler-5.3.3/graph_crawler/observability/metrics/metrics_collector.py +408 -0
- graph_crawler-5.3.3/graph_crawler/observability/metrics/prometheus_metrics.py +293 -0
- graph_crawler-5.3.3/graph_crawler/observability/metrics_core.py +389 -0
- graph_crawler-5.3.3/graph_crawler/observability/structured_logging.py +216 -0
- graph_crawler-5.3.3/graph_crawler/observability/tracing.py +291 -0
- graph_crawler-5.3.3/graph_crawler/optimizations/__init__.py +89 -0
- graph_crawler-5.3.3/graph_crawler/optimizations/generators.py +477 -0
- graph_crawler-5.3.3/graph_crawler/optimizations/memory_slots.py +641 -0
- graph_crawler-5.3.3/graph_crawler/optimizations/simhash_numba.py +284 -0
- graph_crawler-5.3.3/graph_crawler/shared/__init__.py +25 -0
- graph_crawler-5.3.3/graph_crawler/shared/constants.py +943 -0
- graph_crawler-5.3.3/graph_crawler/shared/dto/__init__.py +38 -0
- graph_crawler-5.3.3/graph_crawler/shared/dto/edge_dto.py +52 -0
- graph_crawler-5.3.3/graph_crawler/shared/dto/graph_dto.py +97 -0
- graph_crawler-5.3.3/graph_crawler/shared/dto/node_dto.py +193 -0
- graph_crawler-5.3.3/graph_crawler/shared/error_handling/__init__.py +15 -0
- graph_crawler-5.3.3/graph_crawler/shared/error_handling/error_handler.py +333 -0
- graph_crawler-5.3.3/graph_crawler/shared/exceptions.py +394 -0
- graph_crawler-5.3.3/graph_crawler/shared/platform/__init__.py +125 -0
- graph_crawler-5.3.3/graph_crawler/shared/platform/adaptive_resolver.py +414 -0
- graph_crawler-5.3.3/graph_crawler/shared/platform/config.py +635 -0
- graph_crawler-5.3.3/graph_crawler/shared/platform/detector.py +334 -0
- graph_crawler-5.3.3/graph_crawler/shared/platform/diagnostics.py +660 -0
- graph_crawler-5.3.3/graph_crawler/shared/platform/metrics.py +299 -0
- graph_crawler-5.3.3/graph_crawler/shared/security/__init__.py +22 -0
- graph_crawler-5.3.3/graph_crawler/shared/security/url_sanitizer.py +100 -0
- graph_crawler-5.3.3/graph_crawler/shared/security/url_validator.py +299 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/__init__.py +212 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/async_compat.py +140 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/bloom_filter.py +373 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/captcha/__init__.py +36 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/captcha/base.py +92 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/captcha/manager.py +474 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/celery_config.py +332 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/celery_helpers.py +153 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/cgroup_limits.py +227 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/content_decoder.py +150 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/distributed_rate_limiter.py +265 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/distributed_rate_limiter_backends.py +284 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/dns_cache.py +370 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/enterprise_ua_generator.py +294 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/event_publisher_mixin.py +187 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/fast_json.py +240 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/fingerprint.py +36 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/fingerprint_data.py +99 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/fingerprint_generators.py +128 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/fingerprint_profile.py +121 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/fingerprint_stealth.py +105 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/html_utils.py +118 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/id_generator.py +195 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/isolated_executor.py +193 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/memory_optimizer.py +536 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/rate_limiter.py +185 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/regex_validator.py +966 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/shadow_dom.py +36 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/text_utils.py +387 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/url_patterns.py +135 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/url_utils.py +595 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/user_agent_rotator.py +333 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/validation_helpers.py +225 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/visualization.py +134 -0
- graph_crawler-5.3.3/graph_crawler/shared/utils/visualization_core.py +566 -0
- graph_crawler-5.3.3/graph_crawler/tools/__init__.py +1 -0
- graph_crawler-5.3.3/graph_crawler/tools/db_cleanup.py +263 -0
- graph_crawler-5.3.3/graph_crawler.egg-info/PKG-INFO +531 -0
- graph_crawler-5.3.3/graph_crawler.egg-info/SOURCES.txt +479 -0
- graph_crawler-5.3.3/pyproject.toml +301 -0
- graph_crawler-5.3.3/setup.cfg +4 -0
- graph_crawler-5.3.2/CHANGELOG.md +0 -353
- graph_crawler-5.3.2/CODE_STYLE.md +0 -1473
- graph_crawler-5.3.2/LICENSE +0 -21
- graph_crawler-5.3.2/MANIFEST.in +0 -16
- graph_crawler-5.3.2/PKG-INFO +0 -531
- graph_crawler-5.3.2/README.md +0 -410
- graph_crawler-5.3.2/graph_crawler/__init__.py +0 -492
- graph_crawler-5.3.2/graph_crawler/__version__.py +0 -8
- graph_crawler-5.3.2/graph_crawler/ai/__init__.py +0 -50
- graph_crawler-5.3.2/graph_crawler/api/__init__.py +0 -28
- graph_crawler-5.3.2/graph_crawler/api/_core.py +0 -283
- graph_crawler-5.3.2/graph_crawler/api/_distributed.py +0 -172
- graph_crawler-5.3.2/graph_crawler/api/_shared.py +0 -110
- graph_crawler-5.3.2/graph_crawler/api/_sitemap_distributed.py +0 -238
- graph_crawler-5.3.2/graph_crawler/api/async_.py +0 -323
- graph_crawler-5.3.2/graph_crawler/api/cli.py +0 -440
- graph_crawler-5.3.2/graph_crawler/api/client/__init__.py +0 -8
- graph_crawler-5.3.2/graph_crawler/api/client/client.py +0 -470
- graph_crawler-5.3.2/graph_crawler/api/history_manager.py +0 -55
- graph_crawler-5.3.2/graph_crawler/api/project_init.py +0 -196
- graph_crawler-5.3.2/graph_crawler/api/server/__init__.py +0 -18
- graph_crawler-5.3.2/graph_crawler/api/server/crawl_monitor.py +0 -145
- graph_crawler-5.3.2/graph_crawler/api/server/dashboard.py +0 -221
- graph_crawler-5.3.2/graph_crawler/api/server/rest_api.py +0 -704
- graph_crawler-5.3.2/graph_crawler/api/server/webhooks.py +0 -421
- graph_crawler-5.3.2/graph_crawler/api/server/websocket_manager.py +0 -89
- graph_crawler-5.3.2/graph_crawler/api/stats_collector.py +0 -88
- graph_crawler-5.3.2/graph_crawler/api/sync.py +0 -536
- graph_crawler-5.3.2/graph_crawler/application/__init__.py +0 -38
- graph_crawler-5.3.2/graph_crawler/application/bootstrap.py +0 -211
- graph_crawler-5.3.2/graph_crawler/application/context/__init__.py +0 -31
- graph_crawler-5.3.2/graph_crawler/application/context/dependency_registry.py +0 -354
- graph_crawler-5.3.2/graph_crawler/application/context/graph_context.py +0 -217
- graph_crawler-5.3.2/graph_crawler/application/context/merge_context.py +0 -221
- graph_crawler-5.3.2/graph_crawler/application/dto/__init__.py +0 -67
- graph_crawler-5.3.2/graph_crawler/application/dto/edge_dto.py +0 -25
- graph_crawler-5.3.2/graph_crawler/application/dto/graph_dto.py +0 -27
- graph_crawler-5.3.2/graph_crawler/application/dto/mappers/__init__.py +0 -14
- graph_crawler-5.3.2/graph_crawler/application/dto/mappers/edge_mapper.py +0 -149
- graph_crawler-5.3.2/graph_crawler/application/dto/mappers/graph_mapper.py +0 -622
- graph_crawler-5.3.2/graph_crawler/application/dto/mappers/node_data_codec.py +0 -190
- graph_crawler-5.3.2/graph_crawler/application/dto/mappers/node_mapper.py +0 -417
- graph_crawler-5.3.2/graph_crawler/application/dto/node_dto.py +0 -27
- graph_crawler-5.3.2/graph_crawler/application/dto/utils.py +0 -272
- graph_crawler-5.3.2/graph_crawler/application/services/__init__.py +0 -60
- graph_crawler-5.3.2/graph_crawler/application/services/application_container.py +0 -208
- graph_crawler-5.3.2/graph_crawler/application/services/driver_factory.py +0 -147
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/__init__.py +0 -26
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/base_exporter.py +0 -150
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/csv_exporter.py +0 -318
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/edge_exporter.py +0 -432
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/excel_exporter.py +0 -301
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/jsonl_exporter.py +0 -290
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/node_exporter.py +0 -284
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/parquet_exporter.py +0 -248
- graph_crawler-5.3.2/graph_crawler/application/services/exporters/sql_exporter.py +0 -267
- graph_crawler-5.3.2/graph_crawler/application/services/finalize.py +0 -115
- graph_crawler-5.3.2/graph_crawler/application/services/low_memory_graph_saver.py +0 -337
- graph_crawler-5.3.2/graph_crawler/application/services/resource_budget.py +0 -179
- graph_crawler-5.3.2/graph_crawler/application/services/scheduling/__init__.py +0 -12
- graph_crawler-5.3.2/graph_crawler/application/services/scheduling/rule_based_scheduler.py +0 -113
- graph_crawler-5.3.2/graph_crawler/application/services/storage_factory.py +0 -195
- graph_crawler-5.3.2/graph_crawler/application/use_cases/__init__.py +0 -11
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/__init__.py +0 -81
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/adaptive_throttler.py +0 -373
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/async_bridge.py +0 -45
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/base_spider.py +0 -155
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/celery_batch_spider.py +0 -656
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/celery_spider.py +0 -445
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/checkpoint.py +0 -421
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/crawl_coordinator.py +0 -1049
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/dead_letter_queue.py +0 -413
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/domain_rate_limiter.py +0 -262
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/filters/__init__.py +0 -10
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/filters/base.py +0 -74
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/filters/domain_filter.py +0 -195
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/filters/domain_patterns.py +0 -30
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/filters/path_filter.py +0 -95
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/incremental_strategy.py +0 -239
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/link_processor.py +0 -932
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/multiprocess_spider.py +0 -511
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/node_scanner.py +0 -866
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/parsers/__init__.py +0 -6
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/parsers/base.py +0 -73
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/parsers/html_parser.py +0 -154
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/progress_tracker.py +0 -235
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/scheduler.py +0 -747
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/serialization_mixin.py +0 -218
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/sitemap_parser.py +0 -657
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/sitemap_processor.py +0 -401
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/sitemap_spider.py +0 -608
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/spider.py +0 -813
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/spider_lifecycle.py +0 -108
- graph_crawler-5.3.2/graph_crawler/application/use_cases/crawling/worker_pool.py +0 -154
- graph_crawler-5.3.2/graph_crawler/application/use_cases/graph_export.py +0 -504
- graph_crawler-5.3.2/graph_crawler/application/use_cases/graph_merge/__init__.py +0 -33
- graph_crawler-5.3.2/graph_crawler/application/use_cases/graph_merge/graph_operations.py +0 -632
- graph_crawler-5.3.2/graph_crawler/application/use_cases/graph_merge/merge_strategies.py +0 -348
- graph_crawler-5.3.2/graph_crawler/data/__init__.py +0 -28
- graph_crawler-5.3.2/graph_crawler/data/backends/__init__.py +0 -21
- graph_crawler-5.3.2/graph_crawler/data/backends/memory.py +0 -486
- graph_crawler-5.3.2/graph_crawler/data/backends/sqlite.py +0 -1866
- graph_crawler-5.3.2/graph_crawler/data/interfaces.py +0 -563
- graph_crawler-5.3.2/graph_crawler/domain/__init__.py +0 -62
- graph_crawler-5.3.2/graph_crawler/domain/context/__init__.py +0 -14
- graph_crawler-5.3.2/graph_crawler/domain/context/crawl_context.py +0 -531
- graph_crawler-5.3.2/graph_crawler/domain/entities/__init__.py +0 -32
- graph_crawler-5.3.2/graph_crawler/domain/entities/edge.py +0 -345
- graph_crawler-5.3.2/graph_crawler/domain/entities/edge_analysis.py +0 -223
- graph_crawler-5.3.2/graph_crawler/domain/entities/graph.py +0 -4169
- graph_crawler-5.3.2/graph_crawler/domain/entities/graph_operations.py +0 -30
- graph_crawler-5.3.2/graph_crawler/domain/entities/graph_statistics.py +0 -10
- graph_crawler-5.3.2/graph_crawler/domain/entities/merge_strategies.py +0 -33
- graph_crawler-5.3.2/graph_crawler/domain/entities/node.py +0 -780
- graph_crawler-5.3.2/graph_crawler/domain/entities/redirect_mode.py +0 -23
- graph_crawler-5.3.2/graph_crawler/domain/entities/registries.py +0 -223
- graph_crawler-5.3.2/graph_crawler/domain/entities/sitemap_node.py +0 -74
- graph_crawler-5.3.2/graph_crawler/domain/entities/strategies.py +0 -202
- graph_crawler-5.3.2/graph_crawler/domain/events/__init__.py +0 -162
- graph_crawler-5.3.2/graph_crawler/domain/events/base.py +0 -60
- graph_crawler-5.3.2/graph_crawler/domain/events/crawl.py +0 -112
- graph_crawler-5.3.2/graph_crawler/domain/events/edge.py +0 -43
- graph_crawler-5.3.2/graph_crawler/domain/events/event_bus.py +0 -250
- graph_crawler-5.3.2/graph_crawler/domain/events/events.py +0 -313
- graph_crawler-5.3.2/graph_crawler/domain/events/fetch.py +0 -120
- graph_crawler-5.3.2/graph_crawler/domain/events/idempotent_subscriber.py +0 -120
- graph_crawler-5.3.2/graph_crawler/domain/events/legacy_type_map.py +0 -45
- graph_crawler-5.3.2/graph_crawler/domain/events/llm.py +0 -148
- graph_crawler-5.3.2/graph_crawler/domain/events/node.py +0 -111
- graph_crawler-5.3.2/graph_crawler/domain/events/plugin.py +0 -92
- graph_crawler-5.3.2/graph_crawler/domain/events/scheduler.py +0 -98
- graph_crawler-5.3.2/graph_crawler/domain/events/storage.py +0 -161
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/__init__.py +0 -111
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/adapter.py +0 -29
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/control_channel.py +0 -371
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/crawl_context.py +0 -49
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/distributed_spider.py +0 -62
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/driver.py +0 -87
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/event_bus.py +0 -61
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/exporters.py +0 -69
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/filter.py +0 -19
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/merge_context.py +0 -52
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/node_interfaces.py +0 -389
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/parser.py +0 -88
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/plugin_manager.py +0 -53
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/processor.py +0 -11
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/scanner.py +0 -57
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/scheduler.py +0 -43
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/scheduling/__init__.py +0 -40
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/scheduling/frontier.py +0 -97
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/scheduling/scheduler.py +0 -107
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/spider.py +0 -63
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/stop_condition.py +0 -211
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/storage/__init__.py +0 -43
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/storage/base.py +0 -68
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/storage/eviction.py +0 -98
- graph_crawler-5.3.2/graph_crawler/domain/interfaces/storage/queue.py +0 -234
- graph_crawler-5.3.2/graph_crawler/domain/services/__init__.py +0 -216
- graph_crawler-5.3.2/graph_crawler/domain/services/adjacency_maintenance.py +0 -95
- graph_crawler-5.3.2/graph_crawler/domain/services/cycle_detection.py +0 -92
- graph_crawler-5.3.2/graph_crawler/domain/services/degree_ranking.py +0 -47
- graph_crawler-5.3.2/graph_crawler/domain/services/depth_context.py +0 -123
- graph_crawler-5.3.2/graph_crawler/domain/services/display_title.py +0 -47
- graph_crawler-5.3.2/graph_crawler/domain/services/duplicate_detection.py +0 -141
- graph_crawler-5.3.2/graph_crawler/domain/services/duplicate_selector.py +0 -127
- graph_crawler-5.3.2/graph_crawler/domain/services/duplicate_stats.py +0 -63
- graph_crawler-5.3.2/graph_crawler/domain/services/edge_filter.py +0 -82
- graph_crawler-5.3.2/graph_crawler/domain/services/edge_statistics.py +0 -110
- graph_crawler-5.3.2/graph_crawler/domain/services/eviction_policy.py +0 -83
- graph_crawler-5.3.2/graph_crawler/domain/services/graph_query_cascade.py +0 -178
- graph_crawler-5.3.2/graph_crawler/domain/services/graph_statistics.py +0 -186
- graph_crawler-5.3.2/graph_crawler/domain/services/graph_traversal.py +0 -150
- graph_crawler-5.3.2/graph_crawler/domain/services/language_versions.py +0 -73
- graph_crawler-5.3.2/graph_crawler/domain/services/lsh_index.py +0 -99
- graph_crawler-5.3.2/graph_crawler/domain/services/minimap_builder.py +0 -147
- graph_crawler-5.3.2/graph_crawler/domain/services/node_content_resolver.py +0 -128
- graph_crawler-5.3.2/graph_crawler/domain/services/node_view_builder.py +0 -163
- graph_crawler-5.3.2/graph_crawler/domain/services/pagination_guards.py +0 -136
- graph_crawler-5.3.2/graph_crawler/domain/services/predicate_ops.py +0 -77
- graph_crawler-5.3.2/graph_crawler/domain/services/schema_filter.py +0 -138
- graph_crawler-5.3.2/graph_crawler/domain/services/search_haystack.py +0 -102
- graph_crawler-5.3.2/graph_crawler/domain/services/simhash_clustering.py +0 -96
- graph_crawler-5.3.2/graph_crawler/domain/services/simhash_fallback.py +0 -59
- graph_crawler-5.3.2/graph_crawler/domain/services/similarity_ranking.py +0 -62
- graph_crawler-5.3.2/graph_crawler/domain/services/text_search.py +0 -157
- graph_crawler-5.3.2/graph_crawler/domain/services/url_clustering.py +0 -88
- graph_crawler-5.3.2/graph_crawler/domain/services/url_deduplication.py +0 -101
- graph_crawler-5.3.2/graph_crawler/domain/services/url_normalizer.py +0 -117
- graph_crawler-5.3.2/graph_crawler/domain/services/url_rule_matcher.py +0 -103
- graph_crawler-5.3.2/graph_crawler/domain/services/url_tree_builder.py +0 -197
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/__init__.py +0 -88
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/configs.py +0 -884
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/domain_patterns.py +0 -71
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/fetch_options.py +0 -57
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/html_document.py +0 -59
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/lifecycle.py +0 -30
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/models.py +0 -1315
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/page_actions.py +0 -72
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/redirect_hop.py +0 -49
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/scheduling/__init__.py +0 -23
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/scheduling/crawl_request.py +0 -153
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/scheduling/retry_policy.py +0 -109
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/settings.py +0 -350
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/url_normalization.py +0 -497
- graph_crawler-5.3.2/graph_crawler/domain/value_objects/views.py +0 -293
- graph_crawler-5.3.2/graph_crawler/extensions/__init__.py +0 -1
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/__init__.py +0 -65
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/base.py +0 -136
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/cache_middleware.py +0 -277
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/chain.py +0 -155
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/error_recovery_middleware.py +0 -442
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/logging_middleware.py +0 -108
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/proxy_health.py +0 -141
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/proxy_middleware.py +0 -209
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/proxy_models.py +0 -80
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/proxy_selection.py +0 -87
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/rate_limit_middleware.py +0 -262
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/request_response_middleware.py +0 -476
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/retry_middleware.py +0 -279
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/robots_cache.py +0 -85
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/robots_middleware.py +0 -110
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/robots_validator.py +0 -60
- graph_crawler-5.3.2/graph_crawler/extensions/middleware/user_agent_middleware.py +0 -251
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/__init__.py +0 -57
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/builtin/__init__.py +0 -7
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/builtin/stats_export_plugin.py +0 -99
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/crawl_engine/__init__.py +0 -24
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/crawl_engine/base.py +0 -155
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/crawl_engine/priority_provider.py +0 -247
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/crawl_engine/smart_crawl.py +0 -296
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/__init__.py +0 -128
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/anti_bot_detection.py +0 -55
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/anti_bot_playwright.py +0 -88
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/anti_bot_scripts.py +0 -136
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/anti_bot_stealth.py +0 -177
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/base.py +0 -121
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/captcha/__init__.py +0 -22
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/captcha/detector.py +0 -94
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/captcha/models.py +0 -74
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/captcha/plugin.py +0 -228
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/engine/captcha/services.py +0 -389
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/__init__.py +0 -86
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/base.py +0 -520
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/content_extractors/__init__.py +0 -15
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/content_extractors/base.py +0 -82
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/content_extractors/goose3_extractor.py +0 -80
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/content_extractors/newspaper_extractor.py +0 -93
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/content_extractors/plugin.py +0 -132
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/content_extractors/readability_extractor.py +0 -91
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/defaults.py +0 -32
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/extractors/__init__.py +0 -30
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/extractors/email_extractor.py +0 -146
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/extractors/phone_extractor.py +0 -136
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/extractors/price_extractor.py +0 -137
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/links.py +0 -184
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/markdown_plugin.py +0 -249
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/metadata.py +0 -384
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/smart_page_finder.py +0 -749
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/__init__.py +0 -51
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/constants.py +0 -27
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/exceptions.py +0 -18
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/extractor.py +0 -361
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/options.py +0 -62
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/parsers/__init__.py +0 -25
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/parsers/base.py +0 -43
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/parsers/jsonld.py +0 -331
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/parsers/microdata.py +0 -117
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/parsers/opengraph.py +0 -66
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/parsers/rdfa.py +0 -122
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/parsers/twitter.py +0 -66
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/plugin.py +0 -132
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/structured_data/result.py +0 -233
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/text.py +0 -76
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/node/url_normalizer.py +0 -363
- graph_crawler-5.3.2/graph_crawler/extensions/plugins/registry.py +0 -97
- graph_crawler-5.3.2/graph_crawler/infrastructure/__init__.py +0 -1
- graph_crawler-5.3.2/graph_crawler/infrastructure/adapters/__init__.py +0 -60
- graph_crawler-5.3.2/graph_crawler/infrastructure/adapters/base.py +0 -498
- graph_crawler-5.3.2/graph_crawler/infrastructure/adapters/selectolax_adapter.py +0 -233
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/__init__.py +0 -37
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/celery_app.py +0 -202
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/celery_batch.py +0 -284
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/celery_job_task.py +0 -415
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/celery_unified.py +0 -419
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/config.py +0 -201
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/easy_crawler.py +0 -279
- graph_crawler-5.3.2/graph_crawler/infrastructure/messaging/worker_api.py +0 -607
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/__init__.py +0 -135
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/auto_storage.py +0 -336
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/base.py +0 -111
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/eviction.py +0 -100
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/graph_repository.py +0 -401
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/json/__init__.py +0 -10
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/json_storage.py +0 -375
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/lmdb_eviction_storage.py +0 -401
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/memory/__init__.py +0 -1
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/memory_dedup_store.py +0 -90
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/memory_frontier.py +0 -180
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/memory_politeness_store.py +0 -88
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/memory_storage.py +0 -166
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/mongodb_storage.py +0 -383
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/naming_strategy.py +0 -174
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/postgresql_storage.py +0 -449
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/protocols/__init__.py +0 -1
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/redis_dedup_store.py +0 -119
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/redis_politeness_store.py +0 -122
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/repository.py +0 -130
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/sqlite/__init__.py +0 -10
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/sqlite_eviction_storage.py +0 -918
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/sqlite_storage.py +0 -775
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/__init__.py +0 -47
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/file_job_storage.py +0 -245
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/file_queue_storage.py +0 -248
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/memory_job_storage.py +0 -94
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/memory_queue_storage.py +0 -117
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/postgresql_job_storage.py +0 -317
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/postgresql_queue_storage.py +0 -364
- graph_crawler-5.3.2/graph_crawler/infrastructure/persistence/unified/unified_storage.py +0 -244
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/__init__.py +0 -135
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/__init__.py +0 -38
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/config.py +0 -47
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/context.py +0 -55
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/driver.py +0 -724
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/driver_curl_cffi.py +0 -407
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/plugins/__init__.py +0 -48
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle.py +0 -484
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/plugins/autothrottle_adaptive.py +0 -1435
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/plugins/headers.py +0 -69
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/plugins/http_cache.py +0 -321
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/plugins/rate_limiter.py +0 -96
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/plugins/retry.py +0 -316
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/async_http/stages.py +0 -33
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/base.py +0 -324
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/base_plugin.py +0 -151
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/compression/__init__.py +0 -23
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/compression/strategy.py +0 -219
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/connection_pool.py +0 -349
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/context.py +0 -114
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/core/__init__.py +0 -15
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/core/base_async.py +0 -378
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/core/body_decoder.py +0 -26
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/core/mixins.py +0 -258
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/core/redirect_utils.py +0 -168
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/escalation.py +0 -950
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/factory.py +0 -210
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/__init__.py +0 -19
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/adaptive_semaphore.py +0 -65
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/batch_scheduler.py +0 -764
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/browser_factory.py +0 -580
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/browser_profile.py +0 -718
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/config.py +0 -84
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/context.py +0 -46
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/driver.py +0 -80
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/engine.py +0 -480
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/fetch_metrics.py +0 -115
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/net/__init__.py +0 -41
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/net/geoip.py +0 -136
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/net/proxy_pool.py +0 -225
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/net/rate_limiter.py +0 -139
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/page_actions.py +0 -186
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/page_fetch.py +0 -968
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/__init__.py +0 -71
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/_network_record.py +0 -66
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/captcha_detector.py +0 -315
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/captcha_solver.py +0 -108
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/cookie_consent.py +0 -565
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/form_filler.py +0 -177
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/human_bezier.py +0 -297
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/network_log.py +0 -406
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/ram_adaptive.py +0 -208
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/screenshot.py +0 -169
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/plugins/user_profile.py +0 -556
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/pool_lifecycle.py +0 -658
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/pooled_driver.py +0 -704
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/stages.py +0 -35
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/playwright/stealth_hints.py +0 -153
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/plugin_manager.py +0 -316
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/protocols.py +0 -118
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/undetected/__init__.py +0 -8
- graph_crawler-5.3.2/graph_crawler/infrastructure/transport/undetected/async_driver.py +0 -465
- graph_crawler-5.3.2/graph_crawler/native/__init__.py +0 -199
- graph_crawler-5.3.2/graph_crawler/native/bloom_filter.pyx +0 -255
- graph_crawler-5.3.2/graph_crawler/native/html_parser.pyx +0 -262
- graph_crawler-5.3.2/graph_crawler/native/setup.py +0 -103
- graph_crawler-5.3.2/graph_crawler/native/url_utils.pyx +0 -209
- graph_crawler-5.3.2/graph_crawler/observability/__init__.py +0 -62
- graph_crawler-5.3.2/graph_crawler/observability/decorators/__init__.py +0 -11
- graph_crawler-5.3.2/graph_crawler/observability/decorators/cache.py +0 -126
- graph_crawler-5.3.2/graph_crawler/observability/decorators/log.py +0 -56
- graph_crawler-5.3.2/graph_crawler/observability/decorators/retry.py +0 -121
- graph_crawler-5.3.2/graph_crawler/observability/decorators/timing.py +0 -43
- graph_crawler-5.3.2/graph_crawler/observability/error_tracing.py +0 -361
- graph_crawler-5.3.2/graph_crawler/observability/extensions/__init__.py +0 -18
- graph_crawler-5.3.2/graph_crawler/observability/extensions/memory_guard.py +0 -237
- graph_crawler-5.3.2/graph_crawler/observability/extensions/state_manager.py +0 -319
- graph_crawler-5.3.2/graph_crawler/observability/listeners/__init__.py +0 -33
- graph_crawler-5.3.2/graph_crawler/observability/listeners/base.py +0 -82
- graph_crawler-5.3.2/graph_crawler/observability/listeners/base_metrics_listener.py +0 -18
- graph_crawler-5.3.2/graph_crawler/observability/listeners/crawl_listener.py +0 -28
- graph_crawler-5.3.2/graph_crawler/observability/listeners/dlq_listener.py +0 -215
- graph_crawler-5.3.2/graph_crawler/observability/listeners/error_listener.py +0 -18
- graph_crawler-5.3.2/graph_crawler/observability/listeners/logging_listener.py +0 -88
- graph_crawler-5.3.2/graph_crawler/observability/listeners/metrics_listener.py +0 -109
- graph_crawler-5.3.2/graph_crawler/observability/listeners/node_listener.py +0 -33
- graph_crawler-5.3.2/graph_crawler/observability/listeners/plugin_listener.py +0 -28
- graph_crawler-5.3.2/graph_crawler/observability/listeners/storage_listener.py +0 -21
- graph_crawler-5.3.2/graph_crawler/observability/listeners/url_listener.py +0 -29
- graph_crawler-5.3.2/graph_crawler/observability/metrics/__init__.py +0 -23
- graph_crawler-5.3.2/graph_crawler/observability/metrics/memory_profiler.py +0 -508
- graph_crawler-5.3.2/graph_crawler/observability/metrics/metrics_collector.py +0 -408
- graph_crawler-5.3.2/graph_crawler/observability/metrics/prometheus_metrics.py +0 -293
- graph_crawler-5.3.2/graph_crawler/observability/metrics_core.py +0 -389
- graph_crawler-5.3.2/graph_crawler/observability/structured_logging.py +0 -216
- graph_crawler-5.3.2/graph_crawler/observability/tracing.py +0 -291
- graph_crawler-5.3.2/graph_crawler/optimizations/__init__.py +0 -89
- graph_crawler-5.3.2/graph_crawler/optimizations/generators.py +0 -477
- graph_crawler-5.3.2/graph_crawler/optimizations/memory_slots.py +0 -641
- graph_crawler-5.3.2/graph_crawler/optimizations/simhash_numba.py +0 -284
- graph_crawler-5.3.2/graph_crawler/shared/__init__.py +0 -25
- graph_crawler-5.3.2/graph_crawler/shared/constants.py +0 -938
- graph_crawler-5.3.2/graph_crawler/shared/dto/__init__.py +0 -38
- graph_crawler-5.3.2/graph_crawler/shared/dto/edge_dto.py +0 -52
- graph_crawler-5.3.2/graph_crawler/shared/dto/graph_dto.py +0 -97
- graph_crawler-5.3.2/graph_crawler/shared/dto/node_dto.py +0 -193
- graph_crawler-5.3.2/graph_crawler/shared/error_handling/__init__.py +0 -15
- graph_crawler-5.3.2/graph_crawler/shared/error_handling/error_handler.py +0 -333
- graph_crawler-5.3.2/graph_crawler/shared/exceptions.py +0 -394
- graph_crawler-5.3.2/graph_crawler/shared/platform/__init__.py +0 -125
- graph_crawler-5.3.2/graph_crawler/shared/platform/adaptive_resolver.py +0 -414
- graph_crawler-5.3.2/graph_crawler/shared/platform/config.py +0 -635
- graph_crawler-5.3.2/graph_crawler/shared/platform/detector.py +0 -334
- graph_crawler-5.3.2/graph_crawler/shared/platform/diagnostics.py +0 -660
- graph_crawler-5.3.2/graph_crawler/shared/platform/metrics.py +0 -299
- graph_crawler-5.3.2/graph_crawler/shared/security/__init__.py +0 -22
- graph_crawler-5.3.2/graph_crawler/shared/security/url_sanitizer.py +0 -100
- graph_crawler-5.3.2/graph_crawler/shared/security/url_validator.py +0 -299
- graph_crawler-5.3.2/graph_crawler/shared/utils/__init__.py +0 -212
- graph_crawler-5.3.2/graph_crawler/shared/utils/async_compat.py +0 -140
- graph_crawler-5.3.2/graph_crawler/shared/utils/bloom_filter.py +0 -373
- graph_crawler-5.3.2/graph_crawler/shared/utils/captcha/__init__.py +0 -36
- graph_crawler-5.3.2/graph_crawler/shared/utils/captcha/base.py +0 -92
- graph_crawler-5.3.2/graph_crawler/shared/utils/captcha/manager.py +0 -474
- graph_crawler-5.3.2/graph_crawler/shared/utils/celery_config.py +0 -332
- graph_crawler-5.3.2/graph_crawler/shared/utils/celery_helpers.py +0 -153
- graph_crawler-5.3.2/graph_crawler/shared/utils/cgroup_limits.py +0 -227
- graph_crawler-5.3.2/graph_crawler/shared/utils/content_decoder.py +0 -150
- graph_crawler-5.3.2/graph_crawler/shared/utils/distributed_rate_limiter.py +0 -265
- graph_crawler-5.3.2/graph_crawler/shared/utils/distributed_rate_limiter_backends.py +0 -284
- graph_crawler-5.3.2/graph_crawler/shared/utils/dns_cache.py +0 -370
- graph_crawler-5.3.2/graph_crawler/shared/utils/enterprise_ua_generator.py +0 -294
- graph_crawler-5.3.2/graph_crawler/shared/utils/event_publisher_mixin.py +0 -187
- graph_crawler-5.3.2/graph_crawler/shared/utils/fast_json.py +0 -240
- graph_crawler-5.3.2/graph_crawler/shared/utils/fingerprint.py +0 -36
- graph_crawler-5.3.2/graph_crawler/shared/utils/fingerprint_data.py +0 -99
- graph_crawler-5.3.2/graph_crawler/shared/utils/fingerprint_generators.py +0 -128
- graph_crawler-5.3.2/graph_crawler/shared/utils/fingerprint_profile.py +0 -121
- graph_crawler-5.3.2/graph_crawler/shared/utils/fingerprint_stealth.py +0 -105
- graph_crawler-5.3.2/graph_crawler/shared/utils/html_utils.py +0 -118
- graph_crawler-5.3.2/graph_crawler/shared/utils/id_generator.py +0 -195
- graph_crawler-5.3.2/graph_crawler/shared/utils/memory_optimizer.py +0 -536
- graph_crawler-5.3.2/graph_crawler/shared/utils/rate_limiter.py +0 -185
- graph_crawler-5.3.2/graph_crawler/shared/utils/regex_validator.py +0 -966
- graph_crawler-5.3.2/graph_crawler/shared/utils/shadow_dom.py +0 -36
- graph_crawler-5.3.2/graph_crawler/shared/utils/text_utils.py +0 -387
- graph_crawler-5.3.2/graph_crawler/shared/utils/url_patterns.py +0 -135
- graph_crawler-5.3.2/graph_crawler/shared/utils/url_utils.py +0 -595
- graph_crawler-5.3.2/graph_crawler/shared/utils/user_agent_rotator.py +0 -333
- graph_crawler-5.3.2/graph_crawler/shared/utils/validation_helpers.py +0 -225
- graph_crawler-5.3.2/graph_crawler/shared/utils/visualization.py +0 -134
- graph_crawler-5.3.2/graph_crawler/shared/utils/visualization_core.py +0 -566
- graph_crawler-5.3.2/graph_crawler/tools/__init__.py +0 -1
- graph_crawler-5.3.2/graph_crawler/tools/db_cleanup.py +0 -263
- graph_crawler-5.3.2/graph_crawler.egg-info/PKG-INFO +0 -531
- graph_crawler-5.3.2/graph_crawler.egg-info/SOURCES.txt +0 -479
- graph_crawler-5.3.2/pyproject.toml +0 -301
- graph_crawler-5.3.2/setup.cfg +0 -4
- {graph_crawler-5.3.2 → graph_crawler-5.3.3}/graph_crawler/py.typed +0 -0
- {graph_crawler-5.3.2 → graph_crawler-5.3.3}/graph_crawler.egg-info/dependency_links.txt +0 -0
- {graph_crawler-5.3.2 → graph_crawler-5.3.3}/graph_crawler.egg-info/entry_points.txt +0 -0
- {graph_crawler-5.3.2 → graph_crawler-5.3.3}/graph_crawler.egg-info/requires.txt +0 -0
- {graph_crawler-5.3.2 → graph_crawler-5.3.3}/graph_crawler.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 5.3.3 — 2026-10
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`IsolatedExecutor` / `IsolatedTaskError`** (`from graph_crawler import IsolatedExecutor`). Runs CPU-bound functions
|
|
8
|
+
in a `spawn` process pool: a native crash (SIGSEGV in libxml2/lxml, trafilatura, any C extension) or a hang of a
|
|
9
|
+
worker becomes `IsolatedTaskError(reason="crashed" | "timeout" | "unavailable")` in the caller, the pool restarts
|
|
10
|
+
and the crawl goes on. Tasks that shared the broken pool are retried once; a hung worker is killed after
|
|
11
|
+
`timeout` (default `DEFAULT_ISOLATED_TASK_TIMEOUT` = 30 s). Ordinary exceptions of the function propagate as is.
|
|
12
|
+
- **`CrawlerConfig.node_enrich_timeout`** and `crawl(..., node_enrich_timeout=...)` / `async_crawl(...)` /
|
|
13
|
+
`GraphCrawlerClient.crawl(...)`: per-node enrichment limit (HTML parse, plugins, subclass hook, hashes).
|
|
14
|
+
`None` keeps `DEFAULT_NODE_ENRICH_TIMEOUT` (45 s, `shared.constants`). `NodeScanner(driver, enrich_timeout=...)`.
|
|
15
|
+
- `run_in_html_pool(fn, *args)` (`graph_crawler.domain.entities.node`): runs `fn` in the HTML executor under its
|
|
16
|
+
semaphore. `Node.pop_discovered_links()` returns links extracted on `ON_HTML_PARSED` of an interrupted
|
|
17
|
+
`enrich_node`.
|
|
18
|
+
- `URLRuleMatcher.rule_matches(rule, url)`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **The `Node._update_from_context` hook and `get_content_hash`/`get_simhash` run in the HTML executor** under the
|
|
23
|
+
same semaphore as HTML parsing (they used the default `asyncio.to_thread` pool, `min(32, cpu+4)` threads, outside
|
|
24
|
+
the CPU budget). Concurrency of heavy subclass code is now bounded by `GRAPH_CRAWLER_HTML_PARSER_WORKERS`
|
|
25
|
+
(default — the cgroup CPU quota); `=1` serialises it completely. Code that is not thread-safe must use its own
|
|
26
|
+
lock or `GRAPH_CRAWLER_HTML_PARSER_WORKERS=1`; native code that can crash — `IsolatedExecutor`.
|
|
27
|
+
- **One URL rule — one decision.** `CrawlScheduler`, `LinkProcessor` and `RuleBasedScheduler` share
|
|
28
|
+
`URLRuleMatcher`: first match in list order, `SmartURLRule` is matched against its `scope` (the scheduler used to
|
|
29
|
+
run `re.search` over the full URL, so `SmartURLRule(r"/help", scope=PATH, should_scan=False)` excluded
|
|
30
|
+
`https://helpware.com/`). `GraphSpider` no longer copies `url_rules` with `should_scan=False` into `PathFilter`
|
|
31
|
+
(it applied them to the path, ignoring order and scope); `excluded_paths` / `included_paths` are unchanged.
|
|
32
|
+
- A URL rule whose `priority` is outside `[MIN_URL_PRIORITY, MAX_URL_PRIORITY]` (`[-100, 100]`) gets a WARNING when
|
|
33
|
+
the scheduler is created: `priority` is a queue position and is clamped; rule precedence is list order.
|
|
34
|
+
- `IDriver.fetch(url, *, referer, extra_headers, cookies)` is the contract of every driver: `BaseDriver`,
|
|
35
|
+
`EscalatingDriver` (caller cookies/headers merged with the host session — the session wins on a cookie name
|
|
36
|
+
clash, the session `User-Agent` is applied on top for HTTP/TLS tiers), `PooledPlaywrightDriver` (`extra_headers`),
|
|
37
|
+
`IAsyncDriver`, `IBrowserDriver`. `BaseDriver.fetch_many` passes per-URL `extra_headers_list` / `cookies_list` to
|
|
38
|
+
`fetch` (they were dropped).
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **Per-node timeout no longer drops discovered links.** `scan_node` / `scan_batch` return the links extracted on
|
|
43
|
+
`ON_HTML_PARSED` when enrichment exceeds the limit; the node is still `ERROR` / `FAILED`. Large listing pages, the
|
|
44
|
+
first to hit the limit, keep their edges.
|
|
45
|
+
|
|
46
|
+
## 5.3.2 — 2026-06
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **Fetch provenance on the node.** `Node.channel`, `bot_block_status`, `served_by_driver`, `served_by_engine`,
|
|
51
|
+
`escalations` and `fetch_info` read `metadata["fetch"]`; `Node.ok` (scanned, 2xx/3xx, not blocked, no error) and
|
|
52
|
+
`Node.is_blocked` separate useful pages from block and error pages.
|
|
53
|
+
- **Plugin routing.** `BaseNodePlugin.domains` (domain and subdomains) and `url_pattern` (regex), on the class or via
|
|
54
|
+
`config={"domains": [...], "url_pattern": ...}`, plus an overridable `applies_to(url)`. An invalid `url_pattern`
|
|
55
|
+
raises `ConfigurationError` on `register()`. Several instances of one plugin class with different routes run
|
|
56
|
+
side by side (they used to replace each other).
|
|
57
|
+
- **Typed plugin output.** `NodePluginContext.set_node_field(name, value)` writes a field declared by a `Node`
|
|
58
|
+
subclass, validated against its annotation (`"100"` → `int`); base fields are read-only. Fields are rolled back
|
|
59
|
+
together with `metadata`/`user_data` when the plugin fails.
|
|
60
|
+
- **Empty extraction warning.** `BaseNodePlugin.expects_nonempty` + `extraction_key`: a WARNING when the plugin left
|
|
61
|
+
`user_data[extraction_key]` empty.
|
|
62
|
+
- **`Graph.search(..., user_data_keys=("jobs",))`** searches the listed `user_data` keys as well.
|
|
63
|
+
- **`Node.public_user_data`** and `RESERVED_USER_DATA_KEYS` (`_link_anchors`, `_custom_fields`, `_node_class`).
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- A response with status 400 or higher gets `metadata["error"] = "HTTP <code>"` and is logged as a WARNING
|
|
68
|
+
(`HTTP 404 for <url> — page not scanned`).
|
|
69
|
+
- A bare 403/401/405 without vendor markers is still classified as `none`; the decision is now logged at INFO.
|
|
70
|
+
- Quieter logs: import writes nothing at INFO, platform detection runs once, the start of a crawl is one line,
|
|
71
|
+
and each page is one INFO line with `[channel=…]`, `[block=…]`, `[error=…]`.
|
|
72
|
+
- The temporary `_link_anchors` map is removed from the node once its edges are created (the anchor text stays in
|
|
73
|
+
`edge.metadata["anchor_text"]`). The default JSON export writes `public_user_data`.
|
|
74
|
+
- A third-party plugin that overwrites a reserved `user_data` key gets a WARNING.
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- `load_graph()` without `node_class=` restores a custom `Node` subclass when its module is already imported (the
|
|
79
|
+
class name is stored with the node; nothing is imported from the file). `Graph.copy()`, `union`, `intersection`,
|
|
80
|
+
`difference` and nodes created in a loaded graph keep the node class.
|
|
81
|
+
- `metadata` written by a plugin on `ON_NODE_CREATED` or `ON_AFTER_SCAN` is no longer lost.
|
|
82
|
+
- **Placeholder lists are detected as a JavaScript shell.** A 2xx body with five or more `placeholder` /
|
|
83
|
+
`skeleton` / `shimmer` elements makes `needs_browser` true, so `escalating` goes straight to the browser tier.
|
|
84
|
+
With `driver="http"` the node gets `metadata["js_shell_suspected"]` and a WARNING (once per host) suggests
|
|
85
|
+
`driver="escalating"` or `"playwright"`.
|
|
86
|
+
- **No duplicate edges.** A link repeated on a page (menu + footer + body) created a new `Edge` each time
|
|
87
|
+
(17.5 % of edges on uk.wikipedia); `LinkProcessor` now skips existing `(source, target)` pairs. `Graph.has_edge`
|
|
88
|
+
also sees the backend edge index.
|
|
89
|
+
- **`h1` children are no longer joined with spaces** (`Портал : Поточні події` → `Портал:Поточні події`).
|
|
90
|
+
- **Default ports are normalized** (`http://x:80`, `https://x:443`, empty port).
|
|
91
|
+
- `Graph.normalize_url()` is public; `LinkProcessor` checks the scheduler with the canonical form as well.
|
|
92
|
+
- **`NetworkLogPlugin` waits for network quiet** before publishing the log (`settle_ms`=2000, `quiet_ms`=300;
|
|
93
|
+
`settle_ms=0` restores the old behaviour) — late XHR (search/listing after hydration) was lost.
|
|
94
|
+
- `create_trailing_slash_rule` keeps the root path; an empty path is `/` for PATH-scope rules.
|
|
95
|
+
|
|
96
|
+
## 5.3.1 — 2026-06
|
|
97
|
+
|
|
98
|
+
### Added
|
|
99
|
+
|
|
100
|
+
- **Hydration state globals snapshot.** The Playwright driver serialises `window.__NAME__` objects (`__NUXT__`,
|
|
101
|
+
`__APOLLO_STATE__`, `__INITIAL_STATE__`, `__PINIA__`, …) with `JSON.stringify` after the page has run and embeds
|
|
102
|
+
them into the HTML snapshot as `<script type="application/json" data-agc-state="__NAME__">`. Nuxt 2 ships its
|
|
103
|
+
state as an IIFE (`window.__NUXT__=(function(a,b){return {…}}(…))`) which is JavaScript, not JSON, and was
|
|
104
|
+
invisible to any static state parser. Globals that already exist as a JSON `<script id="__NAME__">`
|
|
105
|
+
(`__NEXT_DATA__`) are not duplicated; `PageFetcher.state_globals_max_chars` (5 MB) caps the snapshot.
|
|
106
|
+
`inject_state_globals(html, states)` is exported for tests and other drivers.
|
|
107
|
+
|
|
108
|
+
## 5.3.0 — 2026-06
|
|
109
|
+
|
|
110
|
+
### Added
|
|
111
|
+
|
|
112
|
+
- **Page actions as public API.** `driver_config={"actions": [PageAction(...) | dict, ...]}` for the Playwright driver:
|
|
113
|
+
`click` / `fill` / `select` / `press` / `wait_for(response=…|selector=…)` / `scroll`, target by `selector`, `text`,
|
|
114
|
+
`placeholder` or `label` (`nth` among visible matches). Actions are validated when the driver is created and run
|
|
115
|
+
after content is ready and before the HTML snapshot and `CONTENT_READY` hooks — the network log is published after
|
|
116
|
+
the actions. Results land in `node.metadata["actions_log"]`, `["requests_after_actions"]` and `["actions_error"]`
|
|
117
|
+
(the first failing action stops the chain with a reason). `from graph_crawler import PageAction`.
|
|
118
|
+
- `engine.page_error_types()` — page error classes of all installed browser SDKs.
|
|
119
|
+
- `PageAction(type="back")`; action errors name the element that intercepts pointer events.
|
|
120
|
+
|
|
121
|
+
### Fixed
|
|
122
|
+
|
|
123
|
+
- Binary request bodies (gzip beacons) no longer raise `UnicodeDecodeError` inside Playwright event listeners
|
|
124
|
+
(`NetworkLogPlugin` and the action recorder read `post_data_buffer` with `errors="replace"`); the error used to break
|
|
125
|
+
the next Playwright call with `TypeError: function takes exactly 5 arguments`.
|
|
126
|
+
|
|
127
|
+
### Fixed
|
|
128
|
+
|
|
129
|
+
- `graph.get_node_by_url(seed)` finds the node after a redirect in the graph returned by `async_crawl`: `add_node`
|
|
130
|
+
restores the alias from `metadata["was_redirected_from"]`.
|
|
131
|
+
|
|
132
|
+
## 5.2.2 — 2026-06
|
|
133
|
+
|
|
134
|
+
### Fixed (test infrastructure)
|
|
135
|
+
|
|
136
|
+
- **The library no longer configures logging.** `GraphCrawlerClient.__init__` called `logging.basicConfig(INFO)`
|
|
137
|
+
when its logger had no handlers, so every crawl printed to stderr and reconfigured the application's root
|
|
138
|
+
logger. Removed; `graph_crawler` gets a `NullHandler`.
|
|
139
|
+
- **Noise demoted:** `HTML executor shutdown` and `lmdb not installed … Falling back to SQLiteEvictionStorage` are
|
|
140
|
+
DEBUG; `channel='chrome' not installed, falling back to bundled Chromium` is a WARNING once per process.
|
|
141
|
+
- **One version source.** `graph_crawler.__version__` (and the default User-Agent) come from the installed
|
|
142
|
+
package metadata (`pyproject.toml`); `__version__.py` no longer hard-codes a number that drifted (5.1.0 vs 5.2.0).
|
|
143
|
+
- **Test suite collects without optional extras.** Tests that need `psutil`, `rapidfuzz`, `stop-words`,
|
|
144
|
+
`html2md-clean` or `playwright` are skipped via `importorskip` instead of failing collection under `-x`.
|
|
145
|
+
`test_div_inline_fix.py` / `test_phase1_fixes.py` tested `html2md_clean` itself (no `graph_crawler` code) and were
|
|
146
|
+
removed from the core suite.
|
|
147
|
+
- GitLab CI (`.gitlab-ci.yml`): offline suite with `[dev]` and a minimal job without extras.
|
|
148
|
+
|
|
149
|
+
## 5.2.1 — 2026-06
|
|
150
|
+
|
|
151
|
+
### Fixed (freelance cases)
|
|
152
|
+
|
|
153
|
+
- **Captured XHR/fetch traffic could not be replayed outside the browser.** `NetworkLogPlugin` recorded the
|
|
154
|
+
URL and method of a request but not its body, so every POST/GraphQL endpoint (robota.ua lists vacancies via
|
|
155
|
+
`POST dracula.robota.ua/?q=getPublishedVacanciesList`) was unusable: a GET of the same URL returns 400.
|
|
156
|
+
Records now carry `post_data` and (on `response`) `request_headers`.
|
|
157
|
+
- **GraphQL responses overwrote each other.** `body_ref` was `sha1(url|status|content-type)` — all operations
|
|
158
|
+
POSTed to one `/graphql` URL shared a key and only the last body survived. The key now includes method and
|
|
159
|
+
request body.
|
|
160
|
+
- **JSON family by default.** The capture allow-list matched exact MIME types only; `application/graphql-
|
|
161
|
+
response+json`, `problem+json`, `vnd.api+json`, `text/json` were dropped. Without an explicit
|
|
162
|
+
`capture_content_types` every `*/json` and `*+json` type is captured (RFC 6839). Default `max_body_kb` 64 → 256
|
|
163
|
+
(listing APIs routinely exceed 64 KB).
|
|
164
|
+
- **Shadow DOM was invisible.** `page.content()` serializes only light DOM: content of open shadow roots (web
|
|
165
|
+
components, embedded price widgets) never reached the node. When a page has open shadow roots, the browser
|
|
166
|
+
driver serializes it with `Element.getHTML({shadowRoots})` and expands the declarative shadow roots into their
|
|
167
|
+
hosts (`shared/utils/shadow_dom.expose_shadow_roots`) — Lexbor, like the HTML spec, does not descend into
|
|
168
|
+
`<template>` content, so a plain declarative-shadow-DOM serialization would still hide it from selectors and link
|
|
169
|
+
extraction. Pages without shadow roots are untouched.
|
|
170
|
+
- `tests/unit/domain/entities/test_graph_new_features.py` still expected the `DeprecationWarning` that
|
|
171
|
+
`export_nodes()` stopped emitting in 4aab7525; it now asserts the opposite.
|
|
172
|
+
|
|
173
|
+
### Fixed (real-site tests)
|
|
174
|
+
|
|
175
|
+
- **Ctrl+C during `crawl()` hung until the crawl-level timeout** (28 s with `timeout=25`; forever without
|
|
176
|
+
one). `asyncio.wait_for` in Python 3.11 swallows the outer cancellation when the awaited coroutine finishes
|
|
177
|
+
at the same moment, so some workers survived `KeyboardInterrupt` and kept crawling. `NodeScanner` and the
|
|
178
|
+
escalation tier budget now use `asyncio.timeout()`; `CrawlCoordinator` cancels its workers on
|
|
179
|
+
`CancelledError`. Ctrl+C now returns in ~0.3 s.
|
|
180
|
+
- **`same_domain=False` was ignored** — without `allowed_domains` the `DomainFilter` default
|
|
181
|
+
(`domain+subdomains`) still applied and external links never entered the graph. Now maps to `allowed_domains=["*"]`.
|
|
182
|
+
- **`graph.metadata["stop_reason"]` was `None` after `timeout=` / `max_pages`** — only stop conditions were
|
|
183
|
+
recorded. Now `"timeout"`, `"max_pages"` or `"limit"`.
|
|
184
|
+
- **Network errors were invisible on the node**: a DNS/connection failure left `response_status=None`,
|
|
185
|
+
`scanned=True` and no message; `get_failed_nodes()` returned `[]`. The error text is now in
|
|
186
|
+
`node.metadata["error"]`, the HTTP status (if any) is kept, and `get_failed_nodes()` with default
|
|
187
|
+
arguments includes network-error nodes.
|
|
188
|
+
- **`storage="json", storage_config={"path": "site.json"}` was silently ignored** (file written to
|
|
189
|
+
`crawler_data/json/graph.json`). `path` is now honoured, like for sqlite (`JSONStorage(file_name=)`).
|
|
190
|
+
- `Graph.export_nodes()` / `Graph.export_edges()` are no longer deprecated: they are the public one-liners the
|
|
191
|
+
README shows and now delegate to `GraphExportUseCase` silently (no `DeprecationWarning`).
|
|
192
|
+
- `tests/manual/real_sites/run_all.py -j N` runs scenarios in parallel; `tests/manual/real_sites/test_user_cases.py`
|
|
193
|
+
— 23 pytest user scenarios on Wikipedia / robota.ua / GitHub / example.com, each hard-capped at 40 s.
|
|
194
|
+
|
|
195
|
+
### Changed
|
|
196
|
+
|
|
197
|
+
- **Engine contract verified end-to-end**. `tests/transport/
|
|
198
|
+
test_engine_contract.py` drives the real `PlaywrightDriver.fetch()` through three engines registered via the
|
|
199
|
+
public `register_engine()` on a recording fake SDK: the call sequence is byte-for-byte identical across
|
|
200
|
+
engines, stealth is injected iff `provides_stealth is False`, and `executable_path`/`ignore_default_args`/
|
|
201
|
+
launch args come only from the engine. No runtime code changed.
|
|
202
|
+
- **`LexborDocument.clean_text()` no longer re-parses the page**. To strip `script/style/noscript/svg/head` without mutating the shared tree it
|
|
203
|
+
serialised the document and built a second `LexborHTMLParser` — i.e. every page with the default
|
|
204
|
+
`TextExtractorPlugin` was parsed twice (`count_parses.py`: 2.0 → **1.0** per page; with `MarkdownPlugin`
|
|
205
|
+
1 parse + 1 clone). It now uses `tree.clone()`.
|
|
206
|
+
- **One `ContentDecoder` for every HTTP tier**. `AsyncDriver` (aiohttp) and `AsyncCurlCffiDriver` (curl_cffi) no longer rely on the client's own
|
|
207
|
+
`response.text`/`.text()`: they read the raw body and decode it through `ContentDecoder`
|
|
208
|
+
(`Content-Type` charset → `<meta charset>` → BOM → chardet → strict utf-8). Pages whose charset is only
|
|
209
|
+
declared in `<meta>` (e.g. windows-1251 without a header) were previously decoded as utf-8 by aiohttp,
|
|
210
|
+
failed, and silently became `html=None` with a "successful" 200. An undecodable body is now reported as
|
|
211
|
+
`FetchResponse.error` (`"ContentDecoder: cannot decode body …"`) with the status code preserved;
|
|
212
|
+
`ConnectionPoolManager.fetch_text()` goes through the same decoder. `FetchResponse.html` is a strict
|
|
213
|
+
`str` field — passing `bytes` raises `ValidationError` instead of being coerced. Browser tiers
|
|
214
|
+
(Playwright `page.content()`, nodriver `tab.get_content()`) already return `str`. Contract test:
|
|
215
|
+
`tests/transport/test_html_is_str_contract.py` (driver matrix returns `str`; cp1251 via meta/header;
|
|
216
|
+
binary → error).
|
|
217
|
+
- **Lazy public facade**. `graph_crawler/__init__.py` now
|
|
218
|
+
eagerly imports only `crawl`, `async_crawl`, `Graph`, `Node`, `save_graph`, `load_graph`,
|
|
219
|
+
`BaseStopCondition`; every other name in `__all__` (drivers, storages, exceptions, settings, views,
|
|
220
|
+
celery tasks, …) resolves on first access via module `__getattr__` and is cached. `aiohttp` is no longer
|
|
221
|
+
loaded by `import graph_crawler`. `bootstrap()` no longer calls `collect_system_metrics()`
|
|
222
|
+
(`psutil.cpu_percent(interval=0.1)` blocked import for 100 ms for a DEBUG line). Import time here:
|
|
223
|
+
470 ms → 228 ms. Optional names (`PlaywrightDriver`, `celery`, `EasyDistributedCrawler`, …) still return
|
|
224
|
+
`None` without their extra.
|
|
225
|
+
- **Escalation re-probe replays the solving tier's User-Agent**.
|
|
226
|
+
Playwright and nodriver now export `navigator.userAgent` as `extras["user_agent"]`;
|
|
227
|
+
`SessionState.absorb` records it (pinned once the session is solved, like `impersonate`/`proxy`) and
|
|
228
|
+
`EscalatingDriver._fetch_tier` sends it as `extra_headers={"User-Agent": …}` to HTTP/TLS tiers together
|
|
229
|
+
with the stored cookies. `cf_clearance` is bound to UA+IP+JA4, so a re-probe on Tier 1 with aiohttp's
|
|
230
|
+
default UA was rejected and the host never descended from the browser tier.
|
|
231
|
+
|
|
232
|
+
### Removed
|
|
233
|
+
|
|
234
|
+
- **`NodePluginContext.parser`**. Node plugins now read the
|
|
235
|
+
single Lexbor tree through the `HTMLDocument`/`HTMLNode` protocols: `LinkExtractorPlugin`
|
|
236
|
+
(`doc.css("a[href]")`, `doc.base_href()`), `MetadataExtractorPlugin`, `TextExtractorPlugin`
|
|
237
|
+
(`doc.clean_text()`, new in the protocol), `StructuredDataPlugin` (OG/Twitter/Microdata/RDFa parsers take
|
|
238
|
+
an `HTMLDocument`; `StructuredDataExtractor.extract(html=, doc=)`), `Email`/`PhoneExtractorPlugin`.
|
|
239
|
+
Migration: `context.parser.find_all(sel)` → `context.html_tree.css(sel)`, `.find()` → `.css_first()`,
|
|
240
|
+
`el.get_attribute()` → `el.attr()`. Fixed along the way in `LexborNode`: `attr()` returns `""` (not
|
|
241
|
+
`None`) for valueless boolean attributes such as `itemscope`, so nested Microdata/RDFa items are now
|
|
242
|
+
detected; `css()`/`css_first()` return descendants only (selectolax included the node itself, which made
|
|
243
|
+
Microdata recurse to `max_nesting_depth`).
|
|
244
|
+
- **`PooledPlaywrightDriver` legacy batch path**: `batch_legacy.py`
|
|
245
|
+
(`LegacyBatch._fetch_batch_legacy`, `_fetch_chain`) is gone. `persistent_browser=False` keeps its
|
|
246
|
+
"launch/stop per batch" semantics through the pool path: after a batch, once no fetch is in flight, the
|
|
247
|
+
pool and the engine session are closed (`_close_pool()` + `_stop_persistent_session()`, shared with
|
|
248
|
+
`close()`). Dead `self.playwright`/`self.browsers` cleanup removed from `close()`.
|
|
249
|
+
- **Escalation.** `classify_block()` rewritten to the
|
|
250
|
+
6.0 decision table: challenge/captcha vendor headers first, then unambiguous body captcha/challenge
|
|
251
|
+
markers (ahead of vendor hard-block headers), then short/blocking-page widgets, status-based verdicts
|
|
252
|
+
and empty-2xx. A bare `401/403/405` with no vendor markers is no longer a block. On the classifier corpus
|
|
253
|
+
it goes 25/37 → **37/37**.
|
|
254
|
+
|
|
255
|
+
- `needs_browser` heuristic (SPA shell: little visible text + SPA root / `<noscript>` JS hint / no
|
|
256
|
+
`<a href>`) is now the default `EscalationPolicy.needs_browser`; on a clean HTTP/TLS response it jumps
|
|
257
|
+
straight to the first browser tier (`escalation_reason="needs_browser"`).
|
|
258
|
+
- Per-tier `TierTimeouts` + `escalation_deadline_s` (60s) budget: a tier is skipped (last response
|
|
259
|
+
returned, browser never started) when the remaining budget is below its `min_budget`; each tier fetch
|
|
260
|
+
is wrapped in `asyncio.wait_for`. New `PER_NODE_FETCH_TIMEOUT` constant with a validator warning.
|
|
261
|
+
- Cross-tier session: `SessionState` / `HostSessionStore` carry solved cookies (`cf_clearance`, `__cf_bm`,
|
|
262
|
+
`datadome`, …) forward and back down to cheaper tiers on re-probe; `impersonate`/`proxy` are pinned once
|
|
263
|
+
a session is solved. curl_cffi pins the impersonate fingerprint; Playwright/nodriver export context
|
|
264
|
+
cookies via `extras["cookies"]`.
|
|
265
|
+
- `extras` contract: every driver stamps `channel`/`driver`/`engine` (via `BaseDriver`/`BaseAsyncDriver`
|
|
266
|
+
`_stamp_extras` + `_finalize_response`) even outside escalation.
|
|
267
|
+
- New Prometheus metrics `crawl_fetch_duration_seconds{channel,engine}`, `crawl_escalations_total`,
|
|
268
|
+
`crawl_escalation_deadline_hits_total`.
|
|
269
|
+
|
|
270
|
+
- **HTML parsing: Lexbor (selectolax) is the only core parser**.
|
|
271
|
+
`beautifulsoup4`, `lxml`, `lxml_html_clean` removed from `[project].dependencies`;
|
|
272
|
+
`BeautifulSoupAdapter`, `LxmlAdapter`, `ScrapyAdapter` deleted. New `HTMLDocument` / `HTMLNode`
|
|
273
|
+
protocols in `domain/value_objects/html_document.py`, implemented by `LexborDocument` in
|
|
274
|
+
`infrastructure/adapters/selectolax_adapter.py`. `<template>` is renamed to `gc-template` before
|
|
275
|
+
parsing so Vue/React SSR links inside templates are not lost. `IParser.parse()` returns `HTMLDocument`;
|
|
276
|
+
`NodePluginContext.html_tree` is now a `LexborDocument`. `get_parser()` accepts `auto|selectolax|lexbor`.
|
|
277
|
+
- `HTMLUtils.extract_links/extract_text/extract_metadata` accept an `HTMLDocument` (string input still
|
|
278
|
+
works but is deprecated).
|
|
279
|
+
- `SitemapParser.parse_large_sitemap_streaming()` uses stdlib `iterparse` by default; lxml is an
|
|
280
|
+
optional fast-path via the new extra `sitemap-fast`.
|
|
281
|
+
|
|
282
|
+
- **`html2md-clean` moved to the optional extra `markdown`** (`pip install "graph-crawler[markdown]"`);
|
|
283
|
+
`MarkdownGenerator/MarkdownOptions/MarkdownResult` re-exports in `graph_crawler.shared.utils` are lazy.
|
|
284
|
+
`MarkdownPlugin` feeds the already-parsed Lexbor tree to html2md-clean 0.5 (`generate_from_tree`) —
|
|
285
|
+
one parse per page instead of 2–4. `import graph_crawler` no longer loads bs4/lxml.
|
|
286
|
+
|
|
287
|
+
- **Dependency map**. Core is now 10 packages: `requests`,
|
|
288
|
+
`httpx`, `pydantic-settings`, `pybloom-live`, `fastapi`, `tenacity`, `stop-words`, `tiktoken`,
|
|
289
|
+
`markdown-it-py` removed from `[project].dependencies`. New extras: `browser` (`playwright` kept as alias),
|
|
290
|
+
`server` (fastapi/uvicorn/websockets), `text` (tiktoken/stop-words), `captcha`; `markdown` also pulls
|
|
291
|
+
`markdown-it-py`; `all` is recursive. Extras `cloudscraper` and `undetected-sync` dropped.
|
|
292
|
+
Extra-gated imports are lazy and fail fast with `requires extra '<name>'`; `transport.PlaywrightDriver/
|
|
293
|
+
RequestsDriver/CloudscraperDriver/RequestsSessionAdapter` are lazy re-exports (ImportError instead of `None`).
|
|
294
|
+
`CrawlerSettings` keeps `GC_*`/`__`/`.env` without pydantic-settings; `CrawlerConfig` is a plain `BaseModel`.
|
|
295
|
+
|
|
296
|
+
- **Transport cleanup**. Deleted: sync drivers
|
|
297
|
+
(`RequestsDriver`, `CloudscraperDriver`, `UndetectedChromeDriver`, `BotasaurusDriver`, `BaseSyncDriver`),
|
|
298
|
+
`AsyncDriverHTTP2` (httpx), `AsyncCloudscraperDriver`, `tls_client.py`, `StealthHTTPDriver`,
|
|
299
|
+
`session_manager/session_adapters/session_protocol`, `shared/utils/captcha_bypass.py`,
|
|
300
|
+
`shared/utils/proxy_manager.py`, packages `transport/http` and `transport/browser`.
|
|
301
|
+
`DriverType` is now `aiohttp | tls | playwright | nodriver | escalating` (+ `asyncio` alias);
|
|
302
|
+
strings `http`/`async`/`asyncio` → `aiohttp` and `stealth`/`curl_cffi` → `tls` are accepted for one
|
|
303
|
+
release with `DeprecationWarning`. One `AsyncDriver` (former `driver_adaptive.py` is now
|
|
304
|
+
`async_http/driver.py`); request hints (`referer`, `extra_headers`, `cookies`) are honoured.
|
|
305
|
+
`requests` is gone from the package: proxy health-check, CAPTCHA solvers/bypass and `SitemapParser`
|
|
306
|
+
use aiohttp (`SitemapParser.parse_sitemap/parse_from_robots` are `asyncio.run` wrappers,
|
|
307
|
+
`http_client=` is deprecated and ignored). `BloomFilter` is pure-python (xxhash) — `pybloom-live`
|
|
308
|
+
no longer needed.
|
|
309
|
+
`import graph_crawler` no longer loads any extra (guarded by `tests/unit/test_import_surface.py`), 3.8 s → 1.7 s here.
|
|
310
|
+
`shared/constants.py` no longer imports aiohttp — `br`/`zstd` are advertised
|
|
311
|
+
by `transport.compression.runtime_browser_headers()` only when the runtime can decode them;
|
|
312
|
+
one driver registry — `application.services.driver_factory` delegates to
|
|
313
|
+
`transport.factory.DriverFactory` (`register_factory`, `registered_names`); `SitemapParser(driver=)`
|
|
314
|
+
fetches robots.txt/sitemaps through the crawl `IDriver` (same tier chain), `SitemapSpider` passes its
|
|
315
|
+
driver, aiohttp is used directly only for binary `.gz`; `tests/transport/test_all_drivers_report_redirects.py`
|
|
316
|
+
is an `IDriver` acceptance matrix (aiohttp / tls / fake playwright / fake nodriver / escalating).
|
|
317
|
+
|
|
318
|
+
- **Escalation**: `EscalationPolicy.reprobe_interval` (5 min) —
|
|
319
|
+
one request per interval re-probes tier 0 for a host remembered on a higher tier (no herd of browser
|
|
320
|
+
re-escalations after TTL); `EscalationPolicy.max_hosts` (10k) — `HostTierMemory` is an LRU and drops
|
|
321
|
+
per-host locks together with entries. In strict mode (`GC_ENGINE_STRICT`) an `ImportError` raised _during_
|
|
322
|
+
`fetch` (lazy browser start without the SDK) now propagates instead of being turned into a network error.
|
|
323
|
+
|
|
324
|
+
- **`extras` contract persisted.** New
|
|
325
|
+
`FetchResponse.fetch_provenance()` / `FETCH_EXTRAS_KEYS`: a JSON-safe slice
|
|
326
|
+
(`bot_block_status, channel, driver, engine, escalations` + `escalation_reason`; cookies/impersonate dropped).
|
|
327
|
+
`NodeScanner` stores it in `node.metadata["fetch"]` for every response, including blocked/error ones, so it
|
|
328
|
+
survives JSON/SQLite/MongoDB/PostgreSQL storage. Contract test `tests/transport/test_extras_contract.py`.
|
|
329
|
+
|
|
330
|
+
### Fixed
|
|
331
|
+
|
|
332
|
+
- Transport `extras` (`bot_block_status`, tier, escalations) were dropped after fetch and never reached the
|
|
333
|
+
node or storage; for blocked pages nothing was transferred at all.
|
|
334
|
+
- `SmartPageFinder` read `html_tree.text` as a property; with Lexbor it is a method — page text was
|
|
335
|
+
silently dropped.
|
|
336
|
+
- `AsyncUndetectedDriver` accepts a plain `dict` config (`AsyncUndetectedConfig.from_mapping`) — building
|
|
337
|
+
the `nodriver` tier through `DriverFactory.create(DriverType.NODRIVER, config={...})` (as `EscalatingDriver`
|
|
338
|
+
does) raised `AttributeError`.
|
|
339
|
+
|
|
340
|
+
## 5.2.0 — 2026-06
|
|
341
|
+
|
|
342
|
+
### Added
|
|
343
|
+
|
|
344
|
+
- `infrastructure/transport/escalation.py`: `classify_block()` (Cloudflare / Akamai / DataDome /
|
|
345
|
+
PerimeterX / Incapsula markers, 403/429/503, empty 200), `EscalationPolicy`, `EscalationTier`,
|
|
346
|
+
`EscalatingDriver` — chain http → tls → browser → undetected with `max_tier`.
|
|
347
|
+
`driver="escalating"` works in `crawl()` / `async_crawl()` / `Crawler` / CLI.
|
|
348
|
+
- `HostTierMemory`: adaptive per-host tier memory — TTL from the moment of decision
|
|
349
|
+
(`GC_TIER_TTL`, default 1200 s), invalidation when the remembered tier gets blocked,
|
|
350
|
+
one escalation per host at a time (per-host lock). Per process.
|
|
351
|
+
- Strict engine mode: `GC_ENGINE_STRICT=1`, `{"browser_engine": {"strict": True}}` or
|
|
352
|
+
`driver_config={"engine_strict": True}` — `ImportError` instead of a silent fallback
|
|
353
|
+
`cloakbrowser → patchright → playwright` or a skipped escalation tier.
|
|
354
|
+
- Browser engine registry in `playwright/engine.py`: `register_engine()`, `resolve_engine()`,
|
|
355
|
+
`registered_engines()`. Built-in engines `cloakbrowser` → `patchright` → `playwright` with
|
|
356
|
+
automatic fail-open. `GC_BROWSER_ENGINE` env selects the engine when config has none.
|
|
357
|
+
`PlaywrightBrowserEngine.effective_name` / `fallback_reason`.
|
|
358
|
+
- `FetchResponse.extras` contract: `bot_block_status`, `channel`, `driver`, `engine`, `escalations`.
|
|
359
|
+
- `DriverType.TLS`, `NODRIVER`, `UNDETECTED`, `BOTASAURUS`, `ESCALATING`; `DriverFactory.create()`
|
|
360
|
+
accepts extra constructor kwargs (`policy=`).
|
|
361
|
+
- Extras: `tls`, `stealth`, `cloak`, `undetected`, `undetected-sync`, `antidetect`, `cloudscraper`, `system`.
|
|
362
|
+
- `README.md`, `CHANGELOG.md`.
|
|
363
|
+
|
|
364
|
+
### Changed
|
|
365
|
+
|
|
366
|
+
- `normalize_protocol` defaults to `False`: `http://` and `https://` are different URLs.
|
|
367
|
+
The crawler follows the real redirect instead of rewriting the scheme itself, so
|
|
368
|
+
http-only hosts stay reachable. Enable it explicitly to merge both schemes on dedup.
|
|
369
|
+
- `Graph.handle_redirect()` stores the alias as the real `Location` the server sent
|
|
370
|
+
(provenance); the normalized form is used only to find and merge nodes.
|
|
371
|
+
- Single `DriverType` enum (`transport/base.py`); `factory.py` re-exports it.
|
|
372
|
+
- `cloudscraper` moved from required dependencies to extra `cloudscraper`.
|
|
373
|
+
- `psutil` is optional (`system` extra); `MemoryGuard` imports it lazily.
|
|
374
|
+
- `requires-python = ">=3.11"` (upper bound removed; classifiers 3.11–3.14).
|
|
375
|
+
- `pytest` runs offline by default (`-m 'not manual'`, no coverage in `addopts`).
|
|
376
|
+
Network / real-site tests live in `tests/manual/` and run with `pytest -m manual tests/manual`.
|
|
377
|
+
- Project URLs point to the GitLab repository.
|
|
378
|
+
|
|
379
|
+
### Fixed
|
|
380
|
+
|
|
381
|
+
- `pooled_driver`: bounded walk over `redirected_from` (infinite loop on objects without a
|
|
382
|
+
`None` terminator); cookies are no longer added twice to a fresh browser.
|
|
383
|
+
- Tests synced with the code: redirect aliases, `html2md-clean` 0.4.0 API, `crawl_coordinator`
|
|
384
|
+
`per_host_max_in_flight`, `.gitignore` lookup at the repository root, `tools/db_cleanup.py`
|
|
385
|
+
CLI allow-listed for `print`. Playwright fake tests skip when `playwright` is not installed.
|
|
386
|
+
|
|
387
|
+
### Removed
|
|
388
|
+
|
|
389
|
+
- `tests/345.py`, `tests/ДОДАТКОВІ_ТЕСТИ.py`, `tests/manual_4a_games_test.py`, `tests/google_maps_results.json`.
|
|
390
|
+
- `EXTRACTION_AUDIT.md` and other analysis / plan documents that described work, not the code.
|
|
391
|
+
- `graph_crawler/data/ARCHITECTURE.md`, `MIGRATION_50_STEPS.md`, `REFACTORING_PLAN.md`, `mkdocs.yml`
|
|
392
|
+
(finished plans / config without content).
|
|
393
|
+
|
|
394
|
+
## 5.1.0
|
|
395
|
+
|
|
396
|
+
Previous release (sync-first API, Playwright pool, adaptive HTTP drivers, storage backends).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 GraphCrawler Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
include graph_crawler/py.typed
|
|
6
|
+
|
|
7
|
+
recursive-include graph_crawler/native *.pyx
|
|
8
|
+
include graph_crawler/native/setup.py
|
|
9
|
+
|
|
10
|
+
prune tests
|
|
11
|
+
global-exclude __pycache__
|
|
12
|
+
global-exclude *.py[cod]
|
|
13
|
+
global-exclude *.so
|
|
14
|
+
global-exclude *.pyd
|
|
15
|
+
global-exclude *.c
|
|
16
|
+
global-exclude .DS_Store
|