package main import ( "context" "fmt" "log" "os" "strconv" "strings" "github.com/jedib0t/go-pretty/v6/table" "github.com/joho/godotenv" "github.com/kr/pretty" "github.com/xuri/excelize/v2" "googlemaps.github.io/maps" ) type Row struct { PlaceID string `xlsx:"column(PlaceID)"` Name string `xlsx:"column(Name)"` Types []string `xlsx:"column(Types)"` Address string `xlsx:"column(Address)"` Website string `xlsx:"column(Website)"` PhoneNumber string `xlsx:"column(PhoneNumber)"` GoogleMapsUrl string `xlsx:"column(GoogleMapsUrl)"` } func main() { fmt.Println("Reading ENV...") err := godotenv.Load(".env") if err != nil { log.Fatalf("Error loading .env file") } fmt.Println("Creating maps api client...") c, err := maps.NewClient(maps.WithAPIKey(os.Getenv("API_KEY"))) if err != nil { log.Fatalf("error creating maps client: %s", err) } t := table.NewWriter() t.AppendHeader(table.Row{"Name", "Address", "PhoneNumber"}) var rows []Row fmt.Println("Searching places...") foundPlaces := searchNearby(c) for _, place := range foundPlaces { details := searchDetails(c, place) r := makeRow(place, details) t.AppendRow(table.Row{r.Name, r.Address, r.PhoneNumber}) rows = append(rows, r) } fmt.Println(t.Render()) pretty.Println(len(rows)) createExcelSheet(rows) } func searchNearby(mapsClient *maps.Client) []maps.PlacesSearchResult { mileInMeters, _ := strconv.ParseUint(os.Getenv("RADIUS_IN_METERS"), 10, strconv.IntSize) Lat, _ := strconv.ParseFloat(os.Getenv("LAT"), 64) Lng, _ := strconv.ParseFloat(os.Getenv("LNG"), 64) latLon := maps.LatLng{ Lat: Lat, Lng: Lng, } var foundPlaces []maps.PlacesSearchResult var nextPageToken string = "" MAX_RESULTS, _ := strconv.Atoi(os.Getenv("MAX_RESULTS")) for next := true; next; next = (len(foundPlaces) <= MAX_RESULTS) && nextPageToken != "" { mapRequest := maps.NearbySearchRequest{ Location: &latLon, Radius: uint(mileInMeters), PageToken: nextPageToken, } searchResponse, err := mapsClient.NearbySearch(context.Background(), &mapRequest) if err != nil { log.Fatalf("error searching places: %s", err) } nextPageToken = searchResponse.NextPageToken for _, place := range searchResponse.Results { if !shouldOmitPlace(place) { foundPlaces = append(foundPlaces, place) } } } return foundPlaces } func findString(slice []string, condition func(string) bool) *string { for _, element := range slice { if condition(element) { return &element } } return nil } func shouldOmitPlace(place maps.PlacesSearchResult) bool { omitTypes := []string{"bar", "food", "restaurant", "store"} requiredTypes := []string{"establishment"} var hasOmitType bool = false var hasRequredType bool = false for _, placeType := range place.Types { foundInOmit := findString(omitTypes, func(omitType string) bool { return omitType == placeType }) if foundInOmit != nil { hasOmitType = true break } foundInRequired := findString(requiredTypes, func(requiredType string) bool { return requiredType == placeType }) if foundInRequired != nil { hasRequredType = true } } return hasOmitType || !hasRequredType } func makeRow(place maps.PlacesSearchResult, details maps.PlaceDetailsResult) Row { return Row{ PlaceID: place.PlaceID, Name: place.Name, Types: place.Types, Address: details.FormattedAddress, PhoneNumber: details.FormattedPhoneNumber, Website: details.Website, GoogleMapsUrl: details.URL, } } func searchDetails(mapsClient *maps.Client, place maps.PlacesSearchResult) maps.PlaceDetailsResult { desiredDetails := []maps.PlaceDetailsFieldMask{ "formatted_address", "formatted_phone_number", "website", "url", } detailsRequest := maps.PlaceDetailsRequest{ PlaceID: place.PlaceID, Fields: desiredDetails, } detailsResponse, err := mapsClient.PlaceDetails(context.Background(), &detailsRequest) if err != nil { log.Fatalf("error getting details for %s: %s", place.Name, err) } return detailsResponse } func createExcelSheet(rows []Row) { fmt.Println("Writing XLSX...") f := excelize.NewFile() sheetName := os.Getenv("SHEET_NAME") index, _ := f.NewSheet(sheetName) f.SetActiveSheet(index) excelHeaders := []string{"PlaceID", "Name", "Types", "Address", "Website", "PhoneNumber", "GoogleMapsUrl"} for col, header := range excelHeaders { cell := string(rune('A'+col)) + "1" f.SetCellValue(sheetName, cell, header) } for i, row := range rows { baseRow := i + 2 f.SetCellValue(sheetName, "A"+strconv.Itoa(baseRow), row.PlaceID) f.SetCellValue(sheetName, "B"+strconv.Itoa(baseRow), row.Name) f.SetCellValue(sheetName, "C"+strconv.Itoa(baseRow), strings.Join(row.Types, ",")) f.SetCellValue(sheetName, "D"+strconv.Itoa(baseRow), row.Address) f.SetCellValue(sheetName, "E"+strconv.Itoa(baseRow), row.Website) f.SetCellValue(sheetName, "F"+strconv.Itoa(baseRow), row.PhoneNumber) f.SetCellValue(sheetName, "G"+strconv.Itoa(baseRow), row.GoogleMapsUrl) } if err := f.SaveAs(sheetName + ".xlsx"); err != nil { fmt.Println(err) } else { fmt.Println("Finished") } }