Skip to content

Instantly share code, notes, and snippets.

@un1tz3r0
Last active July 15, 2025 08:27
Show Gist options
  • Save un1tz3r0/5077a262bc6502bcadd2de743cedcb4d to your computer and use it in GitHub Desktop.
Save un1tz3r0/5077a262bc6502bcadd2de743cedcb4d to your computer and use it in GitHub Desktop.
Python script to search the ollama.com model database without leaving the comfort of your CLI. Also importable as a module if you want to call their search API programmatically.
import aiohttp
import yarl
import bs4
import pathlib, re, click
import asyncio
from contextlib import asynccontextmanager
from typing import Optional, Union, Set, List
@asynccontextmanager
async def ensure_client_session(client_session=None):
if client_session == None:
async with aiohttp.ClientSession() as client_session:
try:
yield client_session
finally:
pass
else:
try:
yield client_session
finally:
pass
from enum import Enum
class OllamaSearchCategory(Enum):
EMBEDDING = 'embedding'
VISION = 'vision'
TOOLS = 'tools'
THINKING = 'thinking'
NONE = None
class OllamaSearchOrder(Enum):
POPULAR = None
NEWEST = 'newest'
from multidict import MultiDict
async def ollama_com_search(*query, category: Union[OllamaSearchCategory, Set[OllamaSearchCategory]] = [OllamaSearchCategory.NONE], order: OllamaSearchOrder = OllamaSearchOrder.POPULAR, client_session: Optional[aiohttp.ClientSession] = None, **kwargs):
async with ensure_client_session(client_session) as client_session:
url = yarl.URL('https://ollama.com/search')
params = MultiDict({'q': ' '.join(list(query))})
if not isinstance(category, (set, list)):
category = {category,} if category != OllamaSearchCategory.NONE else set()
for c in category:
if c != OllamaSearchCategory.NONE:
params.set('c', c.value if isinstance(c, OllamaSearchCategory) else str(c))
if order != OllamaSearchOrder.POPULAR:
params.set('o', order.value if isinstance(order, OllamaSearchOrder) else str(order))
url = url.update_query(params)
print(f"fetch(): url={url}, params={params}")
async with client_session.get(url, headers={'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36'}) as response:
#response.raise_for_status()
html = await response.text()
print(f"got: {html}")
soup = bs4.BeautifulSoup(html, 'html.parser')
listel = soup.find_all("ul", attrs={'role':'list'})[0]
results = listel.find_all('li')
for result in results:
title = result.find('h2').text.strip()
link = result.find('a')['href']
yield title, link
async def ollama_com_library_tags(name: str, client_session: Optional[aiohttp.ClientSession] = None, **kwargs):
async with ensure_client_session(client_session) as client_session:
url = yarl.URL('https://ollama.com/library/{name}/tags')
async with client_session.get(url) as response:
response.raise_for_status()
html = await response.text()
soup = bs4.BeautifulSoup(html, 'html.parser')
mainel = soup.find_all('main')
results = mainel[0].find_all('div', class_='group')
for result in results:
title = result.find('span', class_='group').text.strip()
link = result.find('a')['href']
yield title, link
@click.command()
@click.argument('query', type=str)
@click.option('--order', '-o', type=click.Choice(['popular', 'newest']), default='popular', help='Sort order')
@click.option('--category', '-c', multiple=True, required=False, type=click.Choice(['embedding', 'vision', 'tools', 'thinking']), default=[], help='Category filter')
def search(query: str, order: str, category: List[str]):
asyncio.run(async_search(query, order={v.lower():k for v, k in OllamaSearchOrder.__members__.items()}[order], category=[{v.lower():k for v,k in OllamaSearchCategory.__members__.items()}[c] for c in category]))
async def async_search(query: str, order: str, category: List[str]):
async with ensure_client_session() as client_session:
async for title, link in ollama_com_search(query, order=order, category=category, client_session=client_session):
print(title, link)
if __name__ == '__main__':
search()
aiohttp
bs4
click
yarl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment