package main import ( "encoding/json" "fmt" "net/http" "net/url" "strings" "time" "github.com/PuerkitoBio/goquery" ) // PerformBingImageSearch performs a Bing image search and returns the results. func PerformBingImageSearch(query, safe, lang string, page int) ([]ImageSearchResult, time.Duration, error) { startTime := time.Now() // Build the search URL searchURL := buildBingSearchURL(query, page) // Make the HTTP request resp, err := http.Get(searchURL) if err != nil { return nil, 0, fmt.Errorf("making request: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, 0, fmt.Errorf("unexpected status code: %d", resp.StatusCode) } // Parse the HTML document doc, err := goquery.NewDocumentFromReader(resp.Body) if err != nil { return nil, 0, fmt.Errorf("loading HTML document: %v", err) } // Extract data using goquery var results []ImageSearchResult doc.Find(".iusc").Each(func(i int, s *goquery.Selection) { // Extract the m parameter (JSON-encoded image metadata) metadata, exists := s.Attr("m") if !exists { return } // Parse the metadata to get the direct image URL and title var data map[string]interface{} if err := json.Unmarshal([]byte(metadata), &data); err == nil { mediaURL, ok := data["murl"].(string) if !ok { return } imgURL, ok := data["imgurl"].(string) if !ok { imgURL = mediaURL // Fallback to mediaURL if imgurl is not available } // Use imgURL as the direct image URL directImageURL := imgURL // Extract title from the metadata title, _ := data["t"].(string) // Extract dimensions if available width := 0 height := 0 if ow, ok := data["ow"].(float64); ok { width = int(ow) } if oh, ok := data["oh"].(float64); ok { height = int(oh) } // Extract thumbnail URL from the 'turl' field thumbURL, _ := data["turl"].(string) if thumbURL == "" { // As a fallback, try to get it from the 'src' or 'data-src' attributes imgTag := s.Find("img") thumbURL, exists = imgTag.Attr("src") if !exists { thumbURL, _ = imgTag.Attr("data-src") } } results = append(results, ImageSearchResult{ Thumb: thumbURL, Title: strings.TrimSpace(title), Full: directImageURL, Source: mediaURL, Width: width, Height: height, }) } }) duration := time.Since(startTime) // Check if the number of results is zero if len(results) == 0 { return nil, duration, fmt.Errorf("no images found") } return results, duration, nil } // buildBingSearchURL constructs the search URL for Bing Image Search func buildBingSearchURL(query string, page int) string { baseURL := "https://www.bing.com/images/search" params := url.Values{} params.Add("q", query) params.Add("first", fmt.Sprintf("%d", (page-1)*35+1)) // Pagination, but increasing it doesn't seem to make a difference params.Add("count", "35") params.Add("form", "HDRSC2") return baseURL + "?" + params.Encode() } // Example usage in main (commented out for clarity) // func main() { // results, duration, err := PerformBingImageSearch("kittens", "false", "en", 1) // if err != nil { // fmt.Println("Error:", err) // return // } // fmt.Printf("Search took: %v\n", duration) // fmt.Printf("Total results: %d\n", len(results)) // for _, result := range results { // fmt.Printf("Title: %s\nThumbnail: %s\nWidth: %d\nHeight: %d\nThumbProxy: %s\nSource (Original Image URL): %s\n\n", // result.Title, result.Thumbnail, result.Width, result.Height, result.ThumbProxy, result.Source) // } // }