๐Ÿ”Ž async-search-scraper

May 10, 2026 ยท View on GitHub

Python License: MIT Async

Query a dozen search engines from a single async Python call โ€” and get back a unified, deduplicated list of results.

  • ๐Ÿง  One unified async API over 12 engines (Bing, Brave, Yahoo, Startpage, AOL, Ask, Tor's Torch, โ€ฆ).
  • โšก Drop-in CLI for one-shot searches with print / html / csv / json output.
  • ๐Ÿงฐ Built-in pagination, deduplication, result filtering, and HTTP/SOCKS proxy support.

๐Ÿš€ Quick start

pip install -r requirements.txt
import asyncio
from search_engines import Bing

async def main():
    async with Bing() as engine:
        results = await engine.search("my query")
        print(results.links())

asyncio.run(main())

That's it โ€” results.links() gives you a flat list[str] of URLs; results itself iterates over {host, link, title, text} dicts.


๐Ÿงญ Supported engines

EngineStatusNotes
Bingโœ… Working
Braveโœ… WorkingUses the official Brave Search API; set BRAVE_API_KEY or pass api_key=....
Yahooโœ… WorkingHandles the GDPR consent redirect automatically.
Startpageโœ… Working
AOLโœ… Working
Torch๐Ÿง… Tor onlyRequires a running TOR proxy (socks5://127.0.0.1:9050).
AskโŒ Deprecated
GoogleโŒ Deprecated
DuckDuckGoโŒ Deprecated
DogpileโŒ Deprecated
MojeekโŒ Deprecated
QwantโŒ Deprecated

๐Ÿ“š Usage as a library

Single engine

import asyncio
from search_engines import Bing

async def main():
    async with Bing() as engine:
        results = await engine.search("my query", pages=2)
        for item in results:
            print(item["title"], "โ†’", item["link"])

asyncio.run(main())

Multiple engines, deduplicated

import asyncio
from search_engines import Bing, Yahoo, Startpage

async def main():
    all_links = set()
    for cls in (Bing, Yahoo, Startpage):
        async with cls() as engine:
            engine.ignore_duplicate_urls = True
            results = await engine.search("python programming", pages=1)
            all_links.update(results.links())
    print(f"{len(all_links)} unique URLs")

asyncio.run(main())

Brave (API key)

Note

Brave uses the official Search API. Get a free key at api.search.brave.com and either export BRAVE_API_KEY or pass api_key=... to the constructor.

import asyncio, os
from search_engines import Brave

async def main():
    async with Brave(api_key=os.environ["BRAVE_API_KEY"]) as engine:
        results = await engine.search("my query")
        print(results.links())

asyncio.run(main())

๐Ÿ–ฅ๏ธ Usage as a CLI

python search_engines_cli.py -e bing,yahoo -q "my query" -o json,print
FlagPurposeDefault
-qSearch query (required)โ€”
-eEngine(s), comma-separated, or allgoogle
-pNumber of pages to fetch20
-oOutput: any combination of print, html, csv, jsonprint
-nOutput filename (without extension)search_results/output
-fFilter results by url / title / text / hostnone
-iDrop duplicate URLs across enginesoff
-proxyHTTP/SOCKS proxy URL (protocol://ip:port)none

Typical output:

Searching Bing
page: 1        links: 10
page: 2        links: 20
1  https://www.python.org/                          Welcome to Python.org
2  https://en.wikipedia.org/wiki/Python_(...)       Python (programming language) - Wikipedia
...

โš™๏ธ Configuration

  • BRAVE_API_KEY โ€” environment variable read by the Brave engine when api_key= isn't passed explicitly.
  • Proxy โ€” any URL supported by aiohttp_socks: http://, https://, socks4://, socks5://. Pass via Bing(proxy="socks5://127.0.0.1:9050") or -proxy on the CLI.
  • Tunables โ€” TIMEOUT, USER_AGENT, default page count, and output directory live in search_engines/config.py.

๐Ÿงฉ Extending โ€” adding a new engine

Drop a new class into search_engines/engines/, subclass SearchEngine, override _selectors, _first_page, _next_page, then register it in search_engines/engines/__init__.py's search_engines_dict. Mimic bing.py for a pure-HTML engine, or brave.py / ask.py for JSON-driven ones.


๐Ÿ“ฆ Requirements

Python 3.9โ€“3.13, plus the pinned dependencies in requirements.txt (aiohttp, aiohttp_socks, beautifulsoup4, curl_cffi, requests).

pip install -r requirements.txt
python setup.py install   # optional, to install the package itself

๐Ÿ“„ License

MIT โ€” see LICENSE.

Originally created by Tasos M. Adamopoulos โ€” see Search-Engines-Scraper for the upstream repo.