package main import ( "fmt" "log" "math/rand" "net/http" "net/url" "strconv" "strings" "time" "html/template" "github.com/PuerkitoBio/goquery" ) var funcs = template.FuncMap{ "title": func(s string) string { return strings.Title(s) }, "url_for": func(filename string) string { return "/" + filename }, } var templates = template.Must(template.New("").Funcs(funcs).ParseFiles("templates/results.html")) func main() { http.HandleFunc("/", handleSearch) http.HandleFunc("/search", handleSearch) fmt.Println("Server is listening on http://localhost:5000") log.Fatal(http.ListenAndServe(":5000", nil)) } func handleSearch(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { http.ServeFile(w, r, "static/search.html") return } query := r.FormValue("q") if query == "" { http.ServeFile(w, r, "static/search.html") return } // Random user agent userAgents := []string{ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15", } randIndex := rand.Intn(len(userAgents)) userAgent := userAgents[randIndex] // Time start := time.Now() // Search query searchURL := "https://www.google.com/search?q=" + url.QueryEscape(query) req, err := http.NewRequest("GET", searchURL, nil) if err != nil { http.Error(w, "Failed to create request", http.StatusInternalServerError) return } req.Header.Set("User-Agent", userAgent) resp, err := http.DefaultClient.Do(req) if err != nil { http.Error(w, "Failed to fetch search results", http.StatusInternalServerError) return } defer resp.Body.Close() // Parse HTML doc, err := goquery.NewDocumentFromReader(resp.Body) if err != nil { http.Error(w, "Failed to parse HTML", http.StatusInternalServerError) return } // Retrieve links var results [][]string doc.Find(".yuRUbf").Each(func(i int, s *goquery.Selection) { link := s.Find("a") href, _ := link.Attr("href") title := link.Text() results = append(results, []string{href, title}) }) // Retrieve description var descriptions []string doc.Find(".VwiC3b").Each(func(i int, s *goquery.Selection) { desc := s.Text() descriptions = append(descriptions, desc) }) // Retrieve kno-rdesc kno := "" knoLink := "" rdesc := doc.Find(".kno-rdesc") if rdesc.Length() > 0 { span := rdesc.Find("span") kno = span.Text() descLink := rdesc.Find("a") knoLink, _ = descLink.Attr("href") } // Retrieve featured snippet snip := "" snipSpan := doc.Find(".hgKElc") if snipSpan.Length() > 0 { snip = snipSpan.Text() } elapsed := time.Since(start) // Render template data := struct { Results [][]string Title string Query string Fetched string Snippet string KnoRdesc string RdescLink string ElapsedTime string }{ Results: results, Title: query + " - TailsGo", Query: query, Fetched: fmt.Sprintf("Fetched the results in %.2f seconds", elapsed.Seconds()), Snippet: snip, KnoRdesc: kno, RdescLink: knoLink, ElapsedTime: strconv.FormatFloat(elapsed.Seconds(), 'f', 2, 64), } err = templates.ExecuteTemplate(w, "results.html", data) if err != nil { http.Error(w, "Failed to render template", http.StatusInternalServerError) return } }