유명현

Merge branch 'main' into feature/line_bot

1 +FROM golang:1.17.3-alpine AS builder
2 +
3 +WORKDIR /src
4 +COPY . /src
5 +
6 +RUN go build -o bunjang_api_server
7 +
8 +FROM alpine
9 +
10 +WORKDIR /src
11 +COPY --from=builder /src/bunjang_api_server /src/bunjang_api_server
12 +
13 +EXPOSE 8080
14 +CMD ["./bunjang_api_server"]
1 +package controller
2 +
3 +import (
4 + "bunjang/service"
5 + "net/http"
6 +
7 + "github.com/labstack/echo/v4"
8 +)
9 +
10 +func Search(c echo.Context) error {
11 + keyword := c.Param("keyword")
12 + items, err := service.GetItemByKeyword(keyword)
13 + if err != nil {
14 + return err
15 + }
16 + return c.JSON(http.StatusOK, items)
17 +}
1 +#!/usr/bin/env bash
2 +
3 +docker build -t bunjang-api-server .
4 +docker-compose up -d
...\ No newline at end of file ...\ No newline at end of file
1 +version: '3'
2 +
3 +services:
4 + joongna_api:
5 + image: bunjang-api-server
6 + restart: always
7 + container_name: bunjang-api-server-container
8 + ports:
9 + - '18082:8080'
...\ No newline at end of file ...\ No newline at end of file
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 + "bunjang/router"
5 +
6 + "github.com/labstack/echo/v4"
7 +)
8 +
9 +func main() {
10 + e := echo.New()
11 +
12 + router.Init(e)
13 +
14 + e.Logger.Fatal(e.Start(":8080"))
15 +}
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 router
2 +
3 +import (
4 + "bunjang/controller"
5 +
6 + "github.com/labstack/echo/v4"
7 +)
8 +
9 +const (
10 + API = "/api/v2"
11 + APIBunJang = API + "/bunjang"
12 + APIKeyword = APIBunJang + "/:keyword"
13 +)
14 +
15 +func Init(e *echo.Echo) {
16 + e.GET(APIKeyword, controller.Search)
17 +}
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 + "sync"
15 +)
16 +
17 +func GetItemByKeyword(keyword string) ([]model.Item, error) {
18 + var items []model.Item
19 + wg := sync.WaitGroup{}
20 +
21 + responseItems, err := getApiResponseItems(keyword)
22 + if err != nil {
23 + return nil, err
24 + }
25 +
26 + for _, responseItem := range responseItems {
27 + wg.Add(1)
28 +
29 + go func(responseItem model.ApiResponseItem) {
30 + defer wg.Done()
31 + extraInfo, err := getItemExtraInfo(responseItem.Pid)
32 + if err != nil {
33 + log.Fatal(err)
34 + }
35 + item := model.Item{
36 + Platform: "번개장터",
37 + Name: responseItem.Name,
38 + Price: priceStringToInt(responseItem.Price),
39 + ThumbnailUrl: responseItem.ProductImage,
40 + ItemUrl: "https://m.bunjang.co.kr/products/" + responseItem.Pid,
41 + ExtraInfo: extraInfo,
42 + }
43 + items = append(items, item)
44 + }(responseItem)
45 + }
46 + wg.Wait()
47 +
48 + return items, nil
49 +}
50 +
51 +func getApiResponseItems(keyword string) ([]model.ApiResponseItem, error) {
52 + encText := url.QueryEscape(keyword)
53 + apiUrl := fmt.Sprintf("https://api.bunjang.co.kr/api/1/find_v2.json?q=%s&order=score&n=6", encText)
54 +
55 + response, err := getResponse(apiUrl)
56 + if err != nil {
57 + return nil, err
58 + }
59 +
60 + var apiResponse model.ApiResponse
61 + err = json.Unmarshal(response, &apiResponse)
62 + if err != nil {
63 + return nil, err
64 + }
65 +
66 + return apiResponse.Items, nil
67 +}
68 +
69 +func getItemExtraInfo(pid string) (string, error) {
70 + apiUrl := fmt.Sprintf("https://api.bunjang.co.kr/api/1/product/%s/detail_info.json", pid)
71 +
72 + response, err := getResponse(apiUrl)
73 + if err != nil {
74 + return "", err
75 + }
76 +
77 + var itemInfo map[string]interface{}
78 + err = json.Unmarshal(response, &itemInfo)
79 + if err != nil {
80 + return "", err
81 + }
82 +
83 + extraInfo := itemInfo["item_info"].(map[string]interface{})["description_for_detail"].(string)
84 +
85 + return extraInfo, nil
86 +}
87 +
88 +func getResponse(url string) ([]byte, error) {
89 + req, err := http.NewRequest("GET", url, nil)
90 + if err != nil {
91 + return nil, err
92 + }
93 +
94 + client := &http.Client{}
95 + resp, err := client.Do(req)
96 + if err != nil {
97 + return nil, err
98 + }
99 +
100 + defer func(Body io.ReadCloser) {
101 + err := Body.Close()
102 + if err != nil {
103 + log.Fatal(err)
104 + }
105 + }(resp.Body)
106 +
107 + response, _ := ioutil.ReadAll(resp.Body)
108 +
109 + return response, nil
110 +}
111 +
112 +func priceStringToInt(priceString string) int {
113 + strings.TrimSpace(priceString)
114 +
115 + if priceString == "" {
116 + return 0
117 + }
118 +
119 + priceString = strings.ReplaceAll(priceString, "원", "")
120 + priceString = strings.ReplaceAll(priceString, ",", "")
121 +
122 + price, err := strconv.Atoi(priceString)
123 + if err != nil {
124 + log.Fatal(err)
125 + }
126 + return price
127 +}
1 +#!/usr/bin/env bash
2 +
3 +docker-compose down
4 +docker image rm bunjang-api-server
...\ No newline at end of file ...\ No newline at end of file
1 -FROM python:3 1 +FROM python:alpine
2 2
3 WORKDIR /usr/src/app 3 WORKDIR /usr/src/app
4 4
......
1 +#!/usr/bin/env bash
2 +
3 +docker build -t daangn-api-server ./daangn/
4 +docker build -t joongna-api-server ./joongna/
5 +docker build -t bunjang-api-server ./bunjang/
6 +docker build -t mamuri-db ./database/
7 +
8 +docker-compose up -d
...\ No newline at end of file ...\ No newline at end of file
1 +version: '3'
2 +
3 +services:
4 + daangn_api:
5 + image: daangn-api-server
6 + restart: always
7 + container_name: daangn-api-server-container
8 + ports:
9 + - '18080:8080'
10 +
11 + joongna_api:
12 + image: joongna-api-server
13 + restart: always
14 + container_name: joongna-api-server-container
15 + ports:
16 + - '18081:8080'
17 +
18 + bunjang_api:
19 + image: bunjang-api-server
20 + restart: always
21 + container_name: bunjang-api-server-container
22 + ports:
23 + - '18082:8080'
24 +
25 + db:
26 + image: mamuri-db
27 + restart: always
28 + container_name: mamuri-db-container
29 + ports:
30 + - '13060:3306'
31 + env_file:
32 + - "./database/mysql_init/.env"
...\ No newline at end of file ...\ No newline at end of file
...@@ -11,7 +11,5 @@ WORKDIR /src ...@@ -11,7 +11,5 @@ WORKDIR /src
11 COPY --from=builder /src/joongna_api_server /src/joongna_api_server 11 COPY --from=builder /src/joongna_api_server /src/joongna_api_server
12 COPY --from=builder /src/config/.env /src/config/.env 12 COPY --from=builder /src/config/.env /src/config/.env
13 13
14 -RUN apk add chromium
15 -
16 EXPOSE 8080 14 EXPOSE 8080
17 CMD ["./joongna_api_server"] 15 CMD ["./joongna_api_server"]
......
...@@ -12,6 +12,11 @@ type Config struct { ...@@ -12,6 +12,11 @@ type Config struct {
12 CLIENTID string `env:"SECRET.CLIENTID"` 12 CLIENTID string `env:"SECRET.CLIENTID"`
13 CLIENTSECRET string `env:"SECRET.CLIENTSECRET"` 13 CLIENTSECRET string `env:"SECRET.CLIENTSECRET"`
14 } 14 }
15 +
16 + Header struct {
17 + Cookie string `env:"HEADER.COOKIE"`
18 + UserAgent string `env:"HEADER.USERAGENT"`
19 + }
15 } 20 }
16 21
17 var Cfg *Config 22 var Cfg *Config
......
1 package model 1 package model
2 2
3 type ApiResponse struct { 3 type ApiResponse struct {
4 - LastBuildDate string `json:"lastBuildDate"` 4 + CafeId int `json:"cafeId"`
5 - Total uint `json:"total"` 5 + ArticelCount int `json:"articleCount"`
6 - Start uint `json:"start"` 6 + Query string `json:"query"`
7 - Display uint `json:"display"` 7 + Items []ApiResponseItem `json:"articleList"`
8 - Items []ApiResponseItem `json:"items"`
9 } 8 }
10 9
11 type ApiResponseItem struct { 10 type ApiResponseItem struct {
12 - Title string `json:"title"` 11 + ArticleId int `json:"articleId"`
13 - Link string `json:"link"` 12 + Title string `json:"subject"`
14 - Description string `json:"description"` 13 + ExtraInfo string `json:"summary"`
15 - CafeName string `json:"cafename"` 14 + ThumbnailUrl string `json:"thumbnailImageUrl"`
15 + ProductSale ApiResponseItemSale `json:"productSale"`
16 +}
17 +
18 +type ApiResponseItemSale struct {
19 + SaleStatus string `json:"saleStatue"`
20 + Cost string `json:"cost"`
16 } 21 }
......
1 package service 1 package service
2 2
3 import ( 3 import (
4 - "bytes"
5 "encoding/json" 4 "encoding/json"
5 + "fmt"
6 "io" 6 "io"
7 "io/ioutil" 7 "io/ioutil"
8 "joongna/config" 8 "joongna/config"
...@@ -13,36 +13,35 @@ import ( ...@@ -13,36 +13,35 @@ import (
13 "strconv" 13 "strconv"
14 "strings" 14 "strings"
15 "sync" 15 "sync"
16 - "time"
17 -
18 - "github.com/PuerkitoBio/goquery"
19 - "github.com/go-rod/rod"
20 - "github.com/go-rod/rod/lib/launcher"
21 ) 16 )
22 17
23 func GetItemByKeyword(keyword string) ([]model.Item, error) { 18 func GetItemByKeyword(keyword string) ([]model.Item, error) {
24 var items []model.Item 19 var items []model.Item
25 wg := sync.WaitGroup{} 20 wg := sync.WaitGroup{}
26 21
27 - itemsInfo, err := getItemsInfoByKeyword(keyword) 22 + responseItems, err := getItemsInfoByKeyword(keyword)
28 if err != nil { 23 if err != nil {
29 return nil, err 24 return nil, err
30 } 25 }
31 26
32 - for _, itemInfo := range itemsInfo { 27 + for _, responseItem := range responseItems {
33 - itemUrl := itemInfo.Link
34 - if itemInfo.CafeName != "중고나라" {
35 - continue
36 - }
37 wg.Add(1) 28 wg.Add(1)
38 - go func(itemUrl string) { 29 +
30 + go func(responseItem model.ApiResponseItem) {
39 defer wg.Done() 31 defer wg.Done()
40 - item, err := crawlingNaverCafe(itemUrl)
41 if err != nil { 32 if err != nil {
42 log.Fatal(err) 33 log.Fatal(err)
43 } 34 }
44 - items = append(items, *item) 35 + item := model.Item{
45 - }(itemUrl) 36 + Platform: "중고나라",
37 + Name: responseItem.Title,
38 + Price: priceStringToInt(responseItem.ProductSale.Cost),
39 + ThumbnailUrl: responseItem.ThumbnailUrl,
40 + ItemUrl: fmt.Sprintf("https://m.cafe.naver.com/ca-fe/web/cafes/10050146/articles/%d", responseItem.ArticleId),
41 + ExtraInfo: responseItem.ExtraInfo,
42 + }
43 + items = append(items, item)
44 + }(responseItem)
46 } 45 }
47 wg.Wait() 46 wg.Wait()
48 47
...@@ -50,8 +49,8 @@ func GetItemByKeyword(keyword string) ([]model.Item, error) { ...@@ -50,8 +49,8 @@ func GetItemByKeyword(keyword string) ([]model.Item, error) {
50 } 49 }
51 50
52 func getItemsInfoByKeyword(keyword string) ([]model.ApiResponseItem, error) { 51 func getItemsInfoByKeyword(keyword string) ([]model.ApiResponseItem, error) {
53 - encText := url.QueryEscape("중고나라 " + keyword + " 판매중") 52 + encText := url.QueryEscape(keyword)
54 - apiUrl := "https://openapi.naver.com/v1/search/cafearticle.json?query=" + encText + "&sort=sim" 53 + apiUrl := fmt.Sprintf("https://apis.naver.com/cafe-web/cafe-mobile/CafeMobileWebArticleSearchListV3?cafeId=10050146&query=%s&searchBy=0&sortBy=sim&page=1&perPage=10&adUnit=MW_CAFE_BOARD", encText)
55 54
56 req, err := http.NewRequest("GET", apiUrl, nil) 55 req, err := http.NewRequest("GET", apiUrl, nil)
57 if err != nil { 56 if err != nil {
...@@ -59,6 +58,8 @@ func getItemsInfoByKeyword(keyword string) ([]model.ApiResponseItem, error) { ...@@ -59,6 +58,8 @@ func getItemsInfoByKeyword(keyword string) ([]model.ApiResponseItem, error) {
59 } 58 }
60 req.Header.Add("X-Naver-Client-Id", config.Cfg.Secret.CLIENTID) 59 req.Header.Add("X-Naver-Client-Id", config.Cfg.Secret.CLIENTID)
61 req.Header.Add("X-Naver-Client-Secret", config.Cfg.Secret.CLIENTSECRET) 60 req.Header.Add("X-Naver-Client-Secret", config.Cfg.Secret.CLIENTSECRET)
61 + req.Header.Add("Cookie", config.Cfg.Header.Cookie)
62 + req.Header.Add("User-agent", config.Cfg.Header.UserAgent)
62 63
63 client := &http.Client{} 64 client := &http.Client{}
64 resp, err := client.Do(req) 65 resp, err := client.Do(req)
...@@ -73,55 +74,26 @@ func getItemsInfoByKeyword(keyword string) ([]model.ApiResponseItem, error) { ...@@ -73,55 +74,26 @@ func getItemsInfoByKeyword(keyword string) ([]model.ApiResponseItem, error) {
73 }(resp.Body) 74 }(resp.Body)
74 75
75 response, _ := ioutil.ReadAll(resp.Body) 76 response, _ := ioutil.ReadAll(resp.Body)
76 - var apiResponse model.ApiResponse 77 +
77 - err = json.Unmarshal(response, &apiResponse) 78 + var apiResult map[string]interface{}
79 + err = json.Unmarshal(response, &apiResult)
78 if err != nil { 80 if err != nil {
79 - log.Fatal(err) 81 + return nil, err
80 } 82 }
81 - return apiResponse.Items, nil
82 -}
83 83
84 -func crawlingNaverCafe(cafeUrl string) (*model.Item, error) { 84 + result := apiResult["message"].(map[string]interface{})["result"]
85 - path, _ := launcher.LookPath() 85 + resultJson, err := json.Marshal(result)
86 - u := launcher.New().Bin(path).MustLaunch()
87 -
88 - browser := rod.New().ControlURL(u).MustConnect()
89 - defer func(browser *rod.Browser) {
90 - err := browser.Close()
91 - if err != nil {
92 - log.Fatal(err)
93 - }
94 - }(browser)
95 -
96 - frame := browser.MustPage(cafeUrl).MustElement("iframe#cafe_main")
97 - time.Sleep(time.Second * 2)
98 - source := frame.MustFrame().MustHTML()
99 - html, err := goquery.NewDocumentFromReader(bytes.NewReader([]byte(source)))
100 if err != nil { 86 if err != nil {
101 return nil, err 87 return nil, err
102 } 88 }
103 89
104 - title := html.Find("h3.title_text").Text() 90 + var apiResponse model.ApiResponse
105 - sold := html.Find("div.sold_area").Text() 91 + err = json.Unmarshal(resultJson, &apiResponse)
106 - price := priceStringToInt(html.Find(".ProductPrice").Text()) 92 + if err != nil {
107 - thumbnailUrl, _ := html.Find("div.product_thumb img").Attr("src") 93 + return nil, err
108 - extraInfo := html.Find(".se-module-text").Text()
109 -
110 - title = strings.TrimSpace(title)
111 - sold = strings.TrimSpace(sold)
112 - thumbnailUrl = strings.TrimSpace(thumbnailUrl)
113 - extraInfo = strings.TrimSpace(extraInfo)
114 -
115 - item := model.Item{
116 - Platform: "중고나라",
117 - Name: title,
118 - Price: price,
119 - ThumbnailUrl: thumbnailUrl,
120 - ItemUrl: cafeUrl,
121 - ExtraInfo: extraInfo,
122 } 94 }
123 95
124 - return &item, nil 96 + return apiResponse.Items, nil
125 } 97 }
126 98
127 func priceStringToInt(priceString string) int { 99 func priceStringToInt(priceString string) int {
......
1 +#!/usr/bin/env bash
2 +
3 +docker-compose down
4 +
5 +docker image rm daangn-api-server
6 +docker image rm joongna-api-server
7 +docker image rm bunjang-api-server
8 +docker image rm mamuri-db