diff --git a/luxx/tools/services.py b/luxx/tools/services.py index b7fe420..3fb6ea2 100644 --- a/luxx/tools/services.py +++ b/luxx/tools/services.py @@ -5,42 +5,23 @@ from urllib.parse import parse_qs, urlparse, quote from typing import List from concurrent.futures import ThreadPoolExecutor, as_completed from bs4 import BeautifulSoup +from ddgs import DDGS class SearchService: - """DuckDuckGo search""" + """DuckDuckGo search using ddgs library""" def search(self, query: str, max_results: int = 5) -> List[dict]: - headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"} - url = f"https://html.duckduckgo.com/html/?q={quote(query)}" - - try: - resp = httpx.get(url, headers=headers, timeout=15, follow_redirects=True) - resp.raise_for_status() - except Exception: - return [] - - soup = BeautifulSoup(resp.text, "html.parser") results = [] - - for result in soup.select(".result")[:max_results]: - title_elem = result.select_one(".result__title a") - snippet_elem = result.select_one(".result__snippet") - - if title_elem: - raw_url = title_elem.get("href", "") - if "uddg=" in raw_url: - params = parse_qs(urlparse(raw_url).query) - clean_url = params.get("uddg", [raw_url])[0] - else: - clean_url = raw_url - + try: + for result in DDGS().text(query, max_results=max_results): results.append({ - "title": title_elem.get_text(strip=True), - "url": clean_url, - "snippet": snippet_elem.get_text(strip=True) if snippet_elem else "" + "title": result.get("title", ""), + "url": result.get("href", ""), + "snippet": result.get("body", "") }) - + except Exception: + pass return results diff --git a/pyproject.toml b/pyproject.toml index 63b4d31..e64e109 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ dependencies = [ "email-validator>=2.1.0", "shortuuid>=1.0.11", "sse-starlette>=2.0.0", + "ddgs>=5.0.0", ] [project.optional-dependencies]