Merge branch 'feature/220510_joongna_api' into 'main'
Feature/220510 joongna api # 중고나라 키워드 검색 api 1. `api/v2/joongna/{keyword}` GET 요청하려 keyword 전달 2. 네이버 카페 검색 api를 통해 유사도 높은 순서로 검색 3. 검색 결과의 카페 링크를 통해 세부 항목 크롤링 (selenium) 4. 세부 항목 담아서 response See merge request !6
Showing
9 changed files
with
382 additions
and
25 deletions
joongna/Dockerfile
0 → 100644
1 | +FROM golang:1.17.3 | ||
2 | + | ||
3 | +RUN apt-get -y update | ||
4 | +RUN apt-get install -y wget xvfb gnupg | ||
5 | + | ||
6 | +RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - | ||
7 | +RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' | ||
8 | +RUN apt-get -y update | ||
9 | +RUN apt-get install -y google-chrome-stable | ||
10 | + | ||
11 | +RUN apt-get install -yqq unzip | ||
12 | +RUN wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip | ||
13 | +RUN unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/ | ||
14 | + | ||
15 | +ENV Xvfb :99 | ||
16 | +ENV DISPLAY=:99 |
joongna/controller/controller.go
0 → 100644
1 | +package controller | ||
2 | + | ||
3 | +import ( | ||
4 | + "joongna/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 | +} |
... | @@ -3,6 +3,23 @@ module joongna | ... | @@ -3,6 +3,23 @@ module joongna |
3 | go 1.17 | 3 | go 1.17 |
4 | 4 | ||
5 | require ( | 5 | require ( |
6 | + github.com/PuerkitoBio/goquery v1.8.0 // indirect | ||
7 | + github.com/andybalholm/cascadia v1.3.1 // indirect | ||
8 | + github.com/blang/semver v3.5.1+incompatible // indirect | ||
9 | + github.com/bunsenapp/go-selenium v0.1.0 // indirect | ||
6 | github.com/caarlos0/env/v6 v6.9.1 // indirect | 10 | github.com/caarlos0/env/v6 v6.9.1 // indirect |
11 | + github.com/fedesog/webdriver v0.0.0-20180606182539-99f36c92eaef // indirect | ||
7 | github.com/joho/godotenv v1.4.0 // indirect | 12 | github.com/joho/godotenv v1.4.0 // indirect |
13 | + github.com/labstack/echo/v4 v4.7.2 // indirect | ||
14 | + github.com/labstack/gommon v0.3.1 // indirect | ||
15 | + github.com/mattn/go-colorable v0.1.11 // indirect | ||
16 | + github.com/mattn/go-isatty v0.0.14 // indirect | ||
17 | + github.com/tebeka/selenium v0.9.9 // indirect | ||
18 | + github.com/valyala/bytebufferpool v1.0.0 // indirect | ||
19 | + github.com/valyala/fasttemplate v1.2.1 // indirect | ||
20 | + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect | ||
21 | + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect | ||
22 | + golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect | ||
23 | + golang.org/x/text v0.3.7 // indirect | ||
24 | + sourcegraph.com/sourcegraph/go-selenium v0.0.0-20170113155244-3da7d00aac9c // indirect | ||
8 | ) | 25 | ) | ... | ... |
1 | +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||
2 | +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||
3 | +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= | ||
4 | +cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= | ||
5 | +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||
6 | +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= | ||
7 | +github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k= | ||
8 | +github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= | ||
9 | +github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= | ||
10 | +github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= | ||
11 | +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= | ||
12 | +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= | ||
13 | +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= | ||
14 | +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= | ||
15 | +github.com/bunsenapp/go-selenium v0.1.0 h1:sDE9BCUoZNWycffacIzjU2ubpGTCMX3K9+QhbsbY4EI= | ||
16 | +github.com/bunsenapp/go-selenium v0.1.0/go.mod h1:QbngcjhmXoGwhOcwBMhSXYl1A29IVDZff1T00GZ7y30= | ||
1 | github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k= | 17 | github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k= |
2 | github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= | 18 | github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= |
19 | +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||
20 | +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
21 | +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
22 | +github.com/fedesog/webdriver v0.0.0-20180606182539-99f36c92eaef h1:0z8rB8nAGEso7PhKS21wBjjxTp2uGPyZ6STzRc7mnBY= | ||
23 | +github.com/fedesog/webdriver v0.0.0-20180606182539-99f36c92eaef/go.mod h1:RUn/EmpfFIGHvmeXmh+hk1UaCbjOXa6vl7/kx1b6wxw= | ||
24 | +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||
25 | +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||
26 | +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||
27 | +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= | ||
28 | +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
29 | +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
30 | +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | ||
31 | +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | ||
32 | +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||
33 | +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||
34 | +github.com/google/go-github/v27 v27.0.4/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= | ||
35 | +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= | ||
36 | +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= | ||
37 | +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||
38 | +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||
39 | +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= | ||
40 | +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= | ||
41 | +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||
42 | +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||
3 | github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= | 43 | github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= |
4 | github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= | 44 | github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= |
45 | +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | ||
46 | +github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI= | ||
47 | +github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= | ||
48 | +github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= | ||
49 | +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= | ||
50 | +github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= | ||
51 | +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= | ||
52 | +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= | ||
53 | +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= | ||
54 | +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
55 | +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
56 | +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
57 | +github.com/tebeka/selenium v0.9.9 h1:cNziB+etNgyH/7KlNI7RMC1ua5aH1+5wUlFQyzeMh+w= | ||
58 | +github.com/tebeka/selenium v0.9.9/go.mod h1:5Fr8+pUvU6B1OiPfkdCKdXZyr5znvVkxuPd0NOdZCQc= | ||
59 | +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= | ||
60 | +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= | ||
61 | +github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= | ||
62 | +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | ||
63 | +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= | ||
64 | +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= | ||
65 | +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
66 | +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||
67 | +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= | ||
68 | +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
69 | +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||
70 | +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | ||
71 | +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||
72 | +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||
73 | +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= | ||
74 | +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||
75 | +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||
76 | +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||
77 | +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= | ||
78 | +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
79 | +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
80 | +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
81 | +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
82 | +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
83 | +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
84 | +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
85 | +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
86 | +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | ||
87 | +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
88 | +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||
89 | +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= | ||
90 | +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||
91 | +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||
92 | +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||
93 | +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||
94 | +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
95 | +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
96 | +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
97 | +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
98 | +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
99 | +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
100 | +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
101 | +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
102 | +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
103 | +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
104 | +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
105 | +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
106 | +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
107 | +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
108 | +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
109 | +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
110 | +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
111 | +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4= | ||
112 | +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
113 | +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
114 | +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
115 | +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
116 | +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | ||
117 | +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
118 | +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= | ||
119 | +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||
120 | +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||
121 | +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||
122 | +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
123 | +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
124 | +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= | ||
125 | +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||
126 | +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||
127 | +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||
128 | +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||
129 | +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||
130 | +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||
131 | +golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||
132 | +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= | ||
133 | +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= | ||
134 | +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||
135 | +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||
136 | +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||
137 | +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | ||
138 | +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||
139 | +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||
140 | +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||
141 | +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||
142 | +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||
143 | +google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= | ||
144 | +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||
145 | +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | ||
146 | +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||
147 | +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
148 | +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
149 | +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
150 | +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||
151 | +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||
152 | +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||
153 | +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= | ||
154 | +sourcegraph.com/sourcegraph/go-selenium v0.0.0-20170113155244-3da7d00aac9c h1:tHzm+QPxwLIVkEhk7hjX8tzgIPB4dxcHWg7lrxa0L+A= | ||
155 | +sourcegraph.com/sourcegraph/go-selenium v0.0.0-20170113155244-3da7d00aac9c/go.mod h1:AnVhEyJt1uHaBqUjmUJAmpdW2GPHGx0BivIkVCUvkAo= | ... | ... |
1 | package main | 1 | package main |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | - "fmt" | 4 | + "joongna/router" |
5 | - "io/ioutil" | 5 | + |
6 | - "joongna/config" | 6 | + "github.com/labstack/echo/v4" |
7 | - "log" | ||
8 | - "net/http" | ||
9 | - url2 "net/url" | ||
10 | ) | 7 | ) |
11 | 8 | ||
12 | func main() { | 9 | func main() { |
13 | - keyword := "m1 pro 맥북 프로 16인치" | 10 | + e := echo.New() |
14 | - encText := url2.QueryEscape("중고나라" + keyword) | ||
15 | - url := "https://openapi.naver.com/v1/search/cafearticle.json?query=" + encText + "&sort=sim" | ||
16 | - | ||
17 | - req, err := http.NewRequest("GET", url, nil) | ||
18 | - if err != nil { | ||
19 | - log.Fatal(err) | ||
20 | - } | ||
21 | - req.Header.Add("X-Naver-Client-Id", config.Cfg.Secret.CLIENTID) | ||
22 | - req.Header.Add("X-Naver-Client-Secret", config.Cfg.Secret.CLIENTSECRET) | ||
23 | 11 | ||
24 | - client := &http.Client{} | 12 | + router.Init(e) |
25 | - resp, err := client.Do(req) | ||
26 | - if err != nil { | ||
27 | - log.Fatal(err) | ||
28 | - } | ||
29 | - defer resp.Body.Close() | ||
30 | 13 | ||
31 | - bytes, _ := ioutil.ReadAll(resp.Body) | 14 | + e.Logger.Fatal(e.Start(":8080")) |
32 | - str := string(bytes) | ||
33 | - fmt.Println(str) | ||
34 | } | 15 | } | ... | ... |
joongna/model/api_response.go
0 → 100644
1 | +package model | ||
2 | + | ||
3 | +type ApiResponse struct { | ||
4 | + LastBuildDate string `json:"lastBuildDate"` | ||
5 | + Total uint `json:"total"` | ||
6 | + Start uint `json:"start"` | ||
7 | + Display uint `json:"display"` | ||
8 | + Items []ApiResponseItem `json:"items"` | ||
9 | +} | ||
10 | + | ||
11 | +type ApiResponseItem struct { | ||
12 | + Title string `json:"title"` | ||
13 | + Link string `json:"link"` | ||
14 | + Description string `json:"description"` | ||
15 | + CafeName string `json:"cafename"` | ||
16 | +} |
joongna/model/item.go
0 → 100644
joongna/router/router.go
0 → 100644
1 | +package router | ||
2 | + | ||
3 | +import ( | ||
4 | + "joongna/controller" | ||
5 | + | ||
6 | + "github.com/labstack/echo/v4" | ||
7 | +) | ||
8 | + | ||
9 | +const ( | ||
10 | + API = "/api/v2" | ||
11 | + APIJoongNa = API + "/JoongNa" | ||
12 | + APIKeyword = APIJoongNa + "/:keyword" | ||
13 | +) | ||
14 | + | ||
15 | +func Init(e *echo.Echo) { | ||
16 | + e.GET(APIKeyword, controller.Search) | ||
17 | +} |
joongna/service/item.go
0 → 100644
1 | +package service | ||
2 | + | ||
3 | +import ( | ||
4 | + "bytes" | ||
5 | + "encoding/json" | ||
6 | + "io" | ||
7 | + "io/ioutil" | ||
8 | + "joongna/config" | ||
9 | + "joongna/model" | ||
10 | + "log" | ||
11 | + "net/http" | ||
12 | + "net/url" | ||
13 | + "strconv" | ||
14 | + "strings" | ||
15 | + "time" | ||
16 | + | ||
17 | + "github.com/PuerkitoBio/goquery" | ||
18 | + "github.com/fedesog/webdriver" | ||
19 | +) | ||
20 | + | ||
21 | +func GetItemByKeyword(keyword string) ([]model.Item, error) { | ||
22 | + var items []model.Item | ||
23 | + | ||
24 | + itemsInfo := getItemsInfoByKeyword(keyword) | ||
25 | + for _, itemInfo := range itemsInfo { | ||
26 | + if itemInfo.CafeName != "중고나라" { | ||
27 | + continue | ||
28 | + } | ||
29 | + itemUrl := itemInfo.Link | ||
30 | + sold, price, thumbnailUrl, extraInfo := crawlingNaverCafe(itemUrl) | ||
31 | + | ||
32 | + if sold == "판매 완료" { | ||
33 | + continue | ||
34 | + } | ||
35 | + | ||
36 | + item := model.Item{ | ||
37 | + Platform: "중고나라", | ||
38 | + Name: itemInfo.Title, | ||
39 | + Price: price, | ||
40 | + ThumbnailUrl: thumbnailUrl, | ||
41 | + ItemUrl: itemUrl, | ||
42 | + ExtraInfo: extraInfo, | ||
43 | + } | ||
44 | + items = append(items, item) | ||
45 | + } | ||
46 | + return items, nil | ||
47 | +} | ||
48 | + | ||
49 | +func getItemsInfoByKeyword(keyword string) []model.ApiResponseItem { | ||
50 | + encText := url.QueryEscape("중고나라 " + keyword + " 판매중") | ||
51 | + apiUrl := "https://openapi.naver.com/v1/search/cafearticle.json?query=" + encText + "&sort=sim" | ||
52 | + | ||
53 | + req, err := http.NewRequest("GET", apiUrl, nil) | ||
54 | + if err != nil { | ||
55 | + log.Fatal(err) | ||
56 | + } | ||
57 | + req.Header.Add("X-Naver-Client-Id", config.Cfg.Secret.CLIENTID) | ||
58 | + req.Header.Add("X-Naver-Client-Secret", config.Cfg.Secret.CLIENTSECRET) | ||
59 | + | ||
60 | + client := &http.Client{} | ||
61 | + resp, err := client.Do(req) | ||
62 | + if err != nil { | ||
63 | + log.Fatal(err) | ||
64 | + } | ||
65 | + defer func(Body io.ReadCloser) { | ||
66 | + err := Body.Close() | ||
67 | + if err != nil { | ||
68 | + log.Fatal(err) | ||
69 | + } | ||
70 | + }(resp.Body) | ||
71 | + | ||
72 | + response, _ := ioutil.ReadAll(resp.Body) | ||
73 | + var apiResponse model.ApiResponse | ||
74 | + err = json.Unmarshal(response, &apiResponse) | ||
75 | + if err != nil { | ||
76 | + log.Fatal(err) | ||
77 | + } | ||
78 | + return apiResponse.Items | ||
79 | +} | ||
80 | + | ||
81 | +func crawlingNaverCafe(cafeUrl string) (string, int, string, string) { | ||
82 | + driver := webdriver.NewChromeDriver("./chromedriver") | ||
83 | + err := driver.Start() | ||
84 | + if err != nil { | ||
85 | + log.Println(err) | ||
86 | + } | ||
87 | + desired := webdriver.Capabilities{"Platform": "Linux"} | ||
88 | + required := webdriver.Capabilities{} | ||
89 | + session, err := driver.NewSession(desired, required) | ||
90 | + if err != nil { | ||
91 | + log.Println(err) | ||
92 | + } | ||
93 | + err = session.Url(cafeUrl) | ||
94 | + if err != nil { | ||
95 | + log.Println(err) | ||
96 | + } | ||
97 | + time.Sleep(time.Second * 1) | ||
98 | + err = session.FocusOnFrame("cafe_main") | ||
99 | + if err != nil { | ||
100 | + log.Fatal(err) | ||
101 | + } | ||
102 | + resp, err := session.Source() | ||
103 | + | ||
104 | + html, err := goquery.NewDocumentFromReader(bytes.NewReader([]byte(resp))) | ||
105 | + if err != nil { | ||
106 | + log.Fatal(err) | ||
107 | + } | ||
108 | + | ||
109 | + sold := html.Find("div.sold_area").Text() | ||
110 | + price := priceStringToInt(html.Find(".ProductPrice").Text()) | ||
111 | + thumbnailUrl, _ := html.Find("div.product_thumb img").Attr("src") | ||
112 | + extraInfo := html.Find(".se-module-text").Text() | ||
113 | + | ||
114 | + sold = strings.TrimSpace(sold) | ||
115 | + thumbnailUrl = strings.TrimSpace(thumbnailUrl) | ||
116 | + extraInfo = strings.TrimSpace(extraInfo) | ||
117 | + | ||
118 | + return sold, price, thumbnailUrl, extraInfo | ||
119 | +} | ||
120 | + | ||
121 | +func priceStringToInt(priceString string) int { | ||
122 | + strings.TrimSpace(priceString) | ||
123 | + | ||
124 | + priceString = strings.ReplaceAll(priceString, "원", "") | ||
125 | + priceString = strings.ReplaceAll(priceString, ",", "") | ||
126 | + | ||
127 | + price, err := strconv.Atoi(priceString) | ||
128 | + if err != nil { | ||
129 | + log.Fatal(err) | ||
130 | + } | ||
131 | + return price | ||
132 | +} |
-
Please register or login to post a comment