1 Star 0 Fork 0

wengo / go-amazon

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
cart.go 8.99 KB
一键复制 编辑 原始数据 按行查看 历史
package amazon
import (
"fmt"
"gitee.com/wengo/go-mamba"
"github.com/PuerkitoBio/goquery"
"github.com/tidwall/gjson"
"io/ioutil"
"regexp"
"strconv"
"strings"
"time"
)
// 添加购物车
//
// document: listing页面的document
func (a *Amazon) IsAddCartSuccess(document *goquery.Document) bool {
return document.Find(".a-alert-inline-error").Length() > 0
}
// 添加购物车
//
// document: listing页面的document
func (a *Amazon) AddCart(document *goquery.Document, qty int) (resp *mamba.Response, newDocument *goquery.Document, err error) {
action, method, data, err := a.ExtractFormData(document, "#addToCart")
if err != nil {
return nil, nil, fmt.Errorf("产品页购物车 %s", err)
}
delete(data, "gift-wrap")
data["quantity"] = strconv.Itoa(qty)
resp, newDocument, err = a.Submit(action, method, nil, nil, data)
if err != nil {
return nil, nil, err
}
return
}
// 添加购物车
//
// document: offer页面的document
func (a *Amazon) AddCartByOffers(document *goquery.Document, asin, sellerId string, qty int) (quantity int64, err error) {
body, _ := document.Html()
if !strings.Contains(body, sellerId) {
return 0, fmt.Errorf("没有在 %s 没找到指定的 %s 商家", asin, sellerId)
}
var (
csrfToken string
offerListingId string
)
csrfToken, exists := document.Find("#aod-atc-csrf-token").Attr("value")
endpoint, exists := document.Find("#aod-atc-ajax-endpoint").Attr("value")
if exists {
document.Find("#aod-offer").EachWithBreak(func(i int, selection *goquery.Selection) bool {
link, _ := selection.Find("#aod-offer-soldBy a").Attr("href")
offerListingId, _ = selection.Find("span[data-action='aod-atc-action']").Attr("data-aod-atc-action")
offerListingId = gjson.Get(offerListingId, "oid").String()
if strings.Contains(link, sellerId) && strings.Contains(link, `isAmazonFulfilled=0`) {
return false
}
return true
})
}
if csrfToken != "" && offerListingId != "" {
headers := map[string]string{
"Accept": `application/vnd.com.amazon.api+json; type="cart.add-items/v1"`,
"Content-Type": `application/vnd.com.amazon.api+json; type="cart.add-items.request/v1"`,
"Referer": a.client.BaseURL,
"Accept-Language": `en-US`,
"x-api-csrf-token": csrfToken,
"Origin": a.client.BaseURL, //没有这个会400
//"Origin": `https://www.amazon.com`,//没有这个会400
"Connection": "keep-alive",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
}
body := map[string]interface{}{
"items": []map[string]interface{}{
{"asin": asin, "offerListingId": offerListingId, "quantity": qty, "additionalParameters": map[string]string{}},
},
}
var resp *mamba.Response
resp, _, err = a.json(fmt.Sprintf(`https://%s`, endpoint), headers, body)
if err != nil {
return 0, fmt.Errorf(`无法加入购物车`)
}
content := resp.String()
if gjson.Get(content, "entity.status").Int() == 400 {
var reason string
if gjson.Get(content, "entity.internalInfo.message").String() != "" {
reason = gjson.Get(content, "entity.internalInfo.message").String()
} else {
reason = gjson.Get(content, "entity.details.message").String()
}
return 0, fmt.Errorf(`加入购物车失败, 原因 = %s`, reason)
} else {
if gjson.Get(content, "entity.items.0.quantity").Int() == 0 {
ioutil.WriteFile("cart_error.html", []byte(content), 0644)
}
return gjson.Get(content, "entity.items.0.quantity").Int(), nil
}
//respResult, _ := newDocument.Html()
//matcher := regexp.MustCompile(`<body>(.+?)</body>`)
//result := matcher.FindAllStringSubmatch(respResult, -1)
//if len(result) > 0 {
// if gjson.Get(html.UnescapeString(result[0][1]), "entity.status").Int() > 0 {
// var reason string
// if gjson.Get(html.UnescapeString(result[0][1]), "entity.internalInfo.message").String() != "" {
// reason = gjson.Get(html.UnescapeString(result[0][1]), "entity.internalInfo.message").String()
// } else {
// reason = gjson.Get(html.UnescapeString(result[0][1]), "entity.details.message").String()
// }
// return false, fmt.Errorf(`加入购物车失败, 原因 = %s`, reason)
// } else {
// return isSuccess, nil
// }
//
//}
} else {
if offerListingId == "" {
return 0, fmt.Errorf("没有在 %s 下找到 %s 店铺", asin, sellerId)
} else {
return 0, fmt.Errorf("无法找到 %s 店铺的csrftoken", sellerId)
}
}
}
func (a *Amazon) CheckAddCartSuccess(document *goquery.Document) bool {
return document.Find("#sw-atc-confirmation").Length() > 0
}
// 模拟加入购物车,检查库存
//
// document: listing页面的document
func (a *Amazon) MockAddCart(document *goquery.Document, qty int) (newDocument *goquery.Document, err error) {
asin, _ := document.Find("#addToCart input[name='ASIN']").Attr("value")
sessionId, _ := document.Find("#addToCart input[name='session-id']").Attr("value")
offerListingID, _ := document.Find("#addToCart input[name='offerListingID']").Attr("value")
data := map[string]string{
"a": asin,
"colid": "",
"coliid": "",
"ctaDeviceType": "desktop",
"ctaPageType": "detail",
"customId": "",
"o": "add",
"oid": offerListingID,
"quantity": strconv.Itoa(qty),
"rcxOrdFreq": "",
"rebateId": "",
"redirectToFullPage": "1",
"snsAddressId": "",
"snsMerchantID": "",
"snsMostCommonFrequency": "",
"snsOfferListingID": "",
"snsOnmlOfferId": "",
"snsOptIn": "",
"verificationSessionID": sessionId,
"_encoding": "UTF8",
"ref_": "mw_dp_buy_crt",
"submit.add-to-cart": "Add to cart",
}
_, newDocument, err = a.Submit(`/cart`, POST, nil, data, data)
return
}
// 获取ASIN库存
//
// document: 购物车的document
func (a *Amazon) GetStock(document *goquery.Document) map[string]string {
//content := document.Find(".a-alert-content p").Text()
content, _ := document.Html()
isLimitMatcher := regexp.MustCompile(`(this seller has a limit|um limite de compra|verkoper geldt een limiet|presenta un limite di|vendedor tiene un límite de|お客様お一人あたり|Verkaufsbeschränkung|une limite de vente)`)
if isLimitMatcher.MatchString(content) {
limitMatcher := regexp.MustCompile(`(?:(?:Cart subtotal|カートの小計|Subtotal do carrinho|Subtotal del carrito|Subtotaal winkelwagen|Basket subtotal|Subtotale carrello|Subtotal de la cesta|Zwischensumme|Sous-total du panier).*?[(|(商品]|(?:than the |品は、|Anbieters von |has a limit of |um limite de compra |verkoper geldt een limiet |presenta un limite di |vendedor tiene un límite de |お客様お一人あたり ?|une limite de vente |momentan lediglich: |total de |quantità di |lediglich: |a que |de los |"cartCount":))([0-9]{1,6}) ?(?:(?:available|\. Klicken|de disponible|\. <a|per customer|por cliente|までと限定|per cliente|articles par client|disponibles|点のご|articoli disponibili|disponíveis,"freshCartCount"|)|(?:items?|itens?|articol[io]|Artikel|点|productos?|articles?|artículos?)[))])`)
result := limitMatcher.FindAllStringSubmatch(content, -1)
return map[string]string{
"status": "error",
"reason": fmt.Sprintf("%s limit", result[0][1]),
}
}
//if strings.Contains(content, "per customer") {
// return map[string]string{
// "status": "error",
// "reason": "limit",
// }
//}
matcher, _ := regexp.Compile(`than the ([\d]+) available`)
results := matcher.FindStringSubmatch(content)
if len(results) > 0 {
return map[string]string{
"status": "success",
"qty": results[1],
}
}
html, _ := document.Html()
ioutil.WriteFile("error.html", []byte(html), 0644)
return map[string]string{
"status": "error",
"reason": "unknown",
}
}
// 购物车更新数量
//
// document: 购物车的document
func (a *Amazon) UpdateQuantity(document *goquery.Document) (resp *mamba.Response, newDocument *goquery.Document, err error) {
action, _, queryData, err := a.ExtractFormData(document, "#gutterCartViewForm")
if err != nil {
return nil, nil, err
}
//queryData["cartInitiateId"] = strconv.Itoa(int(time.Now().UnixNano() / 1e6))
queryData["isToBeGiftWrapped"] = "0"
queryData["isToBeGiftWrappedBefore"] = "0"
// 开始下单
resp, newDocument, err = a.Submit(action, GET, nil, queryData, nil)
return
}
// 结账
//
// document: 购物车的document
func (a *Amazon) Checkout(document *goquery.Document) (resp *mamba.Response, newDocument *goquery.Document, err error) {
action, _, queryData, err := a.ExtractFormData(document, "#gutterCartViewForm")
if err != nil {
return nil, nil, fmt.Errorf("购物车为空, 错误提示 %s", err)
//return nil, nil, fmt.Errorf("购物车 %s", err)
}
queryData["cartInitiateId"] = strconv.Itoa(int(time.Now().UnixNano() / 1e6))
//queryData["isToBeGiftWrapped"] = "0"
queryData["isToBeGiftWrappedBefore"] = "1"
// 开始下单
resp, newDocument, err = a.Submit(action, GET, nil, queryData, nil)
return
}
1
https://gitee.com/wengo/go-amazon.git
git@gitee.com:wengo/go-amazon.git
wengo
go-amazon
go-amazon
master

搜索帮助