Search/images-bing.go
2024-08-21 12:30:03 +02:00

115 lines
3 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
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 image source
imgTag := s.Find("img")
imgSrc, exists := imgTag.Attr("src")
if !exists {
imgSrc, exists = imgTag.Attr("data-src")
if !exists {
return
}
}
// Extract the image title from `alt` attribute
title := imgTag.AttrOr("alt", "")
// Extract width and height if available
width, _ := strconv.Atoi(imgTag.AttrOr("width", "0"))
height, _ := strconv.Atoi(imgTag.AttrOr("height", "0"))
// Extract the m parameter (JSON-encoded image metadata)
metadata, exists := s.Attr("m")
if !exists {
return
}
// Parse the metadata to get the media URL (the original image source)
var data map[string]interface{}
if err := json.Unmarshal([]byte(metadata), &data); err == nil {
mediaURL, ok := data["murl"].(string)
if ok {
results = append(results, ImageSearchResult{
Thumbnail: imgSrc,
Title: strings.TrimSpace(title),
Media: mediaURL,
Width: width,
Height: height,
Source: mediaURL,
ThumbProxy: imgSrc,
})
}
}
})
duration := time.Since(startTime)
// Check if the number of results is one or less
if len(results) == 0 {
return nil, duration, fmt.Errorf("no images found")
}
return results, duration, nil
}
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()
}
// 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)
// }
// }