ย 


#์„œ๋ก 


๋ฐ˜๊ฐ‘๋‹ค. ๊ณง ๊ฒŒ์ž„ ๊ฐœ๋ฐœย 6๋…„์ฐจ๊ฐ€ ๋˜๊ฐ€์ง€๋งŒ ์ถœ์‹œํ•œ ๊ฒŒ์ž„์€ ํ•˜๋‚˜๋„ ์—†๋Š” ์ข†๋ณ‘์‹  ๊ฐœ๋ฐœ์ž๋‹ค.


(์งค์€ ๋Œ€์ถฉ ํ˜„์žฌ ๋‚ด๊ฐ€ ํŒ€์žฅ์œผ๋กœ ์žˆ๋Š”ย ์ธ๋””๊ฒŒ์ž„ํŒ€์˜ย ์ผ๋Ÿฌ์ŠคํŠธ๋ฅผย ๊ทธ๋ฆผ์Ÿ์ด ํ—ˆ๋ฝ์—†์ด ๊ทธ๋ƒฅ ๊ฐ€์ ธ์™”๋‹ค.)







์ตœ๊ทผ ์ธ๊ฐค์— ๋งŽ์€ ์งˆ๋ฌธ ๊ธ€๋“ค์ด ์Ÿ์•„์ ธ ์žˆ๋Š”๋ฐ ์œ ํŠœ๋ธŒ ๋ณด๋А๋ผ ๋ฐ”๋กœ๋ฐ”๋กœ ๋‹ต๋ณ€์„ ๋ชปํ•ด์ค„๋•Œ๊ฐ€ ์žˆ๋‹ค.


์ตœ๊ทผ ๋Œ€๋ถ€๋ถ„์€ ์•„๋‹ˆ์ง€๋งŒ ๋ช‡๋ช‡ย ์งˆ๋ฌธ๊ธ€๋“ค์„ ๋ณด๋ฉด์€ย ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๋ฐฐ์šด์ง€ ์–ผ๋งˆ ์•ˆ๋œ ๋‰ด๋น„๋“ค์ด ์ž‘์„ฑํ•˜๋Š”๋ฐ,ย ๋‚˜๊ฐ™์ด ์งฌ๋ฐฅ์ข€ ๋จน์€ ๋†ˆ๋“ค์ด๋ฉด ๊ทธ๋ƒฅ ๋Œ€์ถฉย ๊ตฌ๊ธ€๋งํ•˜๋ฉด ์•„๋Š”๊ฑธ ์ด์ƒˆ๋ผ๋“ค์€ ๊ผญย ๋””์‹œ์— ์งˆ๋ฌธํ•˜๋Ÿฌ ์˜จ๋‹ค.


์•„๋งˆ ๋ฐฉํ•™์‹œ์ฆŒ์ด๋ผ ๊ทธ๋Ÿฐ๊ฐ€ ๋ณด๋‹ค.


ํ•˜์ง€๋งŒ ์ด ํ•‘ํ”„๋“ค์ด ๋ฌด์Šจ ์ž˜๋ชป์ด ์žˆ๊ฒ ๋Š”๊ฐ€. ์ž๊ธฐ๋”ด์—๋Š” ์ตœํ›„์˜ ์ˆ˜๋‹จ์œผ๋กœ ์—ฌ๊ธฐ์— ์งˆ๋ฌธํ•œ๊ฑฐ๊ฒ ์ง€.


๊ทธ๋Ÿฐ ๋‰ด๋น„๋“ค์ดย ๋น ๋ฅธ ๋‹ต๋ณ€์„ ๋ฐ›์ง€ย ๋ชปํ•œ๋‹ค๋ฉด ๊ทธ๋Œ€๋กœ ๊ฐœ๋ฐœ์— ๋Œ€ํ•œ ๊ด€์‹ฌ์ดย ๋งค๋ง๋ผ ๋ฒ„๋ฆฌ์ง€ ์•Š์„๊นŒ.


๊ทธ๋ž˜์„œ ๊ทธ๋Ÿฐ ์งˆ๋ฌธ๋“ค์€ ๋น ๋ฅด๊ฒŒ ๊ด€๋ จ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•œ ๊ตฌ๊ธ€๋งํฌ๋ฅผ ๋ณด๋‚ด๋Š”๊ฑฐ๋ผ๋„ ํ•˜๊ณ ์žˆ๋‹ค.


๊ทผ๋ฐ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ๊น ์ด ์‹œ๋ฐœ๋ จ๋“ค์€ ์™œ ์งˆ๋ฌธ ๋ง๋จธ๋ฆฌ๊ฐ€ ์žˆ๋Š”๋ฐ๋„ ์ ์šฉํ•˜์ง€ ์•Š๋Š”๊ฑธ๊นŒ


์ฐธ๊ณ ๋กœ ์ˆ ๋งˆ์‹œ๊ณ  ์ž‘์„ฑํ•˜๊ณ ์žˆ์–ด์„œ ๋‚ด์šฉ์ด ๋‘๋ฃจ๋ญ‰์‹คํ• ์ˆ˜ ์žˆ๋‹ค.




์—ฌํ•˜ํŠผ ์˜ค๋Š˜์€ ์–ด๋ฆฌ์„๊ฒŒ๋„ ์ธ๊ฐค์— ์ง€์‹์„ ๊ตฌํ•˜๊ณ ์ž ํ•˜๋Š” ๊ธธ์žƒ์€ ์–ด๋ฆฐ ์–‘๋“ค์—๊ฒŒ ์ตœ๋Œ€ํ•œ ๋น ๋ฅธ ์†๋„๋กœ ๋‹ต๋ณ€์„ ํ•ด์ฃผ๊ธฐ ์œ„ํ•œ ๋‚˜๋งŒ์˜ ๋””์”จ ์•Œ๋ฆฌ๋ฏธ๋ฅผ ๋งŒ๋“ค๊ณ ์ž ํ•œ๋‹ค.


๋กœ์ง์€ ์ด๋ ‡๋‹ค.


1. ์ธ๋””๊ฒŒ์ž„๊ฐœ๋ฐœ๊ฐค๋Ÿฌ๋ฆฌ์˜ ๋งจ์•žย ํŽ˜์ด์ง€๋ฅผย ํฌ๋กค๋งํ•œ๋‹ค.

2. ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์ƒˆ๋กœ ์ž‘์„ฑ๋œ ๊ธ€์˜ ์ œ๋ชฉ์— '?', '์งˆ๋ฌธ', '๋‰ด๋น„', '๋„์›€' ์ด ํฌํ•จ๋˜์–ด ์žˆ๊ฑฐ๋‚˜ ๋ง๋จธ๋ฆฌ๊ฐ€ ์งˆ๋ฌธ์ธ ๊ธ€์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

3. ๋งŒ์•ฝ ๊ทธ๋Ÿฐ ๊ธ€์ด ์žˆ๋‹ค๋ฉด ๋””์ฝ”๋กœ ๋‚˜ํ•œํ…Œ ๊ธ€์ œ๋ชฉ๊ณผ ํ•˜์ดํผ๋งํฌ๋ฅผย ๋ณด๋‚ธ๋‹ค


์š”์•ฝํ•˜์ž๋ฉด ๊ทธ๋ƒฅ ํฌ๋กค๋ง + ๋””์ฝ” ๋ด‡์„ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค, ์ฐธ ์‰ฝ์ฃ ?


์ค€๋น„๋ฌผ : NAS



#๋ณธ๋ก 


์–ธ์–ด๋Š” ํŒŒ์ด์ฌ์œผ๋กœ ๊ณจ๋ž๋‹ค. ์‚ฌ์‹ค 3๋…„์ „ ๋Œ€ํ•™๊ต์—์„œ ๊น”์งํ•˜๊ณ  ๋ฐฐ์šด๊ฒŒ ๋‹ค์ง€๋งŒ ํŒŒ์ด์ฌ์ด๋ผ๋Š” ์–ธ์–ด ์ž์ฒด๊ฐ€ ์–ด๋ ค์šด ํŽธ์€ ์•„๋‹ˆ๋‹ค.


์‚ฌ์‹ค ์Šคํฌ๋ฆฝํŠธย ์–ธ์–ด๊ฐ€ ๊ฑฐ๊ธฐ์„œ ๊ฑฐ๊ธฐ์ง€ ๋ญ


์‚ฌ์šฉํ•  ํŒจํ‚ค์ง€? ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ? ๋ชจ๋“ˆ?์€ย BeautifulSoup๋ž‘ requests, ๋””์Šคcord๋ฅผ ์‚ฌ์šฉํ• ๊ฒƒ์ด๋‹ค.


๋””์ฝ”๋ด‡์€ ์˜ˆ์ „์— c#์œผ๋กœ๋งŒ ๋งŒ๋“ค์–ด ๋ดค์—ˆ๋Š”๋ฐย ์‚ด์ง ๋ง›๋งŒ ๋ณด๋‹ˆ๊นŒ ํŒŒ์ด์ฌ์ด ํ›จ์‹  ๋” ์‰ฝ๋‹ค.



import dis/cord
import requests
from bs4 import BeautifulSoup
from dis/cord.ext import commands


bot = commands.Bot(command_prefix="!")
checked_num = 0
notify_keywords = ["์งˆ๋ฌธ", "๋‰ด๋น„", "?"]



header = {'User-Agent' : ''}

minor_ids = {'id':'game_dev'}




@bot.event
async def on_ready():
ย  ย  print(f"Logged in as {bot.user}")


@bot.command()
async def hello(ctx):
ย  ย  resp = requests.get(minor_base_url,params=minor_ids, headers=header)
ย  ย  await ctx.send(resp)

bot.run(Token)




๋Œ€์ถฉ ๋ด‡์„ ๋งŒ๋“ค๊ณ  ๋ฒ ์ด์Šค๋ฅผ ์งœ๋ดค๋‹ค.

๋””์Šค์ฝ”๋“œ ์˜์–ด๋‹จ์–ด๊ฐ€ ๊ธˆ์ง€์–ด๋กœ ๋˜์–ด์žˆ์–ด์„œ ์Šฌ๋ž˜์‹œ ์„ž์—ˆ๋‹ค.

header์™€ ๋””์ฝ”๋ด‡ ํ† ํฐ์˜ ๋‚ด์šฉ์€ ์œ ์ถœ๋˜๋ฉด ์•ˆ๋˜๋Š” ๊ฐœ์ธ์ •๋ณด๋ผ๊ณ  ํ• ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ง€์› ๋‹ค.



๋Œ€์ถฉ ์„ฑ๊ณต์„ ๋‚˜ํƒ€๋‚ด๋Š” 200์ด๋ผ๊ณ  ๋œฌ๊ฑฐ ๋ณด๋‹ˆ ์ž˜ ๋œ๊ฒƒ ๊ฐ™๋‹ค.

(์ด์ œ๋ณด๋‹ˆ๊น urlย ์ž˜๋ชป ์ผ๋Š”๋ฐ ์ด๊ฒŒ ์™œ ๋˜๋ƒ? requests ์ด์ƒˆ๋ผ ์กด๋‚˜ ์œตํ†ต์„ฑ์žˆ๋„ค)



์ด์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•ด๋ณด์ž.




F12๋ฅผ ๋ˆŒ๋Ÿฌ ๊ฐœ๋ฐœ์ž ๋ชจ๋“œ๋กœ ๋“ค์–ด๊ฐ€ ์†Œ์Šค๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด์žˆ๋Š”์ง€ ํŒŒ์•…ํ•œ๋‹ค.


datastr = ""

def ExtractNewArticle(resp):
ย  ย  soup = BeautifulSoup(resp.content, 'html.parser')
ย  ย  contents = soup.find('tbody').find_all('tr')
ย  ย  global datastr
ย  ย  for content in contents:
ย  ย  ย  ย  datastr += content.find('a').text
ย  ย  ย  ย  datastr += '\n'

ย  ย  return False



๋Œ€์ถฉ ์ฝ”๋”ฉ๊ณผย ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐ˜๋ณต ํ•ด๋ณธ๋‹ค.




5๋ฒˆ์ฏค ์‹œํ–‰์ฐฉ์˜ค๋ฅผ ํ•ด๋ณด๋‹ˆ ์ž˜ ๊ธ์–ด์™”๋‹ค.


์ด์ œย 


๊ธ€ ์ œ๋ชฉ์— ํŠน์ • ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๊ฑฐ๋‚˜ ๊ธ€๋จธ๋ฆฌ๊ฐ€ ์งˆ๋ฌธ์ธ์ง€ ์กฐ๊ฑด๋ฌธ์„ ๋งŒ๋“ค๊ณ ,


ํƒ์ƒ‰ํ•˜๊ณ  ์žˆ๋Š” ๊ธ€์ด ๊ณผ๊ฑฐ์— ์ด๋ฏธ ํƒ์ƒ‰ํ•œ ๊ธ€์ธ์ง€ ํ™•์ธํ•˜๊ณ ,


ํƒ์ƒ‰๊ฒฐ๊ณผ์— ๋ถ€ํ•ฉ๋˜๋Š”๊ฒŒ ์žˆ๋‹ค๋ฉด ๋งํฌ๋ฅผ ๋ณด๋‚ด๋ฉด ๋œ๋‹ค.


๊ทธ๋ฆฌ๊ณ  ๋ช‡์ดˆ๋งˆ๋‹ค ํ•œ๋ฒˆ์”ฉ ํ•จ์ˆ˜๋ฅผ ๋Œ๋ฆฌ๋ฉด ๋œ๋‹ค. ์ฐธ์‰ฝ์ฃ ?



def ExtractNewArticle(resp):
ย  ย  soup = BeautifulSoup(resp.content, 'html.parser')
ย  ย  contents = soup.find('tbody').find_all('tr')

ย  ย  global datastr
ย  ย  global checked_num

ย  ย  for content in contents:
ย  ย  ย  ย  gall_num = int(content.find('td', class_= 'gall_num').text)
ย  ย  ย  ย  if(gall_num <= checked_num):
ย  ย  ย  ย  ย  ย  break

ย  ย  ย  ย  is_ask_article = False
ย  ย  ย  ย  article_title = content.find('a').text

ย  ย  ย  ย  if(content.find('td',class_='gall_subject').text == '+์งˆ๋ฌธ'):
ย  ย  ย  ย  ย  ย  is_ask_article = True
ย  ย  ย  ย  else:
ย  ย  ย  ย  ย  ย  for notiword in notify_keywords:
ย  ย  ย  ย  ย  ย  ย  ย  if(article_title.find(notiword) != -1):
ย  ย  ย  ย  ย  ย  ย  ย  ย  ย  is_ask_article = True
ย  ย  ย  ย  ย  ย  ย  ย  ย  ย  break
ย  ย  ย  ย 
ย  ย  ย  ย  if(is_ask_article):
ย  ย  ย  ย  ย  ย  datastr += article_title + ' : '
ย  ย  ย  ย  ย  ย  datastr += minor_base_url + '&no='
ย  ย  ย  ย  ย  ย  datastr += str(gall_num)
ย  ย  ย  ย  ย  ย  datastr += '\n'



๋ฌธ์ œ์—†์ด ์ž˜ ๋‚˜์˜ค๋Š”๊ฒƒ ๊ฐ™....


ํ•˜! ์‹œ๋ฐœ,ย ๊ณต์ง€ํ˜•!ย ์˜ˆ์™ธ์ฒ˜๋ฆฌํ•˜๊ธฐ ๊ท€์ฐฎ๊ฒŒ ํ•˜์ง€ ๋ง๋ผ๊ณ .


๊ทธ๋ž˜๋„ ๊ฑฐ์˜ ๋‹ค์™”๋‹ค.


ย  ย  ย  ย  checked_num = gall_num
ย  ย  ย  ย  gall_subject = content.find('td',class_='gall_subject').text
ย  ย  ย  ย  if(gall_subject == '๊ณต์ง€' or gall_subject == '์„ค๋ฌธ'):
ย  ย  ย  ย  ย  ย  continue


๋Œ€์ถฉ ์˜ˆ์™ธ์ฒ˜๋ฆฌ์™€ ์ด๋ฏธ ๊ทธ ์•„๋ž˜๋กœ ํƒ์ƒ‰ํ–ˆ์œผ๋ฉด ์Šคํ‚ตํ•˜๊ฒŒ ํ–ˆ๋‹ค.


์ด์ œ ์ด ํ•จ์ˆ˜๋ฅผย ๋ช‡์ดˆ๋งˆ๋‹ค ํ•œ๋ฒˆ์”ฉ ๋Œ๋ฆฌ๋ฉด ์™„์„ฑ์ด๋‹ค.


async def my_background_task():
ย  ย  await client.wait_until_ready()
ย  ย  channel = client.get_channel(์ฑ„๋„๋ฒˆํ˜ธ) ย # channel ID goes here
ย  ย  print("Start Task")
ย  ย  while not client.is_closed():
ย  ย  ย  ย  global datastr
ย  ย  ย  ย  datastr = ''
ย  ย  ย  ย  resp = requests.get(minor_base_url,params=minor_ids, headers=header)
ย  ย  ย  ย  ExtractNewArticle(resp)

ย  ย  ย  ย  print("data : "+datastr)
ย  ย  ย  ย  if(datastr != ''):
ย  ย  ย  ย  ย  ย  await channel.send(datastr)
ย  ย  ย  ย  await asyncio.sleep(10) ย # task runs every 60 seconds




์ฒ˜์Œ ๋Œ๋ฆฐ๊ฑฐ ๋ง๊ณ  ๋‚˜์ค‘์— ์ƒˆ๋กœ ์“ด ์งˆ๋ฌธ๊ธ€๋„ ํƒ์ƒ‰๋˜๋Š”์ง€ ์‹คํ—˜ํ•ด๋ดค๋Š”๋ฐ ์ž˜๋œ๋‹ค.


์ด์ œ ์ด๊ฑธ ๋‚ด ์‹œ๋†€๋กœ์ง€ NAS ์— ๊ตฌ๋™์‹œํ‚ค๋ฉด ์ง„์งœ ๋์ด๋‹ค....








....Docker๋กœ ์ปจํ…Œ์ด๋„ˆ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๊ตฌ๋™ํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ๊ฑฐ์˜ย 1์‹œ๊ฐ„ ๋ฐ˜๋™์•ˆ ์ฐพ์•„๋ดค์ง€๋งŒย 

์ด ์ข†๋ณ‘์‹ ์ƒˆ๋ผ๋Š” ๋„์ปค๋ฅผ ์–ด๋–ป๊ฒŒ ์“ฐ๋Š”์ง€ ๋ชฐ๋ผ์„œ ๊ทธ๋ƒฅ ์Œฉ์œผ๋กœ putty๋กœ ssh ์—ฐ๊ฒฐํ•œํ›„ย nohup์œผ๋กœ ๋ด‡์„ย ๋Œ๋ ธ๋‹ค.








#๊ฒฐ๋ก 



์ตœ์ข…์ ์œผ๋กœ ์ž˜๋˜๋Š”๊ฑฐ ํ™•์ธํ–ˆ๋‹ค.


์ด์ œ ์งˆ๋ฌธ์ด ์˜ฌ๋•Œ๋งˆ๋‹ค ๋‚ด ํ๊ด€์ˆ˜๋ จ์žฅ ๋””์ฝ”์„œ๋ฒ„(์ด ๋ฉค๋ฒ„ : ๋‚˜, ๋””์ฝ”๋ด‡)์—ย ์•Œ๋ฆผ์ด ์˜ฌ๊ฒƒ์ด๋‹ค.


๊ทผ๋ฐ ์ง€๊ธˆ์€ ํ•œ์บ”๋งŒ ๋” ๋งˆ์‹œ๊ณ  ์ž˜๊บผ๋‹ˆ๊นŒ ์•Œ๋ฆผ ๊บผ๋†”์•ผ ๊ฒ ๋‹ค.


๋‚ด์ผ๋ถ€ํ„ฐ๋Š” ๋ˆ„๊ตฐ๊ฐ€ ์งˆ๋ฌธ๊ธ€์„ ์“ฐ๋ฉด ๋ˆ„๊ตฌ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ๋‹ต๋ณ€ 'ํ•  ์ˆ˜ย ์žˆ์„๊ฒƒ'์ด๋‹ค.


ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š”๋ง์€ย ํ•˜๊ฒ ๋‹ค๋Š” ๋ง์ดย ์•„๋‹ˆ๋‹ค.


ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š”๋ง์€ย ํ•˜๊ฒ ๋‹ค๋Š” ๋ง์ดย ์•„๋‹ˆ๋‹ค.


ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š”๋ง์€ย ํ•˜๊ฒ ๋‹ค๋Š” ๋ง์ดย ์•„๋‹ˆ๋‹ค.


๊นƒํ—™ :ย broken-fire-egg/DCNotifier: ๋‚˜๋งŒ์˜ ๋””์”จ์•Œ๋ฆฌ๋ฏธ ~๋ˆ„๊ตฌ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ์งˆ๋ฌธ์— ๋‹ตํ•˜๋Š” ๋ฐฉ๋ฒ•~ (github.com)


๋งˆ์น˜๋ฉด์„œย ๋‹ค์Œ ๊ธ€์€ย ๋น ๋ฅธ ์‹œ์ผ๋‚ด์—ย '๊ฒŒ์ž„'๊ฐœ๋ฐœ์ผ์ง€๋กœ ์ฐพ์•„๋ณผ์ˆ˜ ์žˆ๊ธธย ๋นˆ๋‹ค




๊ทผ๋ฐ ๋งŒ๋“œ๋Š”๋ฐ 1์‹œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ 6์‹œ๊นŒ์ง€ ์ด 5์‹œ๊ฐ„ย ๊ฑธ๋ ธ๋Š”๋ฐ ์ˆ ์„ ์•ˆ๋งˆ์‹œ๊ฑฐ๋‚˜ ์ด ๊ฐœ๋ฐœ์ผ์ง€ ์•ˆ์“ฐ๊ฑฐ๋‚˜ Docker ์“ฐ๋Š”๋ฒ•์„ ์•Œ์•˜์œผ๋ฉด ๋” ๋นจ๋ฆฌ ๋งŒ๋“ค์ง€ ์•Š์•˜์„๊นŒ?