๋ก์คํธ์ํฌ ๋๊ธฐ์ด ์นด์นด์คํก ์๋ฆผ๋ด ๊ฐ๋ฐ๊ธฐ
์๋น์ค ๋งํฌ : (https://pf.kakao.com/_dcPGj)
Github ๋งํฌ : (https://github.com/suitelab/lostark-wait-notifier)
๋ค์ด๊ฐ๊ธฐ ์ ์
(http://loaq.kr/)๋ ๋ฐ์ดํฐ ์ฌ๋ฐฐํฌ๋ฅผ ๊ธ์งํ๊ณ ์์ต๋๋ค!
์ด ๊ฒ์๋ฌผ์ ๊ธฐ์กด์ ๋ง๋ค์๋ ์๋น์ค๋ก์จ ํ์ฌ์ ์ด์๋ฐฉ๋ฒ์ด ์๋๋๋ค. ํ๊ธฐ๋ก๋ง ๋ด์ฃผ์ธ์!
ํ์ฌ ์ด์์ค์ธ ์๋น์ค์ ๊ฐ๋ฐ ํ๊ธฐ๋
(http://suitee.me/2018/11/18/lostark-wait-notifier-2/)์ ์ฌ๋ ค๋์์ต๋๋ค.

์์ฆ ๋ก์คํธ์ํฌ๋ฅผ ์ฌ๋ฐ๊ฒ ์ฆ๊ธฐ๊ณ ์๋ค.(~~ํฌ์คํ ์ด ๋ธํด์ง๋ ์ํ~~)
ํ์ง๋ง ์ข์ฒ๋ผ ์ค์ด๋ค์ง ์๋ ๋๊ธฐ์ด๋๋ฌธ์ ํ์ผ ์คํ 5์, ์ฃผ๋ง ์ค์ 10์ ์ดํ์๋ ๋๊ธฐ์ด๊ณผ์ ์ ์์ ์น๋ค์ผํ๋ค.
ํ์๊ฐ ํ๋ ์ดํ๋ ์๋ฒ์ธ ์๋ฐ๋ฐ๋ ๊ธฐ์ค ํ๊ท ๋๊ธฐ์ด์ 15,000๋ช
์ ๋ ๋๋ ๊ฒ ๊ฐ๋ค. ๋๋ต ์๊ฐ์ ์ฌ๋ณธ ๊ฒฐ๊ณผ 2์๊ฐ ๋๊ฒ ๋๊ธฐ๋ฅผ ํ์๋ค.
http://loaq.kr/
๋ก์คํธ์ํฌ๋ฅผ ์ฆ๊ฒจํ๋ ์ ์ ๋ค์ ๊ฒฝ์ฐ ๋๊ธฐ์ด ํํฉ์ ๋ณผ ์ ์๋ ์ ์ฌ์ดํธ๋ฅผ ๊ฝค๋ ๋ง์ด ์๊ณ ์๊ณ ์ด์ฉํ ๊ฒ์ด๋ค. ๋ฌผ๋ก ํ์๋ ์ข ์ข ์ด์ฉํ๋ ํธ์ด๋ค.
๋งค๋ฒ ์ฌ์ดํธ์ ์ฃผ์๋ฅผ ์น๊ณ ๋ค์ด๊ฐ ์๋ก๊ณ ์นจํ๋๊ฒ ๊ท์ฐฎ์์ง๋ ์ฐฐ๋์ ์นด์นด์คํก ํ๋ฌ์ค์น๊ตฌ API๋ฅผ ์ด์ฉํ์ฌ ๋๊ธฐ์ด ์ ๋ณด๋ฅผ ํธํ๊ฒ ์นดํก์ผ๋ก ๋ฐ์๋ณด๋ฉด ์ด๋จ๊น ํ๋ ์๊ฐ์ด ๋ค๊ฒ ๋์๋ค. ๊ฒ์ํ๋ ์ด์ ๊ฐ๋ฐ์ ๋์์ ํ ์ ์๋ ์ฐฌ์ค์๋ค.
loaq.kr์ ๋๊ธฐ์ด ๋ฐ์ดํฐ์ ์์ฒ์ ์๊ณ ์ถ์์ง๋ง ๊ฒฐ๊ตญ ์์๋ด์ง ๋ชปํ์๋ค. ๋ก์คํธ์ํฌ ์ธก์์ ๋ณ๋์ API๋ ์ ๊ณตํด์ฃผ์ง ์๋ ๊ฒ ๊ฐ์๋ค.
๊ทธ๋ฆฌํ์ฌ ๊ฐ๋ฐ ํ๋ก์ธ์ค๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ํ์๋ค.
- loaq.kr์ ๋ฐ์ดํฐ๋ฅผ ํฌ๋กค๋งํ๋ค.
- ํฌ๋กค๋งํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ์ฌ jsonํํ๋ก ์ ๊ณตํ๋ค.
- jsonํํ๋ก ์ ๊ณต๋ฐ์ ๋ฐ์ดํฐ๋ฅผ kakao ํ๋ฌ์ค์น๊ตฌ api๋ฅผ ํตํด ์๋น์ค ํ๋ค.
1. loaq.kr์ ๋ฐ์ดํฐ๋ฅผ ํฌ๋กค๋งํ๋ค.
ํฌ๋กค๋ฌ์ ๊ฒฝ์ฐ selenium๋ฅผ ์์ฃผ ์จ๋ดค์ด์ ๊ณ ๋ คํด๋ดค์ง๋ง ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฌ์ฉํ๋ selenium ํน์ฑ์ request๋น ๋งค๋ฒ ๋น ๋ฅด๊ฒ ํฌ๋กค๋ง ํด์ผํ๋ ์ด๋ฒ ์๋น์ค์๋ ์ด์ธ๋ฆฌ์ง ์๊ฒ ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
๊ทธ๋์ ๋์ค์ ์ผ๋ก ๋ง์ด ์ฌ๋๋ฐ๋ BeautifulSoup๋ฅผ ์ฌ์ฉํ์๋ค.
์ฐ์ loaq.kr์ ๊ตฌ์กฐ๋ฅผ ํ์ ํ๋ค.
(divclassName="server-list")
(divclassName="row")
(divclassName="cell col-center")
๋ฃจํ์จ
(/div)
(divclassName="cell col-center")
(div)
(spanclassName="red")2348(/span)
(/div)
(div)
(spanclassName="small-text bottom-text blue")
(โผ1183)
(/span)
(/div)
(/div)
(divclassName="cell col-center")
(a href="/server/1")์์ธ๋ณด๊ธฐ(/a)
(/div)
(/div)
...
์๋ฒ ํ๊ฐ์ row๊ตฌ์กฐ๋ ์ ๋ ๊ฒ ์ด๋ฃจ์ด์ ธ ์์๊ณ ์๋ฒ๋ช ๊ณผ ๋๊ธฐ์ ๋ฐ์ดํฐ๋ฅผ ๋์ด์ค๋ ค๋ฉด ์ ํฉํ selector๊ฐ div.server-list๋ผ๊ณ ์๊ฐ๋์ด์ ๊ทธ๋ ๊ฒ ์ ํ๋ค.
๊ณต๋ฐฑ, (โผ1183)์ ๊ฐ์ ๋ฑ๋ฝ๋ฐ์ดํฐ, ์์ธ๋ณด๊ธฐ, ํ ์ด๋ธ์ ํค๋ ๋ฑ๋ฑ ๋ถํ์ํ ์ ๋ณด๋ฅผ ์ ๋ฆฌํ๋ค.
for tag in soup.select('div.server-list'):
server_name += tag.text
server_name = server_name.replace(' ', '').split("\n")
server_name = [x for x in server_name
if "(" not in x and "์์ธ" not in x and
"์๋ฒ" not in x and "๋๊ธฐ์ด" not in x and
"\xa0" not in x and "" != x]
2. ํฌ๋กค๋งํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ์ฌ jsonํํ๋ก ์ ๊ณตํ๋ค.
์ ์ ๋ ๋ฐ์ดํฐ๊ฐ ์ค๋น ๋์์ผ๋ ์ด์ json์ผ๋ก ์ ๊ณตํ ์ค๋น๋ฅผ ํ๋ค.
{
"server_time": "2018-11-18 15:49:49",
"items": [
{
"server": "๋ฃจํ์จ",
"wait": "13744"
}
]
}
json์ ํํ๋ฅผ ์์ ๊ฐ์ด ์ค๋นํด๋ณด์๋ค.
์ฒ์์ผ๋ก ๋ง๋ค์ด๋ณด๋ api์ฌ์ ๊ทธ๋ฐ์ง ํํ๊ฐ ์์ง ์ฑ์ ์ฐจ์ง์๋๋ค.
๊ทธ๋๋ ์ด์ ๋ ๋ชจ์์๋ฉด ์ด๋์ ๋ ์ ์ ํ ํ์ํ ๋ฐ์ดํฐ๋ค์ ๋ด๊ณ ์ ๊ณตํ ์ ์๋ ํํ๊ฐ ๋์๋ค๊ณ ์๊ฐ๋๋ค.
servers = {}
servers['server_time'] = soup.select('div.time')[0].text
.replace(" ","").replace('\n', '')
for i, item in enumerate(server_name):
if i % 2 == 0:
items.append({"server": item, "wait": server_name[i + 1]})
servers["items"] = items
3. jsonํํ๋ก ์ ๊ณต๋ฐ์ ๋ฐ์ดํฐ๋ฅผ kakao ํ๋ฌ์ค์น๊ตฌ api๋ฅผ ํตํด ์๋น์ค ํ๋ค.
์ฒ์์ node.js๋ฅผ ์ด์ฉํด์ ๋น๋๊ธฐ ์๋น์ค๋ฅผ ์ ๊ณตํด๋ณผ ์๊ฐ์ด์์ง๋ง ํฌ๋กค๋ฌ์ ๊ฐ์ ์ธ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ ์ ๊ฑด๊ฐ์ ์ข์๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ์ฃผ๋ง๋ฑ์ฒ๋ผ ์ค์ณ ์ง๋๊ฐ๋ค.
๊ทธ๋์ python์ web framework์ค ํ๋์ธ flask๋ฅผ ์ฌ์ฉํด๋ณด์๋ค.
django๋ ๋ช ๋ฒ ์ฌ์ฉํด๋ดค์ง๋ง flask๋ ์ด๋ฐ ์์ ์๋น์ค์ ์ด์ธ๋ฆฐ๋ค๊ณ ์๊ฐ์ด ๋์ด์ ์ฑํํ๊ฒ ๋์๋ค.
flask์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ด ๊ธ์ ์ฃผ์ ์์ ๋ฒ์ด๋๊ธฐ ๋๋ฌธ์ ๋ค์์ ๋์ฑ ๋ค๋ค๋ณด๋๋ก ํ๊ฒ ๋ค.
ํ๋ฌ์ค์น๊ตฌ ๊ณ์ ์ ๋ง๋ ํ ์ค๋งํธ์ฑํ
-API๊ฐ ์ฌ์ง๊ณผ ๊ฐ์ด ์ค์ ๋์ด์์ด์ผํ๋ค.
๋ํ๋ฐฉ์ ์ฒซ ์ง์ ์ ๋ณด์ฌ์ค keyboard๋ฅผ ์ ์ํ๋ ์ฝ๋์ด๋ค.
@app.route('/keyboard')
def Keyboard():
dataSend = {
"type": "buttons",
"buttons": ["๋๊ธฐ์ด", "๋ช
๋ น์ด"]
}
return jsonify(dataSend)
๋ค์์ ๊ฐ ์ํฉ(๋ฉ๋ด)๋ณ ์๋๋ฆฌ์ค๋ฅผ ๊ตฌํํ message์ด๋ค.
ํ์ฌ ์ฐ๋ฆฌ์ ์๋น์ค๋ ๋งค์ฐ ๋จ์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋จํ๊ฒ ๊ตฌ์ฑ๋์ด์๋ค.
keyboard์ ๋๊ธฐ์ด ๋ฒํผ์ด ํด๋ฆญ๋๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ํํ์ด๋ค. ํฌ๋กค๋ฌ์์ ๋ฐ์์จ json ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด ์ค์ ๋ก ๋ณด์ฌ์ค message๋ฅผ ๊ตฌ์ฑํ๋ค.
๋ง์ง๋ง์ dataSend["keyboard"] = {"type": "buttons", "buttons": ["๋๊ธฐ์ด", "๋ช
๋ น์ด"]}
๋ฅผ ์ถ๊ฐํ์ฌ ๋ชจ๋ ํ๋ฉด์์ keyboard๊ฐ ๋์ํ๊ฒ ๋ง๋ค์ด์ค๋ค.
@app.route('/message', methods=['POST'])
def Message():
dataReceive = request.get_json()
content = dataReceive['content']
if content == u"๋๊ธฐ์ด":
cr = Crawler()
json_file = cr.start()
text = f"์๋ฒ์๊ฐ - {json_file['server_time']}\n\n"
for item in json_file['items']:
text += f"{item['server']} - {item['wait']}\n"
dataSend = {
"message": {
"text": text
}
}
elif content == u"๋ช
๋ น์ด":
dataSend = {
"message": {
"text": "1. ๋๊ธฐ์ด\n2. ๋ช
๋ น์ด"
}
}
else:
dataSend = {
"message": {
"text": "๋ช
๋ น์ด๋ฅผ ๋ค์ ์
๋ ฅํด์ฃผ์ธ์. 1. ๋๊ธฐ์ด, 2.๋ช
๋ น์ด"
}
}
dataSend["keyboard"] = {"type": "buttons", "buttons": ["๋๊ธฐ์ด", "๋ช
๋ น์ด"]}
return jsonify(dataSend)
ํ๋ฃจ๋ง์ ๊ธ์กฐํ ํ๋ก๊ทธ๋จ์ด๋ผ ์์ฑ๋๊ฐ ๋ง์ด ๋จ์ด์ง์ง๋ง ํ์ฌ๋ ๋ง์ ์ฌ๋๋ค์ด ์ด์ฉํด์ฃผ์ ์ ๊ฐ์ฌํ ๋ฐ๋ฆ์ด๋ค ๐

(http://www.inven.co.kr/board/lostark/4821/5381)
๋ก์คํธ์ํฌ ์ธ๋ฒค์์๋ ๋ง์ ๋ถ๋ค์ด ์ด์ฉํด์ฃผ์๊ณ ๊ณ์ ๋ค.

(https://pf.kakao.com/_dcPGj)
ํ์ฌ ๊ธฐ์ค์ผ๋ก 3000๋ช
์ ๋ํํ๋ค! โค๏ธโค๏ธโค๏ธ
์ด๋ฒ ์๋น์ค ๊ฐ๋ฐ์ ๊ท์ฐฎ์์ ๋ฒ์ด๋๋ ค๊ณ ์์ํ ๋ชธ๋ถ๋ฆผ์ ๋นํด ๊ฝค๋ ๋ณด๋์ฐฌ ๊ฐ๋ฐ์ด์๋ค๋ ์๊ฐ์ด ๋ ๋ค.
์์ผ๋ก๋ ์ด๋ฐ ์์ด๋์ด๊ฐ ๋ ์ค๋ฅด๋ฉด ํธ๋ฆฌํจ์ ์ํด ํธ๋ฆฌํจ์ ๊ฐ๋ฐํ๋ ๊ฐ๋ฐ์๊ฐ ๋ ๊ฒ์ด๋ค.