dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Web search and page-content extraction for Go — no API key, no SDK, no account.
gosearch queries real search engines (DuckDuckGo, Bing, Google, Yandex) by
fetching their public HTML result pages and parsing them directly, and
extracts the readable main content of any URL. It is built for local-first
programs — LLM agents, CLI tools, self-hosted services — that cannot or will
not depend on a hosted search API.
results, _ := gosearch.Search(ctx, "golang html parser", gosearch.DuckDuckGo)
page, _ := gosearch.Fetch(ctx, results[0].URL,
gosearch.WithMarkdown(), // headings, lists, links, code fences preserved
)
fmt.Println(page.Content) // ready to feed an LLM
gosearch/browser)Most "web search for my agent/tool" solutions assume you'll pay for and depend
on a hosted search API (SerpAPI, Google Custom Search, Bing Search API…).
That is a real dependency: an account, a key, a bill, a third party on your
critical path. Projects built to run fully locally need none of those things
— so gosearch talks to the engines' own public result pages directly, the
same way a web browser would, and parses what comes back.
The core module's entire third-party dependency surface is
golang.org/x/net/html. That is
a deliberate architectural bet: you can drop this into almost any Go program
without dragging in an SDK.
Search(ctx, query, engine, ...Option) call returning structured
[]Result{Title, URL, Snippet}.Fetch(ctx, url, ...Option) returns a
page's main content with navigation, ads, scripts, and boilerplate removed
— never raw HTML.WithMarkdown() renders extracted content as
GitHub-flavored Markdown: headings, lists, tables, fenced code, links, and
emphasis survive. Built for LLM context, where structure carries meaning.WithFallback(...) moves to the next engine
only when the current one reports being blocked or challenged, instead of
failing outright.ErrBlocked, ErrChallenge) via errors.Is, never as a
silent empty result or a parse panic on a captcha page.İ/I, reordered parameters);
these collapse into one result, original spelling preserved.WithDates() fills Result.Date from each
engine's own metadata when provided; off by default so timeless use cases
are never polluted by accident.WithBlockedDomains(...) /
WithAllowedDomains(...) enforce your spam and quality rules on the
result list. The library judges no site on its own.Requirements: Go 1.25+. No keys, no accounts, no config files.
go get github.com/BugraAkdemir/gosearch@latest
package main
import (
"context"
"fmt"
"log"
"github.com/BugraAkdemir/gosearch"
)
func main() {
ctx := context.Background()
// Search (DuckDuckGo is the most reliable default).
results, err := gosearch.Search(ctx, "facebook", gosearch.DuckDuckGo,
gosearch.WithMaxResults(5),
)
if err != nil {
log.Fatal(err)
}
for _, r := range results {
fmt.Println(r.Title, "->", r.URL)
}
// Extract any page's readable content.
page, err := gosearch.Fetch(ctx, "https://en.wikipedia.org/wiki/Facebook")
if err != nil {
log.Fatal(err)
}
fmt.Println(page.Title)
fmt.Println(page.Content)
}
If the primary engine blocks or challenges the request, the same query continues down the chain automatically. First success wins.
results, err := gosearch.Search(ctx, "facebook", gosearch.Google,
gosearch.WithFallback(gosearch.Bing, gosearch.DuckDuckGo),
)
page, err := gosearch.Fetch(ctx, url, gosearch.WithMarkdown())
// page.Content now contains "# Heading", "- list items", "[links](…)", "```code```"
The two calls compose into the standard retrieval flow:
// 1. Find candidate sources.
results, err := gosearch.Search(ctx, question, gosearch.DuckDuckGo,
gosearch.WithFallback(gosearch.Bing),
gosearch.WithMaxResults(5),
gosearch.WithBlockedDomains("pinterest.com"), // your quality policy
)
// 2. Read the top hits as Markdown context.
var context strings.Builder
for _, r := range results[:min(3, len(results))] {
page, err := gosearch.Fetch(ctx, r.URL, gosearch.WithMarkdown())
if err != nil {
continue // one unreadable source ≠ abort
}
fmt.Fprintf(&context, "## %s\n%s\n\n", page.Title, page.Content)
}
// context.String() → model input
results, _ := gosearch.Search(ctx, q, gosearch.Bing,
gosearch.WithDates(), // Result.Date: "1 day ago", "2026-08-20", …
)
Full option semantics: docs/API.md. Task-oriented
copy-paste recipes: docs/RECIPES.md.
Anti-bot strictness differs per engine and per network — IP reputation is often the deciding factor, not client behavior. Rough expectations from a normal residential connection, based on live testing of this library:
| Engine | Expected reliability | Notes |
|---|---|---|
| DuckDuckGo | Highest | Official no-JS HTML endpoint; parser validated against a real captured page. |
| Bing | High | Served clean organic results even to a flagged datacenter IP; titles arrive behind a click-tracker unwrapped best-effort. |
| Moderate | No official no-JS endpoint; DOM changes without notice. | |
| Yandex | Lowest | Aggressive geo/IP-based captcha gating, especially outside Russia. |
"Best-effort heuristic" status: the DuckDuckGo parser is validated against a real captured response; the other three parsers match current observed markup and are tested against synthetic fixtures, but engines rotate their DOM without notice — treat a parse miss as a signal to capture fresh HTML, not necessarily a bug.
One variadic ...Option applies to both Search and Fetch; scope notes
below. Full table with semantics: docs/API.md.
| Option | Scope | Purpose |
|---|---|---|
WithTimeout(d) | both | Request deadline (default 15s) |
WithMaxResults(n) | Search | Cap result count |
WithFallback(engines...) | Search | Ordered block/challenge fallback |
WithDates() | Search | Populate Result.Date (default off) |
WithBlockedDomains(ds...) / WithAllowedDomains(ds...) | Search | Your domain policy |
WithRetries(n) | both | Transient-failure retries (default 2, 0 disables) |
WithProxy(rawURL) | both | Route through your own egress |
WithCookies(cs...) | both | Seed session cookies |
WithHeader(k, v) / WithUserAgent(ua) | both | Override request headers |
WithHTTPClient(c) | both | Bring your own *http.Client (escape hatch) |
WithMarkdown() | Fetch | Markdown instead of plain-text content |
Search engines run anti-bot systems. A 200 OK does not mean success —
engines serve captcha/challenge pages with status 200, which is why every
response passes through block detection before parsing, and why failures are
typed errors rather than empty slices. From datacenter/cloud IPs every engine
may challenge or block you regardless of politeness; residential networks
fare far better. When every engine in a fallback chain refuses you, Search
returns an errors.Join of each engine's error so you can see exactly what
happened.
This library behaves like an ordinary visitor — and stops there. It will never solve CAPTCHAs, execute JS challenges to disguise itself, mask automation flags, or rotate identities to defeat a security control. Those cross from "look like a normal visitor" into "defeat a security control," which is out of scope on principle, not merely as a technical limitation.
gosearch/browser)For pages whose content only exists after JavaScript runs — which defeats
plain-HTTP Fetch() by definition — an opt-in separate Go module drives
a real, unmodified Chromium-family browser:
chrome-headless-shell with explicit permission; or embeds the
engine at compile time via -tags gosearch_embed_engine.Because it lives in its own module, go get github.com/BugraAkdemir/gosearch
never pulls browser dependencies into your project. See
browser/README.md for installation and trade-offs.
Releases follow semantic versioning as annotated
vX.Y.Z tags; the module proxy distributes them automatically. During
v0.x, the public API may still evolve between minor versions — pin an exact
version if that matters to you. The browser/ directory is a separate Go
module with its own prefixed tags (browser/vX.Y.Z).
| Document | Contents |
|---|---|
| gosearch.bugradev.com | Project website — docs, release notes, and engine status, synced live from this repository |
docs/GETTING_STARTED.md | From zero to first search and first extraction |
docs/RECIPES.md | Copy-paste solutions: fallback chains, error handling, LLM pipelines, batch searching, the browser engine, troubleshooting |
docs/API.md | Human-readable reference for every function, type, option, and error (go doc -all . remains the source of truth) |
docs/ARCHITECTURE.md | Package graph, request flow, provider status, and the reasoning behind the internal/ split |
See CONTRIBUTING.md. Development conventions,
verification commands, and known pitfalls live in
AGENTS.md; the phased roadmap and exit criteria live in
plan.md.