Sponsored Links
ZIPLOOT TECHNICAL GUIDE

Build a 100% Free Web Search REST API (SerpAPI Alternative)

Build a 100% Free Web Search REST API (SerpAPI Alternative)

Technical Summary

Building AI agents, RAG pipelines, or web scrapers often requires real-time web search. Commercial providers like SerpAPI or Google Custom Search charge steep monthly fees or cap free tiers at 100 requests. In this guide, we engineer a 100% free, self-hosted Web Search REST API Gateway that extracts structured JSON search results (Title, Clean Direct URL, Snippet) with zero third-party dependencies. 💬 FAQs & Solutions ↓

Why Commercial Search Engine APIs Fail Developers

  • SerpAPI & Serper.dev — Charge $50 to $250/month with strict monthly credit limits
  • Google Custom Search API — Capped at 100 queries/day; charges $5 per 1,000 requests after
  • Bing Web Search API — Requires Microsoft Azure billing with complex subscription tiers
  • Rate Limit Roadblocks — Rapid automated queries trigger 429 Too Many Requests errors
Free Web Search REST API Architecture Gateway — ZipLoot Guide

High-concurrency zero-cost search parsing engine gateway with JSON response normalization.

Gateway Architecture & DOM Parsing Strategy

Our custom gateway acts as an intermediate HTTP server that receives query requests, fetches raw search results asynchronously, strips redirect tracking parameters (such as DuckDuckGo's uddg= wrapper), sanitizes HTML entities, and formats the output into standard JSON.

1. Python Standard Library Implementation (Zero Dependencies)

Below is the complete standalone Python REST API server code. It requires no pip install or third-party libraries—it runs natively using Python's built-in urllib and http.server modules.

import urllib.request

import urllib.parse

import json

import re

import html

import sys

from http.server import HTTPServer, BaseHTTPRequestHandler



def free_web_search(query, max_results=10):

 url = "https://html.duckduckgo.com/html/"

 

 data = urllib.parse.urlencode({'q': query}).encode('utf-8')

 headers = {

 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",

 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",

 "Accept-Language": "en-US,en;q=0.9",

 "Content-Type": "application/x-www-form-urlencoded",

 "Origin": "https://html.duckduckgo.com",

 "Referer": "https://html.duckduckgo.com/"

 }

 

 req = urllib.request.Request(url, data=data, headers=headers, method="POST")

 

 try:

 with urllib.request.urlopen(req, timeout=10) as response:

 raw_html = response.read().decode('utf-8', errors='ignore')

 

 results = []

 links = re.findall(r'<a[^>]*class="result__a"[^>]*href="([^"]+)"[^>]*>(.*?)</a>', raw_html, re.DOTALL)

 snippets = re.findall(r'<a[^>]*class="result__snippet"[^>]*>(.*?)</a>|<td[^>]*class="result__snippet"[^>]*>(.*?)</td>', raw_html, re.DOTALL)

 

 for i, (raw_url, raw_title) in enumerate(links):

 if i >= max_results:

 break

 

 title = html.unescape(re.sub(r'<[^>]+>', '', raw_title)).strip()

 

 snippet_text = ""

 if i < len(snippets):

 snip_tuple = snippets[i]

 raw_snip = snip_tuple[0] or snip_tuple[1] or ""

 snippet_text = html.unescape(re.sub(r'<[^>]+>', '', raw_snip)).strip()

 

 clean_url = raw_url

 if "uddg=" in raw_url:

 try:

 clean_url = urllib.parse.unquote(raw_url.split("uddg=")[1].split("&")[0])

 except Exception:

 clean_url = raw_url

 

 if title and clean_url:

 results.append({

 "title": title,

 "url": clean_url,

 "snippet": snippet_text

 })

 

 return {

 "status": "success",

 "provider": "ZipLoot Free Search Gateway Engine",

 "query": query,

 "count": len(results),

 "results": results

 }

 

 except Exception as e:

 return {"status": "error", "message": str(e)}



class SimpleSearchHandler(BaseHTTPRequestHandler):

 def do_GET(self):

 parsed_path = urllib.parse.urlparse(self.path)

 params = urllib.parse.parse_qs(parsed_path.query)

 

 if parsed_path.path in ["/search", "/api/search"]:

 query = params.get("q", [""])[0]

 if not query:

 self.send_response(400)

 self.send_header("Content-Type", "application/json; charset=utf-8")

 self.end_headers()

 self.wfile.write(json.dumps({"error": "Missing 'q' query parameter"}, indent=2).encode('utf-8'))

 return

 

 res = free_web_search(query)

 self.send_response(200)

 self.send_header("Content-Type", "application/json; charset=utf-8")

 self.send_header("Access-Control-Allow-Origin", "*")

 self.end_headers()

 self.wfile.write(json.dumps(res, indent=2, ensure_ascii=False).encode('utf-8'))

 else:

 self.send_response(200)

 self.send_header("Content-Type", "text/html; charset=utf-8")

 self.end_headers()

 self.wfile.write(b"<h1>ZipLoot Free Web Search API</h1><p>Use /api/search?q=query</p>")



if __name__ == "__main__":

 port = 8000

 print(f"Starting Free Search REST API Server at http://localhost:{port}...")

 server = HTTPServer(('0.0.0.0', port), SimpleSearchHandler)

 server.serve_forever()

2. Sample JSON Output Response

When executing a GET request to http://localhost:8000/api/search?q=deepseek+r1+api, your server returns structured JSON instantaneously:

{

 "status": "success",

 "provider": "ZipLoot Free Search Gateway Engine",

 "query": "deepseek r1 api",

 "count": 10,

 "results": [

 {

 "title": "DeepSeek-R1 Release | DeepSeek API Docs",

 "url": "https://api-docs.deepseek.com/news/news250120/",

 "snippet": "License Update! DeepSeek-R1 is now MIT licensed for clear open access..."

 },

 {

 "title": "Your First API Call | DeepSeek API Docs",

 "url": "https://api-docs.deepseek.com/",

 "snippet": "Your First API Call The DeepSeek API uses an API format compatible with OpenAI/Anthropic..."

 }

 ]

}

3. Live Local Interactive UI Test

Below is the live execution screenshot of the ZipLoot Free Web Search API dashboard running locally at http://localhost:8000 for the search query "deepseek r1 api":

ZipLoot Free Web Search API Live Local Execution UI Screenshot

Figure 2: Real-time UI dashboard execution output for 'deepseek r1 api' query returning structured JSON search results.

Frequently Asked Questions (FAQs)

Is an API key required to use this gateway?

No. The gateway parses raw HTTP endpoints directly and does not require registration or API keys.

Can this be deployed to free hosting services like Serv00 or Alwaysdata?

Yes. Because it uses pure Python standard library modules with low RAM overhead, it runs seamlessly on Serv00, Alwaysdata, or Cloudflare Workers.

Engineering Verdict

By using a custom DOM sanitizer and parsing gateway, developers eliminate monthly API costs like SerpAPI completely, unlocking unlimited real-time search data for AI agents and scrapers.


Disclaimer: This article is strictly for educational and technical research purposes. Always respect target website robots.txt and rate limits.