Archived
1
0
Fork 0
This repository has been archived on 2024-12-18. You can view files and clone it, but cannot push or open issues or pull requests.
restockbot/parser_amazon.go
Julien Riou 244c9f68e7
refactor: move filters out of parser
Filters are now separate structures to include a product or not based
on their own set of properties. For now, include and exclude filters
are supported. They take a regex as an argument and include a product
if the regex matches (or doesn't match) the product name. This commit
will allow us to create new filters on product like on a price range.

Signed-off-by: Julien Riou <julien@riou.xyz>
2021-05-19 17:43:31 +02:00

133 lines
3.9 KiB
Go

package main
import (
"fmt"
"regexp"
"strings"
log "github.com/sirupsen/logrus"
paapi5 "github.com/spiegel-im-spiegel/pa-api"
"github.com/spiegel-im-spiegel/pa-api/entity"
"github.com/spiegel-im-spiegel/pa-api/query"
)
// NewAmazonServer creates an Amazon Server function based on the Marketplace.
// The paapi5 marketplaceEnum is not exported, so this type cannot be used in simple map.
func NewAmazonServer(marketplace string) *paapi5.Server {
switch marketplace {
case "www.amazon.fr":
return paapi5.New(paapi5.WithMarketplace(paapi5.LocaleFrance))
case "www.amazon.com":
return paapi5.New(paapi5.WithMarketplace(paapi5.LocaleUnitedStates))
default:
return paapi5.New() // default Marketplace
}
}
// Map of messages to detect availability
var availabilityMessages = []string{"En stock."}
// AmazonParser structure to handle Amazon parsing logic
type AmazonParser struct {
client paapi5.Client
searches []string
includeRegex *regexp.Regexp
excludeRegex *regexp.Regexp
amazonFulfilled bool
amazonMerchant bool
affiliateLinks bool
}
// NewAmazonParser to create a new AmazonParser instance
func NewAmazonParser(marketplace string, partnerTag string, accessKey string, secretKey string, searches []string, amazonFulfilled bool, amazonMerchant bool, affiliateLinks bool) *AmazonParser {
return &AmazonParser{
client: NewAmazonServer(marketplace).CreateClient(partnerTag, accessKey, secretKey),
searches: searches,
amazonFulfilled: amazonFulfilled,
amazonMerchant: amazonMerchant,
affiliateLinks: affiliateLinks,
}
}
// Parse Amazon API to return list of products
// Implements Parser interface
func (p *AmazonParser) Parse() ([]*Product, error) {
var products []*Product
for _, search := range p.searches {
log.Debugf("searching for '%s' on %s", search, p.client.Marketplace())
// create search request on API
q := query.NewSearchItems(
p.client.Marketplace(),
p.client.PartnerTag(),
p.client.PartnerType(),
).Search(query.Keywords, search).EnableItemInfo().EnableOffers()
body, err := p.client.Request(q)
if err != nil {
return nil, err
}
// decode response
res, err := entity.DecodeResponse(body)
if err != nil {
return nil, err
}
// decode products
for _, item := range res.SearchResult.Items {
product := &Product{}
if !p.affiliateLinks {
product.URL = fmt.Sprintf("https://%s/dp/%s", p.client.Marketplace(), item.ASIN)
} else {
product.URL = item.DetailPageURL // includes partner tag
}
product.Name = item.ItemInfo.Title.DisplayValue
if item.Offers != nil && *item.Offers.Listings != nil {
for _, offer := range *item.Offers.Listings {
// detect if product is packaged by Amazon
if p.amazonFulfilled && !offer.DeliveryInfo.IsAmazonFulfilled {
log.Debugf("excluding offer by '%s' for product '%s' because not fulfilled by Amazon", offer.MerchantInfo.Name, product.Name)
continue
}
// detect if product is sold by Amazon
if p.amazonMerchant && !strings.HasPrefix(offer.MerchantInfo.Name, "Amazon") {
log.Debugf("excluding offer by '%s' for product '%s' because not sold by Amazon", offer.MerchantInfo.Name, product.Name)
continue
}
// detect price
product.Price = offer.Price.Amount
product.PriceCurrency = offer.Price.Currency
// detect availability
if ContainsString(availabilityMessages, offer.Availability.Message) {
product.Available = true
break
}
}
}
products = append(products, product)
}
}
return products, nil
}
// String to print AmazonParser
// Implements the Parser interface
func (p *AmazonParser) String() string {
return fmt.Sprintf("AmazonParser<%s@%s>", p.client.PartnerTag(), p.client.Marketplace())
}
// ShopName returns shop name from Amazon Marketplace
func (p *AmazonParser) ShopName() (string, error) {
return strings.ReplaceAll(p.client.Marketplace(), "www.", ""), nil
}