# SPDX-License-Identifier: AGPL-3.0-or-later """DuckDuckGo Web (general) This implementation fetches the link to the first API page (i.e. ``links.duckduckgo.com/d.js?...``) from duckduckgo.com and uses the ``n`` parameter of the API to fetch all subsequent pages. This also means that it's not possible to immediately search for the third page - the first and the second page would need to be loaded first. The reason why we can't just normally use the `vqd` value is that the API URLs require an additional parameter `dp` which seems generated at server-side, so we can't build it ourselves and must scrape it from the HTML pages. """ import typing as t import re from urllib.parse import quote_plus, urljoin from lxml import html from searx.utils import html_to_text, extract_text, eval_xpath from searx.result_types import EngineResults from searx.enginelib import EngineCache from searx.network import get if t.TYPE_CHECKING: from searx.extended_types import SXNG_Response from searx.search.processors import OnlineParams about = { "website": "https://duckduckgo.com/", "wikidata_id": "Q12805", "use_official_api": False, "require_api_key": False, "results": "JSON", } # engine dependent config categories = ["general"] paging = True base_url = "https://duckduckgo.com" CACHE: EngineCache """Cache to store the API URLs for combinations of (query, page).""" def setup(engine_settings: dict[str, str]): global CACHE # pylint:disable=global-statement CACHE = EngineCache(engine_settings["name"]) return CACHE def _fetch_first_page_link( query: str, headers: dict[str, str], ): """Search for a:: str: return f"nextpage_url|{query}|{pageno}" def _solve_jsa(resp: "SXNG_Response") -> "SXNG_Response": """Duckduckgo sometimes issues a challenge instead of json.""" # length that a real browser would report for where the broken snippet is html_len = { "