-
Notifications
You must be signed in to change notification settings - Fork 1
/
gamestop-handler.go
144 lines (115 loc) · 3.3 KB
/
gamestop-handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/PuerkitoBio/goquery"
)
type Monitor interface {
Collect(ctx context.Context, url string) (int, error)
Evaluate(ctx context.Context) ([]Message, error)
}
type GamestopHandler struct {
Name string
Products []Products
Message []Message
alreadyPingedProducts map[string]bool
}
func NewGamestopHandler(name string) (Monitor, error) {
return &GamestopHandler{
Name: name,
Products: []Products{},
Message: []Message{},
alreadyPingedProducts: make(map[string]bool),
}, nil
}
type Products struct {
ID string
Title string
ImageUrl string
Link string
Series string
Price string
Availability bool
}
func getHtml(url string) *http.Response {
res, err := http.Get(url)
if err != nil {
fmt.Printf("Error: %v", err)
return nil
}
if res.StatusCode > 400 {
fmt.Printf("Status code: %v \n", res.StatusCode)
}
return res
}
type DataProductAttribute struct {
Id string
Name string
Price string
Brand string
}
func (g *GamestopHandler) scrapePageData(doc *goquery.Document) (p []Products) {
doc.Find("div.prodList>div.searchTileLayout").Each(func(index int, item *goquery.Selection) {
dataProductAttribute, _ := item.Attr("data-product")
var dataProductInstances []DataProductAttribute
err := json.Unmarshal([]byte(dataProductAttribute), &dataProductInstances)
if err != nil {
fmt.Println(fmt.Sprintf("failed to unmarshall json into go struct: %s", err.Error()))
return
}
dataProductInstance := dataProductInstances[0]
link, _ := item.Find("div.searchTilePriceDesktop>h3.desktopSearchProductTitle>a").Attr("href")
series := item.Find("div.searchTilePriceDesktop>h4.platLogo").Text()
imageUrl, _ := item.Find("div.searchProductImage").First().Find("img").First().Attr("data-llsrc")
availability := item.Find("button").HasClass("SPTenabled")
p = append(p, Products{
ID: dataProductInstance.Id,
Title: dataProductInstance.Name,
Link: "https://www.gamestop.de" + link,
ImageUrl: imageUrl,
Series: series,
Price: dataProductInstance.Price,
Availability: availability,
})
})
return p
}
func (g *GamestopHandler) Collect(ctx context.Context, url string) (int, error) {
// fetch data. return statuscode or error
response := getHtml(url)
defer response.Body.Close()
doc, err := goquery.NewDocumentFromReader(response.Body)
if err != nil {
fmt.Printf("Error: %v", err)
return 0, err
}
data := g.scrapePageData(doc)
g.Products = data
return response.StatusCode, nil
}
func (g *GamestopHandler) Evaluate(ctx context.Context) (m []Message, err error) {
// evaluate data. return list of messages or error
for _, p := range g.Products {
isProductAvailable := p.Availability
if !isProductAvailable {
if g.alreadyPingedProducts[p.ID] {
g.alreadyPingedProducts[p.ID] = false
}
continue
}
if g.alreadyPingedProducts[p.ID] == true {
fmt.Println(fmt.Sprintf("skipping product %s - was already pinged", p.ID))
continue
}
m = append(m, Message{
ID: p.ID,
Name: p.Title,
Price: p.Price,
ImageUrl: p.Link,
})
g.alreadyPingedProducts[p.ID] = true
}
return m, nil
}