윤준석

ADD: bunjang api server model, service

1 +module bunjang
2 +
3 +go 1.17
4 +
5 +require (
6 + github.com/PuerkitoBio/goquery v1.8.0 // indirect
7 + github.com/andybalholm/cascadia v1.3.1 // indirect
8 + github.com/go-rod/rod v0.106.8 // indirect
9 + github.com/labstack/echo/v4 v4.7.2 // indirect
10 + github.com/labstack/gommon v0.3.1 // indirect
11 + github.com/mattn/go-colorable v0.1.11 // indirect
12 + github.com/mattn/go-isatty v0.0.14 // indirect
13 + github.com/valyala/bytebufferpool v1.0.0 // indirect
14 + github.com/valyala/fasttemplate v1.2.1 // indirect
15 + github.com/ysmood/goob v0.4.0 // indirect
16 + github.com/ysmood/gson v0.7.1 // indirect
17 + github.com/ysmood/leakless v0.7.0 // indirect
18 + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
19 + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
20 + golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
21 + golang.org/x/text v0.3.7 // indirect
22 +)
1 +github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
2 +github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
3 +github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
4 +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
5 +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7 +github.com/go-rod/rod v0.106.8 h1:pVMVz0jMtLVyx8FhJEEA6l+EY9Iw/nJTDYT/he4+UJc=
8 +github.com/go-rod/rod v0.106.8/go.mod h1:xkZOchuKqTOkMOBkrzb7uJpbKZRab1haPCWDvuZkS2U=
9 +github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
10 +github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
11 +github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
12 +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
13 +github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
14 +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
15 +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
16 +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
17 +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
18 +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
19 +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
20 +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
21 +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
22 +github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
23 +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
24 +github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
25 +github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
26 +github.com/ysmood/got v0.29.1/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
27 +github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
28 +github.com/ysmood/gson v0.7.1 h1:zKL2MTGtynxdBdlZjyGsvEOZ7dkxaY5TH6QhAbTgz0Q=
29 +github.com/ysmood/gson v0.7.1/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
30 +github.com/ysmood/leakless v0.7.0 h1:XCGdaPExyoreoQd+H5qgxM3ReNbSPFsEXpSKwbXbwQw=
31 +github.com/ysmood/leakless v0.7.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
32 +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
33 +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
34 +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
35 +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
36 +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
37 +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
38 +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
39 +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
40 +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
41 +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
42 +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
43 +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
44 +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
45 +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
46 +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
47 +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
48 +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
49 +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
50 +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
1 +package main
2 +
3 +import (
4 + "github.com/labstack/echo/v4"
5 +)
6 +
7 +func main() {
8 + e := echo.New()
9 +
10 + e.Logger.Fatal(e.Start(":8080"))
11 +}
1 +package model
2 +
3 +type ApiResponse struct {
4 + Result string `json:"result"`
5 + NoResult bool `json:"no_result"`
6 + Items []ApiResponseItem `json:"list"`
7 +}
8 +
9 +type ApiResponseItem struct {
10 + Name string `json:"name"`
11 + Pid string `json:"pid"`
12 + Price string `json:"price"`
13 + ProductImage string `json:"product_image"`
14 +}
1 +package model
2 +
3 +type Item struct {
4 + Platform string `json:"platform"`
5 + Name string `json:"name"`
6 + Price int `json:"price"`
7 + ThumbnailUrl string `json:"thumbnailUrl"`
8 + ItemUrl string `json:"itemUrl"`
9 + ExtraInfo string `json:"extraInfo"`
10 +}
1 +package service
2 +
3 +import (
4 + "bunjang/model"
5 + "encoding/json"
6 + "fmt"
7 + "io"
8 + "io/ioutil"
9 + "log"
10 + "net/http"
11 + "net/url"
12 + "strconv"
13 + "strings"
14 +)
15 +
16 +func GetItemByKeyword(keyword string) ([]model.Item, error) {
17 + var items []model.Item
18 +
19 + responseItems, err := getApiResponseItems(keyword)
20 + if err != nil {
21 + return nil, err
22 + }
23 +
24 + for _, responseItem := range responseItems {
25 + extraInfo, err := getItemExtraInfo(responseItem.Pid)
26 + if err != nil {
27 + return nil, err
28 + }
29 + item := model.Item{
30 + Platform: "번개장터",
31 + Name: responseItem.Name,
32 + Price: priceStringToInt(responseItem.Price),
33 + ThumbnailUrl: responseItem.ProductImage,
34 + ItemUrl: "https://m.bunjang.co.kr/products/" + responseItem.Pid,
35 + ExtraInfo: extraInfo,
36 + }
37 +
38 + items = append(items, item)
39 + }
40 +
41 + return items, nil
42 +}
43 +
44 +func getApiResponseItems(keyword string) ([]model.ApiResponseItem, error) {
45 + encText := url.QueryEscape(keyword)
46 + apiUrl := fmt.Sprintf("https://api.bunjang.co.kr/api/1/find_v2.json?q=%s&order=score", encText)
47 +
48 + response, err := getResponse(apiUrl)
49 + if err != nil {
50 + return nil, err
51 + }
52 +
53 + var apiResponse model.ApiResponse
54 + err = json.Unmarshal(response, &apiResponse)
55 + if err != nil {
56 + return nil, err
57 + }
58 +
59 + return apiResponse.Items, nil
60 +}
61 +
62 +func getItemExtraInfo(pid string) (string, error) {
63 + apiUrl := fmt.Sprintf("https://api.bunjang.co.kr/api/1/product/%s/detail_info.json", pid)
64 +
65 + response, err := getResponse(apiUrl)
66 + if err != nil {
67 + return "", err
68 + }
69 +
70 + var itemInfo map[string]interface{}
71 + err = json.Unmarshal(response, &itemInfo)
72 + if err != nil {
73 + return "", err
74 + }
75 +
76 + extraInfo := itemInfo["item_info"].(map[string]interface{})["description_for_detail"].(string)
77 +
78 + return extraInfo, nil
79 +}
80 +
81 +func getResponse(url string) ([]byte, error) {
82 + req, err := http.NewRequest("GET", url, nil)
83 + if err != nil {
84 + return nil, err
85 + }
86 +
87 + client := &http.Client{}
88 + resp, err := client.Do(req)
89 + if err != nil {
90 + return nil, err
91 + }
92 +
93 + defer func(Body io.ReadCloser) {
94 + err := Body.Close()
95 + if err != nil {
96 + log.Fatal(err)
97 + }
98 + }(resp.Body)
99 +
100 + response, _ := ioutil.ReadAll(resp.Body)
101 +
102 + return response, nil
103 +}
104 +
105 +func priceStringToInt(priceString string) int {
106 + strings.TrimSpace(priceString)
107 +
108 + if priceString == "" {
109 + return 0
110 + }
111 +
112 + priceString = strings.ReplaceAll(priceString, "원", "")
113 + priceString = strings.ReplaceAll(priceString, ",", "")
114 +
115 + price, err := strconv.Atoi(priceString)
116 + if err != nil {
117 + log.Fatal(err)
118 + }
119 + return price
120 +}