From 70a1b5c9ef5a5116620846a0a65415268670c5ee Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 29 Mar 2026 17:10:56 +0000 Subject: [PATCH] search-qwant --- usr/bin/search-duckduck | 84 ++++++++++++++++++++++------------- usr/bin/search-qwant | 98 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 31 deletions(-) create mode 100755 usr/bin/search-qwant diff --git a/usr/bin/search-duckduck b/usr/bin/search-duckduck index 8de8e70..399aed2 100755 --- a/usr/bin/search-duckduck +++ b/usr/bin/search-duckduck @@ -2,72 +2,94 @@ import sys import subprocess +import time +import random + -# Vérifie et installe les dépendances si nécessaire def ensure_package(pkg): try: __import__(pkg) except ImportError: - print(f"{pkg} non trouvé, installation...") subprocess.check_call([sys.executable, "-m", "pip", "install", pkg]) -ensure_package("bs4") -ensure_package("requests") + +for pkg in ("bs4", "requests"): + ensure_package(pkg) from bs4 import BeautifulSoup import requests import argparse -def recherche_duckduckgo(query, n=5): - url = "https://html.duckduckgo.com/html/" - headers = {"User-Agent": "Mozilla/5.0"} +def create_session(): + session = requests.Session() + session.headers.update({ + "User-Agent": "Mozilla/5.0" + }) + return session + + +def fetch(session, method, url, **kwargs): + for _ in range(3): + try: + response = session.request(method, url, timeout=10, **kwargs) + if response.status_code == 200: + return response + time.sleep(5) + except requests.RequestException: + time.sleep(5) + return None + + +def recherche_duckduckgo(session, query, n): + url = "https://html.duckduckgo.com/html/" + response = fetch(session, "POST", url, data={"q": query}) + + if not response: + return [] - response = requests.post(url, data={"q": query}, headers=headers) soup = BeautifulSoup(response.text, "html.parser") results = [] - for result in soup.find_all("a", class_="result__a", limit=n): - title = result.get_text() + for result in soup.select("a.result__a")[:n]: + title = result.get_text(strip=True) link = result.get("href") - results.append((title, link)) + if link: + results.append((title, link)) + time.sleep(random.uniform(1.5, 3.5)) return results -def extract_text(url, max_chars=300): - try: - headers = {"User-Agent": "Mozilla/5.0"} - response = requests.get(url, headers=headers, timeout=5) +def extract_text(session, url, max_chars): + response = fetch(session, "GET", url) - soup = BeautifulSoup(response.text, "html.parser") + if not response: + return "[Erreur: accès impossible]" - # Récupère le texte brut - text = soup.get_text(separator=" ", strip=True) + soup = BeautifulSoup(response.text, "html.parser") + text = soup.get_text(separator=" ", strip=True) - return text[:max_chars] + "..." - - except Exception as e: - return f"[Erreur lors de l'accès au site: {e}]" + return (text[:max_chars] + "...") if len(text) > max_chars else text -def main(): +def main(argc, argv): parser = argparse.ArgumentParser(description="Recherche + extraction de texte") - parser.add_argument("query", type=str, help="Terme de recherche") - parser.add_argument("-n", "--number", type=int, default=5, help="Nombre de résultats") - parser.add_argument("--chars", type=int, default=1000, help="Nombre de caractères à extraire") + parser.add_argument("query", type=str) + parser.add_argument("-n", "--number", type=int, default=5) + parser.add_argument("--chars", type=int, default=1000) - args = parser.parse_args() + args = parser.parse_args(argv[1:]) - results = recherche_duckduckgo(args.query, args.number) + session = create_session() + results = recherche_duckduckgo(session, args.query, args.number) for i, (title, link) in enumerate(results, 1): print(f"\n{i}. {title}") print(f"URL: {link}") - - snippet = extract_text(link, args.chars) + snippet = extract_text(session, link, args.chars) print(f"Extrait: {snippet}") if __name__ == "__main__": - main() + main(len(sys.argv), sys.argv) diff --git a/usr/bin/search-qwant b/usr/bin/search-qwant new file mode 100755 index 0000000..d853b48 --- /dev/null +++ b/usr/bin/search-qwant @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +import sys +import subprocess +import time +import random + + +def ensure_package(pkg): + try: + __import__(pkg) + except ImportError: + subprocess.check_call([sys.executable, "-m", "pip", "install", pkg]) + + +ensure_package("requests") + +import requests +import argparse + + +def create_session(): + session = requests.Session() + session.headers.update({ + "User-Agent": "Mozilla/5.0" + }) + return session + + +def fetch(session, url, params=None, retries=2, timeout=5): + for _ in range(retries): + try: + r = session.get(url, params=params, timeout=timeout) + if r.status_code == 200: + return r.json() + time.sleep(random.uniform(1, 2)) + except requests.RequestException: + time.sleep(random.uniform(1, 2)) + return None + + +def recherche_qwant(session, query, n): + url = "https://api.qwant.com/v3/search/web" + params = { + "q": query, + "count": n, + "offset": 0, + "t": "web", + "safesearch": 0, + "locale": "en_US" + } + + data = fetch(session, url, params=params) + if not data: + return [] + + results = [] + items = data.get("data", {}).get("result", {}).get("items", []) + + for item in items[:n]: + title = item.get("title") + link = item.get("url") + if title and link: + results.append((title, link)) + + time.sleep(random.uniform(1, 2)) + return results + + +def extract_text(session, url, max_chars): + try: + r = session.get(url, timeout=5) + text = r.text + return (text[:max_chars] + "...") if len(text) > max_chars else text + except Exception as e: + return f"[Erreur: {e}]" + + +def main(argc, argv): + parser = argparse.ArgumentParser() + parser.add_argument("query", type=str) + parser.add_argument("-n", "--number", type=int, default=5) + parser.add_argument("--chars", type=int, default=1000) + + args = parser.parse_args(argv[1:]) + + session = create_session() + results = recherche_qwant(session, args.query, args.number) + + for i, (title, link) in enumerate(results, 1): + print(f"\n{i}. {title}") + print(f"URL: {link}") + snippet = extract_text(session, link, args.chars) + print(f"Extrait: {snippet}") + + +if __name__ == "__main__": + main(len(sys.argv), sys.argv)