#!/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]) for pkg in ("bs4", "requests"): ensure_package(pkg) from bs4 import BeautifulSoup import requests import argparse 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 [] soup = BeautifulSoup(response.text, "html.parser") results = [] for result in soup.select("a.result__a")[:n]: title = result.get_text(strip=True) link = result.get("href") if link: results.append((title, link)) time.sleep(random.uniform(1.5, 3.5)) return results def extract_text(session, url, max_chars): response = fetch(session, "GET", url) if not response: return "[Erreur: accès impossible]" soup = BeautifulSoup(response.text, "html.parser") text = soup.get_text(separator=" ", strip=True) return (text[:max_chars] + "...") if len(text) > max_chars else text def main(argc, argv): parser = argparse.ArgumentParser(description="Recherche + extraction de texte") 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_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(session, link, args.chars) print(f"Extrait: {snippet}") if __name__ == "__main__": main(len(sys.argv), sys.argv)