Adapted bot to new StarCity website
This commit is contained in:
parent
10af0ea3c8
commit
b965115cb3
3 changed files with 59 additions and 47 deletions
|
|
@ -1,21 +0,0 @@
|
||||||
package cardsinfo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFetchPriceOne(t *testing.T) {
|
|
||||||
price, _ := fetchPrice("$2.28")
|
|
||||||
assert.Equal(t, 2.28, price)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchPriceTwo(t *testing.T) {
|
|
||||||
price, _ := fetchPrice("$2.28$1.14")
|
|
||||||
assert.Equal(t, 2.28, price)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchPriceNo(t *testing.T) {
|
|
||||||
_, err := fetchPrice("")
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
package cardsinfo
|
package cardsinfo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"encoding/json"
|
||||||
"github.com/antchfx/htmlquery"
|
"github.com/antchfx/htmlquery"
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
"strconv"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Scgurl = "http://www.starcitygames.com/results?name="
|
const Scgurl = "https://www.starcitygames.com/search.php?search_query="
|
||||||
|
const Scgapi = "https://newstarcityconnector.herokuapp.com/eyApi/products/"
|
||||||
|
|
||||||
func GetSCGPrices(name string) ([]CardPrice, error) {
|
func GetSCGPrices(name string) ([]CardPrice, error) {
|
||||||
preprocessedName := preprocessNameForSearch(name)
|
preprocessedName := preprocessNameForSearch(name)
|
||||||
|
|
@ -60,20 +62,35 @@ func buildCardPrice(name, edition string, price float64, link string) CardPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPriceContainers(doc *html.Node) []*html.Node {
|
func getPriceContainers(doc *html.Node) []*html.Node {
|
||||||
nodesOdd := htmlquery.Find(doc, "//tr[contains(@class, 'deckdbbody_row')]")
|
nodes := htmlquery.Find(doc, "//tr[@class='product']")
|
||||||
nodesEven := htmlquery.Find(doc, "//tr[contains(@class, 'deckdbbody2_row')]")
|
|
||||||
nodes := append(nodesOdd, nodesEven...)
|
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchPrice(price string) (float64, error) {
|
func getItemId(item *html.Node) string {
|
||||||
split := strings.Split(price, "$")
|
return htmlquery.SelectAttr(item, "data-id")
|
||||||
if len(split) < 2 {
|
|
||||||
return 0, errors.New("not enough values")
|
|
||||||
}
|
}
|
||||||
p := split[1]
|
|
||||||
v, err := strconv.ParseFloat(p, 64)
|
func getPriceById(id string) float64 {
|
||||||
return v, err
|
path := Scgapi + id + "/variants"
|
||||||
|
resp, err := http.Get(path)
|
||||||
|
if err != nil || resp.StatusCode != http.StatusOK {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
respString, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
var scgResponse ScgResponse
|
||||||
|
err = json.Unmarshal(respString, &scgResponse)
|
||||||
|
if err != nil {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
for _, v := range scgResponse.Response.Data {
|
||||||
|
if len(v.OptionValues) > 0 && v.OptionValues[0].Label == "Near Mint" {
|
||||||
|
return v.Price
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSCGUrl(name string) string {
|
func getSCGUrl(name string) string {
|
||||||
|
|
@ -84,38 +101,37 @@ func getSCGUrl(name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseName(container *html.Node) string {
|
func parseName(container *html.Node) string {
|
||||||
nameNode := htmlquery.FindOne(container, "//td[contains(@class, 'search_results_1')]")
|
nameNode := htmlquery.FindOne(container, "//h4[@class='listItem-title']")
|
||||||
if nameNode == nil {
|
if nameNode == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
name := htmlquery.InnerText(nameNode)
|
name := htmlquery.InnerText(nameNode)
|
||||||
|
name = strings.Trim(name, "\n ")
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseEdition(container *html.Node) string {
|
func parseEdition(container *html.Node) string {
|
||||||
editionNode := htmlquery.FindOne(container, "//td[contains(@class, 'search_results_2')]")
|
editionNode := htmlquery.FindOne(container, "//span[@class='category-row-name-search']")
|
||||||
if editionNode == nil {
|
if editionNode == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
edition := strings.Trim(htmlquery.InnerText(editionNode), "\n ")
|
edition := strings.Trim(htmlquery.InnerText(editionNode), "\n ")
|
||||||
return edition
|
parts := strings.Split(edition, "/")
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
last := len(parts) - 1
|
||||||
|
return parts[last]
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePrice(container *html.Node) float64 {
|
func parsePrice(container *html.Node) float64 {
|
||||||
priceNode := htmlquery.FindOne(container, "//td[contains(@class, 'search_results_9')]")
|
id := getItemId(container)
|
||||||
if priceNode == nil {
|
price := getPriceById(id)
|
||||||
return 0.0
|
|
||||||
}
|
|
||||||
priceString := htmlquery.InnerText(priceNode)
|
|
||||||
price, err := fetchPrice(priceString)
|
|
||||||
if err != nil {
|
|
||||||
return 0.0
|
|
||||||
}
|
|
||||||
return price
|
return price
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLink(container *html.Node) string {
|
func parseLink(container *html.Node) string {
|
||||||
linkNodes := htmlquery.Find(container, "//td[contains(@class, 'search_results_1')]/b/a")
|
linkNodes := htmlquery.Find(container, "//h4[@class='listItem-title']/a")
|
||||||
if len(linkNodes) == 0 {
|
if len(linkNodes) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,3 +22,20 @@ func (c *Card) getName() string {
|
||||||
}
|
}
|
||||||
return c.Name
|
return c.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScgResponse struct {
|
||||||
|
Response ScgResponseContainer `json:"response"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScgResponseContainer struct {
|
||||||
|
Data []ScgConditionContainer `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScgConditionContainer struct {
|
||||||
|
Price float64 `json:"price"`
|
||||||
|
OptionValues []ScgCondition `json:"option_values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScgCondition struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue