### UrlStore Default Configuration Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Minimal setup for UrlStore using default configuration. Use this for basic URL storage and addition. ```python from courlan import UrlStore # Minimal setup store = UrlStore() store.add_urls(['https://example.com/page1', 'https://example.com/page2']) ``` -------------------------------- ### Install Development Dependencies Source: https://github.com/adbar/courlan/blob/master/CONTRIBUTING.md Install Courlan with its development dependencies from a local checkout. This command is necessary to set up the project for local development and testing. ```bash pip install -e ".[dev]" ``` -------------------------------- ### Network Configuration Example Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Illustrates setting network configuration options such as the HTTP connection pool size, retry strategy, and acceptable HTTP status codes. ```python from courlan.meta import HTTP_POOL, RETRY_STRATEGY, ACCEPTABLE_CODES # Configure network settings HTTP_POOL = 10 RETRY_STRATEGY = {"tries": 3, "delay": 1, "backoff": 2} ACCEPTABLE_CODES = [200, 201, 301, 302] ``` -------------------------------- ### Install coURLan using pip Source: https://github.com/adbar/courlan/blob/master/README.md Install the latest stable version of coURLan from PyPI. You can also upgrade to the latest version or install directly from the GitHub repository. ```bash pip install courlan ``` ```bash pip install --upgrade courlan ``` ```bash pip install git+https://github.com/adbar/courlan.git ``` -------------------------------- ### URL Storage and Crawling Example Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Shows a basic workflow for using UrlStore to manage URLs for crawling. This is a core part of the URL Storage & Crawling use case. ```python from courlan.urlstore import UrlStore # Initialize UrlStore store = UrlStore() # Add URLs to the store store.add_urls(["http://example.com", "http://example.org"]) # Get URLs to download urls_to_download = store.get_download_urls(10) # Process downloaded URLs (example) for url in urls_to_download: # ... download content ... store.add_from_html(url, "Link") ``` -------------------------------- ### URL Manipulation Example Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Demonstrates using URL utility functions like extract_domain. This is part of the URL Manipulation use case. ```python from courlan.urlutils import extract_domain # Extract the domain from a URL domain = extract_domain("http://www.example.com/path") ``` -------------------------------- ### URL Validation Example Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Demonstrates using the check_url function for validating URLs. This is part of the URL Validation use case. ```python from courlan.core import check_url # Check if a URL is valid is_valid = check_url("http://example.com") ``` -------------------------------- ### UrlStore Combined Configuration Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Example of combining multiple configuration options for UrlStore, such as compressed storage, language filtering, strict mode, trailing slash normalization, and verbose output. ```python # For German language crawling with strict filtering store = UrlStore( compressed=True, # Reduce memory usage language='de', # Only German content strict=True, # Filter major platforms trailing_slash=False, # Normalize URL format verbose=True # Graceful interruption ) ``` -------------------------------- ### Example Usage of State Enum Source: https://github.com/adbar/courlan/blob/master/_autodocs/types.md Demonstrates how to use the State enum to check the visit status of a domain. This is useful for conditional logic within the UrlStore. ```python from courlan.urlstore import State domain_state = State.OPEN if domain_state == State.OPEN: print("Domain has unvisited URLs") ``` -------------------------------- ### Get all known domains Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Retrieves a list of all domain URLs that the UrlStore is currently aware of. ```python def get_known_domains(self) -> list[str]: ``` -------------------------------- ### Language Filtering Example Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Shows how to use language filtering functions like lang_filter. This is part of the Language & Filtering use case. ```python from courlan.filters import lang_filter # Filter content based on language (example) content = "This is English text." if lang_filter(content, "en"): print("Content is in English.") ``` -------------------------------- ### Example of UrlStore Interaction with UrlPathTuple Source: https://github.com/adbar/courlan/blob/master/_autodocs/types.md Illustrates how to retrieve known URLs for a domain using UrlStore methods, which internally utilize UrlPathTuple objects. Direct manipulation of UrlPathTuple is typically for internal use. ```python # Typically used internally by UrlStore # To get full URLs, use UrlStore methods: store.find_known_urls('https://example.com') # Returns: ['https://example.com/page1', 'https://example.com/page2', ...] ``` -------------------------------- ### Common Log Messages from Network Module Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/meta.md Examples of log messages from the network module, indicating network reachability issues and successful results. ```text WARNING: cannot reach URL: DEBUG: result found: ``` -------------------------------- ### Common Log Messages from UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/meta.md Examples of log messages from UrlStore, including invalid URLs, wrong languages, and discarded URLs. ```text DEBUG: Invalid URL: DEBUG: Wrong language: WARNING: Discarding URL: WARNING: discarded (size): urls: DEBUG: %s objects in GC after UrlStore.discard DEBUG: UrlStore reset, %s objects in GC ``` -------------------------------- ### Link Extraction Example Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Illustrates using the extract_links function to extract hyperlinks from a given URL. This is part of the Link Extraction use case. ```python from courlan.core import extract_links # Extract links from a URL links = extract_links("http://example.com") ``` -------------------------------- ### Configure Logging Verbosity Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Set up Python's logging module to control the verbosity of Courlan's output. This example enables all debug messages. ```python import logging # Enable all debug messages logging.basicConfig( level=logging.DEBUG, format='%(name)s - %(levelname)s - %(message)s' ) from courlan import check_url check_url('https://example.com') # Now shows debug logs ``` -------------------------------- ### Get downloadable URLs with time limits Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Fetches a list of URLs that are ready for immediate download. This method respects per-domain time limits to ensure polite crawling. It can return up to a specified maximum number of URLs. ```python def get_download_urls( self, time_limit: float = 10.0, max_urls: int = 10000, ) -> list[str]: ``` ```python # Get up to 100 URLs, respecting 10-second delay per domain urls = store.get_download_urls(time_limit=10, max_urls=100) ``` -------------------------------- ### Get Host and Path from URL Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/url_utilities.md Decomposes a URL into its host (scheme + netloc) and path (including query and fragment). Useful for organizing URLs by domain while preserving the full path. ```python from courlan import get_host_and_path get_host_and_path('https://www.un.org/en/about-us') # ('https://www.un.org', '/en/about-us') get_host_and_path('https://example.com:8080/path?id=1&lang=en#section') # ('https://example.com:8080', '/path?id=1&lang=en#section') get_host_and_path('https://example.com/') # ('https://example.com', '/') # Used internally by UrlStore for domain-based organization host, path = get_host_and_path('https://blog.example.com/article/page1') # host = 'https://blog.example.com' # path = '/article/page1' ``` -------------------------------- ### Example of SplitResult Usage Source: https://github.com/adbar/courlan/blob/master/_autodocs/types.md Shows the structure of a SplitResult object, which is returned by urllib.parse.urlsplit() and used for URL normalization. It contains components like scheme, netloc, path, query, and fragment. ```python from urllib.parse import SplitResult # A named tuple-like object with fields: SplitResult( scheme='https', netloc='www.example.com', path='/page', query='id=1', fragment='section' ) ``` -------------------------------- ### Get Host Info (Domain and Base URL) from URL Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/url_utilities.md Combines domain extraction and base URL retrieval into a single function. Returns the extracted domain name and the full base URL (protocol + domain). ```python from courlan import get_hostinfo domain, base_url = get_hostinfo('https://www.un.org/en/about-us') # domain = 'un.org' # base_url = 'https://www.un.org' domain, base_url = get_hostinfo('https://example.com') # domain = 'example.com' # base_url = 'https://example.com' ``` -------------------------------- ### Initialize UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Instantiate the UrlStore class. Options include enabling compression, setting a language filter, enforcing strict URL filtering, managing trailing slashes, and enabling verbose mode for signal handlers. ```python # Basic usage store = UrlStore() ``` ```python # With compression for large URL collections store = UrlStore(compressed=True) ``` ```python # With language filtering store = UrlStore(language='en', strict=True) ``` ```python # With verbose mode (Unix/Linux only) store = UrlStore(verbose=True) ``` -------------------------------- ### Initialize and add URLs to UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Demonstrates the basic usage pattern for initializing an UrlStore with specific options and adding initial URLs to begin a crawling process. ```python from courlan import UrlStore import time # Initialize store = UrlStore(compressed=True, language='en', verbose=True) # Add initial URLs store.add_urls(['https://example.com', 'https://other.org']) ``` -------------------------------- ### Sample URLs with Options Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Use sample_urls to select a subset of URLs. Configure sample size and options to exclude domains based on URL count. ```python from courlan import sample_urls sample = sample_urls( input_urls, samplesize, exclude_min = None, exclude_max = None, strict = False, verbose = False, ) ``` -------------------------------- ### Get Logger for a Specific Module Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/meta.md Obtain a logger instance for a particular Courlan module or the root logger. ```python logger = logging.getLogger('courlan.core') logger = logging.getLogger('courlan.urlstore') logger = logging.getLogger('courlan') # Root logger ``` -------------------------------- ### Configure Basic Logging Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/meta.md Set up basic logging to display all debug messages with a simple format. ```python import logging # Show all debug messages logging.basicConfig( level=logging.DEBUG, format='%(name)s - %(levelname)s - %(message)s' ) ``` -------------------------------- ### Get download counts per domain Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Retrieves a list containing the number of URLs downloaded from each known domain. ```python def get_all_counts(self) -> list[int]: ``` -------------------------------- ### Get domains with unvisited URLs Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Returns a list of domain URLs that still contain one or more unvisited URLs. ```python def get_unvisited_domains(self) -> list[str]: ``` -------------------------------- ### UrlStore Constructor Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Initializes a new UrlStore instance. Options include enabling compression, setting a language for filtering, enforcing strict URL filtering, preserving trailing slashes, and enabling verbose mode for signal handlers. ```APIDOC ## UrlStore() ### Description Initializes a new UrlStore instance with configurable options for compression, language filtering, strictness, trailing slash handling, and verbose mode. ### Parameters - **compressed** (bool) - Optional - Default: `False` - Enable compression (bz2 or zlib) for stored URLs to reduce memory usage. - **language** (str | None) - Optional - Default: `None` - ISO 639-1 language code for language-aware URL filtering when adding URLs. - **strict** (bool) - Optional - Default: `False` - Apply strict URL filtering when adding URLs. - **trailing_slash** (bool) - Optional - Default: `True` - Preserve trailing slashes when storing URLs. - **verbose** (bool) - Optional - Default: `False` - Enable signal handlers (SIGINT, SIGTERM) to dump unvisited URLs on interruption (Unix only). ### Examples ```python # Basic usage store = UrlStore() # With compression for large URL collections store = UrlStore(compressed=True) # With language filtering store = UrlStore(language='en', strict=True) # With verbose mode (Unix/Linux only) store = UrlStore(verbose=True) ``` ``` -------------------------------- ### UrlStore Constructor Configuration Source: https://github.com/adbar/courlan/blob/master/_autodocs/API-INDEX.md Configure UrlStore with options for compression, language filtering, strictness, trailing slashes, and verbosity. ```python UrlStore( compressed=False, # Compress stored URLs language=None, # ISO 639-1 language code strict=False, # Strict filtering trailing_slash=True, # Preserve trailing slashes verbose=False # Signal handlers for graceful exit ) ``` -------------------------------- ### Common Log Messages from check_url() Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/meta.md Examples of DEBUG messages generated by the check_url() function, indicating URL rejection reasons. ```text DEBUG: rejected, basic filter: DEBUG: rejected, type filter: DEBUG: rejected, lang filter: DEBUG: rejected, validation test: DEBUG: rejected, extension filter: DEBUG: rejected, domain name: DEBUG: rejected, path filter: DEBUG: discarded URL: ``` -------------------------------- ### Get total number of stored URLs Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Returns the aggregate count of all URLs currently stored within the UrlStore, across all domains. ```python def total_url_number(self) -> int: ``` -------------------------------- ### Initialize UrlStore for Web Crawling Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Configure UrlStore for efficient web crawling of news sites. Use compression for large collections, filter by language, enforce strictness to avoid spam, and normalize URLs. ```python from courlan import UrlStore store = UrlStore( compressed=True, # Handle large collections language='en', # Focus on English content strict=True, # Filter spam and ads trailing_slash=False # Normalize URLs ) ``` -------------------------------- ### News Crawler Workflow Source: https://github.com/adbar/courlan/blob/master/_autodocs/API-INDEX.md Set up a news crawler using UrlStore with strict filtering and compression. It adds seed URLs, establishes a download schedule, fetches content, and adds extracted links back to the store. ```python from courlan import UrlStore import time import requests # Strict filtering for news quality store = UrlStore(language='en', strict=True, compressed=True) # Add seed URLs # Assuming news_domains is defined elsewhere store.add_urls(news_domains) # Crawl loop with scheduling while store.unvisited_websites_number() > 0: schedule = store.establish_download_schedule(max_urls=20) for delay, url in schedule: time.sleep(delay) response = requests.get(url) store.add_from_html(response.text, url) ``` -------------------------------- ### Loading a Persisted UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Demonstrates how to load a previously persisted UrlStore object from a file. ```python from courlan.urlstore import UrlStore # Load a persisted UrlStore store = UrlStore.load_store("path/to/your/store.json") ``` -------------------------------- ### write Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Saves the current state of the UrlStore to disk as a pickled object. ```APIDOC ## write() ### Description Saves the UrlStore to disk as a pickled object. ### Method ```python def write(self, filename: str) -> None ``` ### Parameters - **filename** (str) - Required - The name of the file to save the UrlStore to ### Example ```python store.write('my_urls.pkl') ``` ``` -------------------------------- ### Logging Module Configuration Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Shows how to configure the logging module for the library, including setting the logging level. ```python import logging # Configure logging level logging.basicConfig(level=logging.INFO) ``` -------------------------------- ### Basic URL Format Filter Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/filters.md Checks if a URL starts with 'http' and falls within a length range of 10 to 500 characters. ```python def basic_filter(url: str) -> bool: # Checks basic URL format: starts with `http` and is 10-500 characters long. ``` -------------------------------- ### Load UrlStore State from File Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Loads a previously saved UrlStore state from a pickle file. The loaded store will resume with the same configuration as when it was saved. ```python from courlan import load_store store = load_store('urls.pkl') # Resumes with same configuration as when saved ``` -------------------------------- ### Basic Courlan Command-Line Usage Source: https://github.com/adbar/courlan/blob/master/README.md Demonstrates basic command-line usage for processing a list of URLs from an input file to an output file. ```bash $ courlan --inputfile url-list.txt --outputfile cleaned-urls.txt ``` -------------------------------- ### is_navigation_page() Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/filters.md Detects if a URL points to a navigation or overview page rather than a content page. Examples include pagination, category listings, and archives. ```APIDOC ## is_navigation_page() ### Description Detects if a URL points to a navigation or overview page rather than a content page. Examples include pagination (`/page/1/`), category listings (`/category/tech/`), archives (`/2024/`), etc. ### Parameters - **url** (str) - Required - URL to check. ### Return Value `True` if the URL matches navigation page patterns, `False` otherwise. ### Navigation Patterns Detected - Archives: `/archives/` - Authors: `/author/`, `/auth/` - Categories/Tags: `/category/`, `/cat/`, `/tag/`, `/tags/`, `/topic/`, `/topics/`, `/schlagwort/`, `/kategorie/` - Pagination: `/page/`, `/paged/`, `/seite/`, `/paged` - Query-based pagination: `?p=123` (numeric) ### Examples ```python from courlan import is_navigation_page is_navigation_page('https://www.randomblog.net/category/myposts') # True is_navigation_page('https://example.com/page/2/') # True is_navigation_page('https://example.com/article/my-post') # False is_navigation_page('https://blog.com/2024/01/article') # False (date-based URL structure is content) is_navigation_page('https://example.com/archives') # True ``` ``` -------------------------------- ### Crawl with UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/API-INDEX.md Initialize UrlStore, add seed URLs, and then iteratively fetch URLs, extract links from their HTML content, and add them back to the store until no unvisited URLs remain. ```python from courlan import UrlStore store = UrlStore(language='en', strict=True) store.add_urls(['https://example.com']) while store.unvisited_websites_number() > 0: url = store.get_url('https://example.com') if url: html = fetch(url) # Assuming fetch is defined elsewhere store.add_from_html(html, url) ``` -------------------------------- ### Extract Links with Options Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Use extract_links to get links from page content. Configure options like external link filtering, language, and strictness. ```python from courlan import extract_links links = extract_links( pagecontent, url, external_bool = False, no_filter = False, language = None, strict = True, trailing_slash = True, with_nav = False, redirects = False, reference = None, ) ``` -------------------------------- ### Include Navigation Pages Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/check_url.md Demonstrates how to include navigation and overview pages, such as pagination, by setting with_nav=True. By default, these pages are filtered out. ```python # Include pagination pages check_url('http://www.example.org/page/10/', with_nav=True) # Returns: ('http://www.example.org/page/10', 'example.org') # Default: exclude pagination check_url('http://www.example.org/page/10/') # Returns: None ``` -------------------------------- ### sample_urls() Source: https://github.com/adbar/courlan/blob/master/_autodocs/API-INDEX.md Samples URLs based on their associated domains. ```APIDOC ## sample_urls() ### Description Samples URLs by domain. This function selects a subset of URLs, organized or filtered by their respective domains. ### Method Not applicable (function call) ### Parameters None explicitly defined in this reference. ### Returns - `List of URLs`: A list containing sampled URLs. ``` -------------------------------- ### Import UrlStore and load_store Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Import the necessary classes from the courlan library. This is typically the first step before using UrlStore. ```python from courlan import UrlStore, load_store ``` -------------------------------- ### Get crawl delay from robots.txt Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Retrieves the crawl delay specified in a website's robots.txt file. If no delay is specified or rules are not found, a default value is returned. ```python def get_crawl_delay(self, website: str, default: float = 5) -> float: ``` ```python delay = store.get_crawl_delay('https://example.com', default=5) # Returns delay from robots.txt or 5 seconds ``` -------------------------------- ### Implement Checkpointing for Backup and Recovery Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Implement a function to create regular checkpoints of the UrlStore state. This is crucial for backup and recovery in long-running crawling processes. ```python # Regular checkpoints import shutil import time def checkpoint(store, interval=3600): last_save = time.time() while True: if time.time() - last_save > interval: store.write('urls_backup.pkl') last_save = time.time() # ... crawling ... ``` -------------------------------- ### Using RobotFileParser with UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/types.md Demonstrates how to parse robots.txt rules using the standard library's RobotFileParser and store them within the UrlStore. This allows the UrlStore to respect crawling restrictions. ```python from urllib.robotparser import RobotFileParser rules = RobotFileParser() rules.set_url('https://example.com/robots.txt') rules.read() store.store_rules('https://example.com', rules) # Later, check if URL is allowed if rules.can_fetch('*', 'https://example.com/page'): # Can fetch this URL pass ``` -------------------------------- ### URL Utility Functions Source: https://github.com/adbar/courlan/blob/master/README.md Provides various utility functions for URL manipulation, including getting base URLs, host and path, host information, and fixing relative URLs. ```python from courlan import * url = 'https://www.un.org/en/about-us' get_base_url(url) ``` ```python get_host_and_path(url) ``` ```python get_hostinfo(url) ``` ```python fix_relative_urls('https://www.un.org', 'en/about-us') ``` -------------------------------- ### Public API Exports from __init__.py Source: https://github.com/adbar/courlan/blob/master/_autodocs/MODULE-STRUCTURE.md Imports core functions like check_url and extract_links from the courlan.core module, and sample_urls from courlan.sampling. ```python from courlan.core import ( check_url, extract_links, filter_links, ) from courlan.sampling import sample_urls ``` -------------------------------- ### Focused Crawling with Robots.txt Source: https://github.com/adbar/courlan/blob/master/_autodocs/API-INDEX.md Demonstrates how to perform focused crawling by integrating robots.txt rules for filtering links. This approach allows for controlled crawling based on website policies. ```python from courlan import check_url, extract_links, filter_links import robots # Manual control for special cases robots_parser = robots.RobotFileParser() robots_parser.set_url('https://example.com/robots.txt') robots_parser.read() html = requests.get(url).text links, nav = filter_links( html, url, lang='en', rules=robots_parser, strict=True ) # Process nav links first for link in nav: # ... process navigation ... ``` -------------------------------- ### Get Base URL from URL String or Parsed Object Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/url_utilities.md Strips a URL to its base (scheme + netloc), removing path, query, and fragments. Accepts both string URLs and urllib.parse.SplitResult objects. ```python from courlan import get_base_url get_base_url('https://www.un.org/en/about-us') # 'https://www.un.org' get_base_url('https://example.com:8080/path?query=1#frag') # 'https://example.com:8080' # With parsed URL from urllib.parse import urlsplit parsed = urlsplit('https://example.com/path') get_base_url(parsed) # 'https://example.com' ``` -------------------------------- ### Get an unvisited URL from a domain Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Retrieves a single URL from the specified domain. Optionally marks the URL as visited immediately upon retrieval. Returns None if no unvisited URLs are available for the domain. ```python def get_url(self, domain: str, as_visited: bool = True) -> str | None: ``` ```python url = store.get_url('https://example.com') # Retrieves first unvisited URL and marks it visited # Returns None if all URLs visited ``` -------------------------------- ### Establish a download schedule with backoff Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Generates a list of URLs with associated delays, suitable for implementing a polite crawling schedule. The output is sorted by URL, and each tuple contains the delay in seconds and the URL itself. ```python def establish_download_schedule( self, max_urls: int = 100, time_limit: int = 10, ) -> list[str]: ``` ```python schedule = store.establish_download_schedule(max_urls=10, time_limit=5) # [(0.0, 'https://example.com/1'), # (5.0, 'https://example.com/2'), # (0.0, 'https://other.org/page'), # ...] for delay, url in schedule: sleep(delay) download(url) ``` -------------------------------- ### Robots.txt Parsing and Storage Source: https://github.com/adbar/courlan/blob/master/_autodocs/MODULE-STRUCTURE.md Demonstrates how to use `urllib.robotparser.RobotFileParser` to fetch and parse a website's `robots.txt` file, and then store these rules within a Courlan `UrlStore`. ```python from urllib.robotparser import RobotFileParser from courlan import UrlStore rules = RobotFileParser() rules.set_url(url + '/robots.txt') rules.read() store = UrlStore() store.store_rules(url, rules) ``` -------------------------------- ### check_url Returns None for Invalid URLs Source: https://github.com/adbar/courlan/blob/master/_autodocs/errors.md Provides examples of check_url returning None for various invalid URL formats, including invalid IP addresses, too short URLs, and incorrect schemes. ```python from courlan import check_url # Invalid URLs return None print(check_url('http://666.0.0.1/')) # None (invalid IP) print(check_url('http://invalid')) # None (too short) print(check_url('ftp://example.com')) # None (wrong scheme) ``` -------------------------------- ### Sample URLs by Domain Source: https://github.com/adbar/courlan/blob/master/_autodocs/README.md Uses `sample_urls` to select a specified number of URLs per domain from a larger list, useful for targeted crawling. ```python from courlan import sample_urls urls = ['https://example.com/' + str(i) for i in range(100)] sample = sample_urls(urls, 10) # 10 URLs per domain ``` -------------------------------- ### UrlStore Full Constructor Signature Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md This shows the complete signature for the UrlStore constructor, including all available parameters and their default values. ```python from courlan import UrlStore store = UrlStore( compressed: bool = False, language: str | None = None, strict: bool = False, trailing_slash: bool = True, verbose: bool = False, ) ``` -------------------------------- ### redirection_test(url: str) Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/meta.md Performs an HTTP HEAD request to a URL and follows redirects to get the final canonical URL. This function is used internally by `check_url(with_redirects=True)` and is crucial for resolving shortened URLs or complex redirect chains. ```APIDOC ## redirection_test(url: str) ### Description Performs an HTTP HEAD request to a URL and follows redirects to get the final canonical URL. Used internally by `check_url(with_redirects=True)`. ### Parameters #### Path Parameters - **url** (str) - Required - URL to test for redirects ### Return Value The final URL after following redirects (may differ from input URL). ### Raises - **ValueError**: If the URL cannot be reached or returns a non-acceptable HTTP status ### Acceptable Status Codes The function accepts these HTTP status codes: - 200 (OK) - 300, 301, 302, 303, 304, 305, 306, 307, 308 (Redirect codes) Any other status (4xx, 5xx, etc.) raises `ValueError`. ### Network Configuration - **HTTP Pool**: urllib3 PoolManager with: - 100 concurrent connection pools - 10-second timeout per request - Automatic retry strategy (2 retries for specific status codes) - SSL warnings disabled - **Retry Strategy**: Retries on status codes: 429, 499, 500, 502, 503, 504, 509, 520-527, 530, 598 - Max 2 retries with exponential backoff - Backoff factor: 1 second ### Examples ```python from courlan.network import redirection_test # URL with redirect final_url = redirection_test('https://example.com/redirect') # May return different URL if there were redirects # Shortener expansion final_url = redirection_test('https://bit.ly/example') # Returns the full expanded URL # Failed request raises ValueError try: final_url = redirection_test('https://unreachable.example.org') except ValueError as e: print(f"Cannot reach URL: {e}") ``` ### Internal Usage Called automatically by `check_url()` when `with_redirects=True`: ```python from courlan import check_url url, domain = check_url( 'https://httpbin.org/redirect-to?url=https://example.com', with_redirects=True ) # Uses redirection_test() internally ``` ### Source `courlan/network.py`: lines 46-71 ``` -------------------------------- ### Check for Blacklisted Domains in Strict Mode Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Demonstrates how to check if a domain is in the BLACKLIST and if strict mode is enabled. ```python from courlan.settings import BLACKLIST # Set of problematic domains to exclude in strict mode # Examples: 'facebook', 'google', 'instagram', 'twitter', 'amazon', etc. if domain in BLACKLIST and strict_mode: # Domain is blocked pass ``` -------------------------------- ### Polite Crawling with Rate Limiting Source: https://github.com/adbar/courlan/blob/master/_autodocs/README.md Utilize `UrlStore` to manage URLs for polite crawling. Establish a download schedule with maximum URLs and time limits to respect server rates, then process responses and add new URLs. ```python from courlan import UrlStore import time store = UrlStore() store.add_urls(initial_urls) while store.unvisited_websites_number() > 0: schedule = store.establish_download_schedule( max_urls=10, time_limit=5 ) for delay, url in schedule: time.sleep(delay) response = requests.get(url) store.add_from_html(response.text, url) ``` -------------------------------- ### Crawling Loop with URL Store Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Demonstrates a typical crawling loop using the URL store. It establishes a download schedule, fetches pages, extracts new links, and optionally stores robots.txt rules. This pattern is useful for managing large-scale web crawling efficiently. ```python while store.unvisited_websites_number() > 0: # Get batch of URLs with schedule schedule = store.establish_download_schedule(max_urls=10, time_limit=5) for delay, url in schedule: time.sleep(delay) # Fetch page response = requests.get(url) # Extract and add new links store.add_from_html(response.text, url, lang='en') # Optional: store robots.txt rules # store.store_rules(get_base_url(url), parse_robots(url)) ``` ```python # Save state for recovery store.write('urls_checkpoint.pkl') ``` -------------------------------- ### establish_download_schedule Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Returns URLs with backoff schedule tuples for polite crawling, ensuring delays between requests to the same domain. ```APIDOC ## establish_download_schedule() ### Description Returns URLs with backoff schedule tuples for polite crawling. ### Method ```python def establish_download_schedule( self, max_urls: int = 100, time_limit: int = 10, ) -> list[str] ``` ### Parameters - **max_urls** (int) - Optional - Maximum number of URLs to return (default: `100`) - **time_limit** (int) - Optional - Minimum seconds to wait before re-crawling a domain (default: `10`) ### Return List of tuples `(delay_seconds, url)`, sorted by URL ### Example ```python schedule = store.establish_download_schedule(max_urls=10, time_limit=5) # [(0.0, 'https://example.com/1'), # (5.0, 'https://example.com/2'), # (0.0, 'https://other.org/page'), # ...] for delay, url in schedule: sleep(delay) download(url) ``` ``` -------------------------------- ### Configure UrlStore for Research Data Collection Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Set up UrlStore for research purposes, allowing broader content with strict=False and enabling verbose output for graceful interruption handling. Includes periodic state saving. ```python store = UrlStore( strict=False, # Allow broader content verbose=True # Handle interruption gracefully ) # Periodically save state import time while crawling: # ... crawl URLs ... if time.time() % 3600 < 1: # Every hour store.write('checkpoint.pkl') ``` -------------------------------- ### Graceful Interruption Handling with UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/README.md Initialize `UrlStore` with `verbose=True` to automatically print unvisited URLs to stdout upon interruption (e.g., Ctrl+C). This allows for saving progress or resuming crawls. ```python from courlan import UrlStore store = UrlStore(verbose=True) # Now on Ctrl+C, unvisited URLs are printed to stdout # Redirect to file: python script.py > unvisited.txt ``` -------------------------------- ### Research Data Collection Workflow Source: https://github.com/adbar/courlan/blob/master/_autodocs/API-INDEX.md Use UrlStore for broad data collection with compression and verbose logging. Save the store's state periodically and later sample the dumped URLs for analysis. ```python from courlan import UrlStore, sample_urls # Collect broadly, then sample store = UrlStore(compressed=True, verbose=True) # Assuming all_urls is defined elsewhere store.add_urls(all_urls) # Save checkpoint store.write('research_urls.pkl') # Later: sample for analysis sample = sample_urls(store.dump_urls(), 100) ``` -------------------------------- ### Language-Specific Crawling with UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/README.md Initialize `UrlStore` with a specific language and strict mode. Add initial URLs and then filter extracted links from HTML content based on the specified language. ```python from courlan import UrlStore, filter_links store = UrlStore(language='de', strict=True) store.add_urls(german_urls) html = requests.get(url).text links, nav = filter_links(html, url, lang='de') store.add_urls(links, appendleft=nav) ``` -------------------------------- ### Manage URLs for Crawling with UrlStore Source: https://github.com/adbar/courlan/blob/master/_autodocs/README.md Demonstrates using `UrlStore` to add, retrieve, and process URLs for a web crawl, including adding links extracted from fetched HTML. ```python from courlan import UrlStore store = UrlStore(language='en', strict=True) store.add_urls(['https://example.com']) while store.unvisited_websites_number() > 0: url = store.get_url('https://example.com') if url: html = requests.get(url).text store.add_from_html(html, url) ``` -------------------------------- ### sample_urls() Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/sample_urls.md Samples URLs from a list using domain-based stratified sampling. Creates a balanced sample across multiple domains, optionally filtering by domain size constraints. Useful for creating representative URL datasets without bias toward large domains. ```APIDOC ## sample_urls(input_urls: list[str], samplesize: int, exclude_min: int | None = None, exclude_max: int | None = None, strict: bool = False, verbose: bool = False) ### Description Samples URLs from a list using domain-based stratified sampling. Creates a balanced sample across multiple domains, optionally filtering by domain size constraints. Useful for creating representative URL datasets without bias toward large domains. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **input_urls** (list[str]) - Required - List of URLs to sample from. - **samplesize** (int) - Required - Number of URLs to sample per domain. - **exclude_min** (int | None) - Optional - Exclude domains with fewer than this many URLs. Defaults to None. - **exclude_max** (int | None) - Optional - Exclude domains with more than this many URLs. Defaults to None. - **strict** (bool) - Optional - Enable strict URL filtering when organizing by domain. Defaults to False. - **verbose** (bool) - Optional - Enable debug logging output. Defaults to False. ### Return Value A list of sampled URLs (sorted alphabetically). ### Examples #### Basic sampling ```python from courlan import sample_urls urls = [ 'https://example1.org/' + str(i) for i in range(100) ] + [ 'https://example2.org/' + str(i) for i in range(50) ] # Sample 10 URLs per domain sample = sample_urls(urls, 10) # Returns ~20 URLs total (10 from each domain) print(len(sample)) # Approximately 20 ``` #### Filter by domain size ```python # Only sample from domains with 20-80 URLs sample = sample_urls(urls, 10, exclude_min=20, exclude_max=80) # Excludes domains outside this size range ``` #### Exclude small domains ```python # Only sample from domains with at least 50 URLs sample = sample_urls(urls, 10, exclude_min=50) # Domains with fewer than 50 URLs are skipped ``` #### Exclude large domains ```python # Only sample from domains with at most 100 URLs sample = sample_urls(urls, 10, exclude_max=100) # Domains with more than 100 URLs are skipped ``` #### Strict filtering ```python # Apply strict URL validation during sampling sample = sample_urls(urls, 10, strict=True) # URLs that fail strict validation are excluded before sampling ``` #### Verbose output ```python # Enable logging to see which domains are processed sample = sample_urls(urls, 10, verbose=True) # Prints debug information about sampling process ``` ``` -------------------------------- ### load_store() Source: https://github.com/adbar/courlan/blob/master/_autodocs/API-INDEX.md Loads a saved UrlStore object from disk. ```APIDOC ## load_store() ### Description Load saved UrlStore from disk. This function deserializes a UrlStore object that was previously saved to a file. ### Method Not applicable (function call) ### Parameters None explicitly defined in this reference. ### Returns - `UrlStore object`: The loaded UrlStore instance. ``` -------------------------------- ### URL Utilities Exports from __init__.py Source: https://github.com/adbar/courlan/blob/master/_autodocs/MODULE-STRUCTURE.md Imports URL utility functions such as extract_domain, filter_urls, fix_relative_urls, get_base_url, get_host_and_path, get_hostinfo, and is_external from the courlan.urlutils module. ```python from courlan.urlutils import ( extract_domain, filter_urls, fix_relative_urls, get_base_url, get_host_and_path, get_hostinfo, is_external, ) ``` -------------------------------- ### UrlStore Configuration for Memory Constraints Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Optimize UrlStore for memory-constrained environments by using maximum compression and disabling verbose mode to reduce overhead. Includes periodic dumping and reloading to clear caches. ```python store = UrlStore( compressed=True, # Maximum compression verbose=False # Disable signal handlers overhead ) # Periodically dump and reload to clear caches for batch in batches: store.add_urls(batch) # ... process ... store.reset() # Clear memory ``` -------------------------------- ### Courlan Command-Line Interface Help Source: https://github.com/adbar/courlan/blob/master/README.md Displays the help message for the Courlan command-line utility, outlining available options for input/output, filtering, and sampling. ```bash $ courlan --help usage: courlan [-h] -i INPUTFILE -o OUTPUTFILE [-d DISCARDEDFILE] [-v] [-p PARALLEL] [--strict] [-l LANGUAGE] [-r] [--sample SAMPLE] [--exclude-max EXCLUDE_MAX] [--exclude-min EXCLUDE_MIN] Command-line interface for Courlan options: -h, --help show this help message and exit I/O: Manage input and output -i INPUTFILE, --inputfile INPUTFILE name of input file (required) -o OUTPUTFILE, --outputfile OUTPUTFILE name of output file (required) -d DISCARDEDFILE, --discardedfile DISCARDEDFILE name of file to store discarded URLs (optional) -v, --verbose increase output verbosity -p PARALLEL, --parallel PARALLEL number of parallel processes (not used for sampling) Filtering: Configure URL filters --strict perform more restrictive tests -l LANGUAGE, --language LANGUAGE use language filter (ISO 639-1 code) -r, --redirects check redirects Sampling: Use sampling by host, configure sample size --sample SAMPLE size of sample per domain --exclude-max EXCLUDE_MAX exclude domains with more than n URLs --exclude-min EXCLUDE_MIN exclude domains with less than n URLs ``` -------------------------------- ### Follow Redirects with check_url Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/check_url.md Shows how to use the with_redirects=True option to have check_url() follow HTTP redirects and return the final URL. This requires the URL to be reachable. ```python # Follow HTTP redirects url, domain = check_url( 'https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.org', with_redirects=True ) # May return the final URL after redirects ``` -------------------------------- ### Custom URL Storage Implementation Source: https://github.com/adbar/courlan/blob/master/_autodocs/MODULE-STRUCTURE.md Shows how to extend the `UrlStore` class from Courlan to implement custom storage logic. This is useful for modifying how URLs are retrieved or managed. ```python from courlan import UrlStore class MyUrlStore(UrlStore): def get_url(self, domain, **kwargs): # Custom selection logic return super().get_url(domain, **kwargs) ``` -------------------------------- ### Storage Classes Exports from __init__.py Source: https://github.com/adbar/courlan/blob/master/_autodocs/MODULE-STRUCTURE.md Imports storage-related classes and functions like UrlStore and load_store from the courlan.urlstore module. ```python from courlan.urlstore import ( UrlStore, load_store, ) ``` -------------------------------- ### load_store() Source: https://github.com/adbar/courlan/blob/master/_autodocs/DOCUMENTATION-MAP.md Loads a persisted UrlStore object from a file. ```APIDOC ## load_store() ### Description Loads a previously persisted `UrlStore` object from a file. This allows you to resume a crawling session or access previously stored URL data. ### Method `load_store(filepath)` ### Parameters #### Path Parameters - **filepath** (string) - Required - The path to the file from which to load the `UrlStore`. ### Request Example ```python from courlan.urlstore import load_store # Load the UrlStore from a file loaded_store = load_store('path/to/your/urlstore_backup.json') # Now you can use the loaded_store object print(f"Loaded store with {loaded_store.total_url_number()} URLs.") ``` ### Response #### Success Response (200) - **UrlStore object** - The loaded `UrlStore` instance. #### Response Example ```json { "example": "UrlStore object instance" } ``` ``` -------------------------------- ### Enable Memory Recovery for Unvisited URLs Source: https://github.com/adbar/courlan/blob/master/_autodocs/errors.md Configure `UrlStore` with `verbose=True` to enable memory recovery. On receiving SIGINT or SIGTERM, it will print unvisited URLs, which can be redirected to a file for later processing. ```python from courlan import UrlStore # Enable with verbose=True store = UrlStore(verbose=True) # On Ctrl+C, will call print_unvisited_urls() before exiting # Pipe output to file for later processing: # python script.py 2>/dev/null > unvisited.txt ``` -------------------------------- ### Print all URLs and their status Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Outputs all stored URLs to the console, along with their corresponding visited status, formatted as 'URL\tvisited_status'. ```python def print_urls(self) -> None: ``` -------------------------------- ### Handle ValueError for Incomplete URL Source: https://github.com/adbar/courlan/blob/master/_autodocs/errors.md Illustrates catching a ValueError from get_host_and_path when an empty URL is provided, indicating an incomplete URL. ```python from courlan import get_host_and_path try: get_host_and_path('') # Empty URL except ValueError as e: print(e) # "incomplete URL: " ``` -------------------------------- ### Retrieve robots.txt rules Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/urlstore.md Fetches the stored robots.txt parsing rules for a specific website. Returns None if no rules have been stored for the given website. ```python def get_rules(self, website: str) -> RobotFileParser | None: ``` -------------------------------- ### Basic filter_links() Usage Source: https://github.com/adbar/courlan/blob/master/_autodocs/api-reference/filter_links.md Demonstrates basic usage of filter_links() without robots.txt. It shows how regular content links and priority navigation links are separated. Note that non-crawlable links like 'login' and 'contact' are automatically filtered. ```python from courlan import filter_links from urllib.robotparser import RobotFileParser html = ''' Article Category Page 2 Login Contact ''' # Without robots.txt links, priority_links = filter_links(html, 'https://example.org/') print(links) # ['/article/123'] print(priority_links) # ['/category/tech', '/page/2'] # Note: login and contact are filtered as not-crawlable ``` -------------------------------- ### Save UrlStore State to File Source: https://github.com/adbar/courlan/blob/master/_autodocs/configuration.md Saves the current state of the UrlStore to a file using Python's pickle format. This binary format is not human-readable but is efficient for storage and retrieval. ```python store.write('urls.pkl') # Binary format, not human-readable ``` -------------------------------- ### Sampling URLs by Domain Source: https://github.com/adbar/courlan/blob/master/README.md Use the sample_urls function to select a specified number of URLs from a larger list, useful for creating representative samples of web content. ```python from courlan import sample_urls my_urls = ['https://example.org/' + str(x) for x in range(100)] my_sample = sample_urls(my_urls, 10) ``` -------------------------------- ### Format Code with Ruff Source: https://github.com/adbar/courlan/blob/master/CONTRIBUTING.md Apply code formatting to the Courlan project and tests directory using Ruff. This ensures consistent code style across the project. ```bash ruff format courlan tests ``` -------------------------------- ### Logging Integration with Courlan Source: https://github.com/adbar/courlan/blob/master/_autodocs/MODULE-STRUCTURE.md Explains how to integrate Python's standard logging module with Courlan. All Courlan modules utilize the `logging` module for output, allowing for configurable verbosity. ```python import logging logging.basicConfig(level=logging.DEBUG) # All courlan modules use logging for output ``` -------------------------------- ### Cleaning Functions Exports from __init__.py Source: https://github.com/adbar/courlan/blob/master/_autodocs/MODULE-STRUCTURE.md Imports URL cleaning and normalization functions such as clean_url, normalize_url, and scrub_url from the courlan.clean module. ```python from courlan.clean import ( clean_url, normalize_url, scrub_url, ) ```