Source code for searx.engines.braveapi
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Engine to search using the Brave (WEB) Search API.
.. _Brave Search API: https://api-dashboard.search.brave.com/documentation
Configuration
=============
The engine has the following mandatory setting:
- :py:obj:`api_key`
Optional settings are:
- :py:obj:`results_per_page`
.. code:: yaml
- name: braveapi
engine: braveapi
api_key: 'YOUR-API-KEY' # required
results_per_page: 20 # optional
The API supports paging and time filters.
"""
import typing as t
from urllib.parse import urlencode
from dateutil import parser
from searx.exceptions import SearxEngineAPIException
from searx.result_types import EngineResults
if t.TYPE_CHECKING:
from searx.extended_types import SXNG_Response
from searx.search.processors import OnlineParams
about = {
"website": "https://api.search.brave.com/",
"wikidata_id": None,
"official_api_documentation": "https://api-dashboard.search.brave.com/documentation",
"use_official_api": True,
"require_api_key": True,
"results": "JSON",
}
api_key: str = ""
"""API key for Brave Search API (required)."""
categories = ["general", "web"]
paging = True
safesearch = True
time_range_support = True
results_per_page: int = 20
"""Maximum number of results per page (default 20)."""
base_url = "https://api.search.brave.com/res/v1/web/search"
"""Base URL for the Brave Search API."""
time_range_map = {"day": "past_day", "week": "past_week", "month": "past_month", "year": "past_year"}
"""Mapping of SearXNG time ranges to Brave API time ranges."""
[docs]
def init(_):
"""Initialize the engine."""
if not api_key:
raise SearxEngineAPIException("No API key provided")
[docs]
def request(query: str, params: "OnlineParams") -> None:
"""Create the API request."""
search_args: dict[str, str | int | None] = {
"q": query,
"count": results_per_page,
"offset": (params["pageno"] - 1) * results_per_page,
}
# Apply time filter if specified
if params["time_range"]:
search_args["time_range"] = time_range_map.get(params["time_range"])
# Apply SafeSearch if enabled
if params["safesearch"]:
search_args["safesearch"] = "strict"
params["url"] = f"{base_url}?{urlencode(search_args)}"
params["headers"]["X-Subscription-Token"] = api_key
def _extract_published_date(published_date_raw: str):
"""Extract and parse the published date from the API response.
Args:
published_date_raw: Raw date string from the API
Returns:
Parsed datetime object or None if parsing fails
"""
if not published_date_raw:
return None
try:
return parser.parse(published_date_raw)
except parser.ParserError:
return None
[docs]
def response(resp: "SXNG_Response") -> EngineResults:
"""Process the API response and return results."""
res = EngineResults()
data = resp.json()
for result in data.get("web", {}).get("results", []):
res.add(
res.types.MainResult(
url=result["url"],
title=result["title"],
content=result.get("description", ""),
publishedDate=_extract_published_date(result.get("age")),
thumbnail=result.get("thumbnail", {}).get("src"),
),
)
return res