We will learn today how to implement a bot blocker using user-agents.
1. Install the library
pip install user-agents
2. Creating the decorator file
# dependencies/bot_detection.py import functools from fastapi import Request, HTTPException from user_agents import parse def block_bots(func): @functools.wraps(func) async def wrapper(request: Request, *args, **kwargs): ua_string = request.headers.get("user-agent", "") ua = parse(ua_string) if ua.is_bot: raise HTTPException(status_code=403, detail="Access denied.") return await func(request, *args, **kwargs) return wrapper
3. Importing and using it in your router
from dependencies.bot_detection import block_bots @limiter.limit("5/minute") @amazon.get("/mi_endpoint", response_model=str, status_code=status.HTTP_200_OK) @block_bots async def endpoint( request: Request, busqueda: str = Query(..., description="Search term"), limit: int = Query(1, description="Number of results to get") ) -> str: logger.info(f"Searching for {busqueda}") ...
4. Testing it works
You can test quickly from the terminal:
# Normal request — must pass ✔️ curl -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36" \ http://localhost:8000/mi_endpoint?busqueda=1234567890 # Bot request — must return 403 ❌ curl -H "User-Agent: Googlebot/2.1" \ http://localhost:8000/mi_endpoint?busqueda=1234567890
5. Optional — log blocked users
If you want to see in your log who is being blocked:
def block_bots(func): @functools.wraps(func) async def wrapper(request: Request, *args, **kwargs): ua_string = request.headers.get("user-agent", "") ua = parse(ua_string) if ua.is_bot: logger.warning(f"Bot blocked - IP: {request.client.host} UA: {ua_string}") raise HTTPException(status_code=403, detail="Access denied.") return await func(request, *args, **kwargs) return wrapper
To use it: always add:
request: Request,
In the function’s route parameters.
