BeautifulSoup์ Selenium์ ์ด์ฉํ์ฌ ํผํ ์จ๋ผ์ธ์ ๋ฐ์ดํฐ ์ผํฐ์์ 5์๋ถํฐ 10์๊น์ง์ ํฌ์ง์ ๋ณ ์ ์์ ์ด์ฉ์ ์ ๋ฐ์ดํฐ๋ฅผ ํฌ๋กค๋ง ํ ํ, ํผํ ์จ๋ผ์ธ์ ํฌ์ง์ ๋ณ ์ ์์ ์ ํธ๋๋ฅผ ํ์ธํ ๊ฒ์ด๋ค. ์ ์ ํฌ๋กค๋ง๋ง์ผ๋ก ํด๋น ์ฌ์ดํธ์ ๋ฐ์ดํฐ๋ฅผ ๋ค ๋ถ๋ฌ์ฌ ์ ์๊ธฐ ๋๋ฌธ์ ์ ์ ํฌ๋กค๋ง์ ์ํํ๋ BeautifulSoup์ ๋์ ํฌ๋กค๋ง์ ์ํํ๋ Selenium์ ํจ๊ป ํ์ฉํ์ฌ ํฌ๋กค๋ง์ ์ํํ์๋ค. ์ํ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
1. ๋ฐ์ดํฐ ์์ง ๊ณผ์
2. ํฌ๋กค๋ง
3. ์๊ฐํ
1. ๋ฐ์ดํฐ ์์ง ๊ณผ์
ํฌ์ง์ ๋ณ ์ ์์ ์ด์ฉ์ ์๋ฅผ ์ป๊ธฐ ์ํด์๋ ํผํ ์จ๋ผ์ธ์ ๋ฐ์ดํฐ ์ผํฐ(fifaonline4.nexon.com/datacenter/dailysquad)์ ์ ์ํ ํ, ๋ค์ ๊ณผ์ ์ ํตํด ์ํํ์ฌ์ผ ํ๋ค.
(1) ๋ ์ง ์ ํ
โท ๋นจ๊ฐ ์ ์ ํ ๋๋ฆฌ ๋ถ๋ถ์ ์ ํํ์ฌ ๋ ์ง๋ฅผ ์ง์ ํ ์ ์๋ค.
โท ๋ ์ง๋ฅผ ๋ณ๊ฒฝํ ๊ฒฝ์ฐ, ์์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๋นจ๊ฐ ์ ์ ํ ๋๋ฆฌ ๋ถ๋ถ URL์ด ๋ฐ๋๋๋ฐ, strDate์ ํ ๋น๋ ๋ ์ง๋ฅผ ๋ฐ๊พธ์ด ๋ ์ง๋ณ ๋ฐ์ดํฐ๋ฅผ ์์งํ ๊ฒ์ด๋ค.
(2) ํฌ์ง์ ์ ํ
โท ๋นจ๊ฐ ์ ์ ํ ๋๋ฆฌ ๋ถ๋ถ์ ํด๋น๋ ํญ์ ์ ํํ์ฌ, ํฌ์ง์ ๋ณ ์ ์์ ์ ๋ณด ๋ฐ ์ด์ฉ์ ์์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์๋ค.
๋ฐ์ดํฐ ์์ง ํ๋ก์ธ์ค๋ฅผ ์์ฝํ๋ฉด, ๋ ์ง๋ฅผ ์ ํํ๊ณ , ํฌ์ง์ ์ ์ ํํ ๋ค, ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์๋ค. ์ด๋, ํฌ์ง์ ํญ์ ์ ํํ ์, URL์ ๋ฐ๋์ง ์๊ณ , ์์ฒด์ ์ผ๋ก ์ฌ์ดํธ๊ฐ ๋ํ๋ด๋ ๋ฐ์ดํฐ๊ฐ ๋ฐ๋๊ฒ ๋๋ค. ๋ฐ๋ผ์ ํฌ์ง์ ๋ณ ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ป๊ธฐ ์ํด์๋ ๋์ ํฌ๋กค๋ง์ด ํ์์ ์ด๋ค.
2. ๋ฐ์ดํฐ ์์ง
In:
import pandas as pd
import time
import datetime
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
โท ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ํฌ๋กค๋ง ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ดํฐํ๋ ์์ผ๋ก ์ถ๋ ฅํ๊ธฐ ์ํ pandas, ์๊ฐ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ์ํ time๊ณผ datetime, ์ ์ ํฌ๋กค๋ง์ ์ํํ๊ธฐ ์ํ bs4, ๋์ ํฌ๋กค๋ง์ ์ํํ๊ธฐ ์ํด selenium์ ์ฌ์ฉํ์๋ค.
In:
def get_player_pref(bs, date):
sel_bs = bs.select('#divBestUsePositionPlayer')
player_pref = sel_bs[0].select('div.item_list.swiper-slide')
name, rank, overall, position, price, pay, num_user, season = list(), list(), list(), list(), list(), list(), list(), list()
order = 1
for p in player_pref:
rank.append(order)
name.append(p.find('span', {'class', 'name'}).text)
overall.append(p.find('span', {'class', 'ovr'}).text)
position.append(p.find('span', {'class', 'position'}).text.strip())
price.append(p.find('span', {'class', 'price span_bp1'}).text)
pay.append(p.find('span', {'class', 'pay'}).text)
num_user.append(p.find('p', {'class', 'txt'}).text)
temp = str(p.select('span.icon')[0].img)
temp = temp.replace('<img src="http://s.nx.com/s2/game/fo4/obt/externalAssets/season/', '')
temp = temp.replace('.png"/>', '')
season.append(temp)
order += 1
tap = bs.select_one('#middle > div > div > div.daily > div.position_pl.daily_wrap > div.position_pl__cont.content_wrap > div.position_tab > div.tab_item.active > a').text
tap = [tap for _ in range(len(name))]
date = [date for _ in range(len(name))]
df_player_pref = pd.DataFrame(tap, columns = ['tap'])
df_player_pref['date'] = date; df_player_pref['name'] = name; df_player_pref['rank'] = rank; df_player_pref['overall'] = overall; df_player_pref['position'] = position; df_player_pref['price'] = price; df_player_pref['pay'] = pay; df_player_pref['num_user'] = num_user; df_player_pref['season'] = season
return df_player_pref
โท get_player_pref ํจ์์ ์ฒซ ๋ฒ์งธ ์ธ์๋ URL์ ๋ด์ฉ์ ๋ถ๋ฌ์ค๊ณ , ๋ ๋ฒ์งธ ์ธ์๋ ํด๋น URL์ ๋ ์ง๋ฅผ ์๋ฏธํ๋ค. ํด๋น ๋ ์ง์ ๋ํ URL ์ ๋ณด๋ฅผ ๋ฐ์์, ํน์ ํฌ์ง์ ์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ ํฌ๋กค๋ง์ ์ํํ์ฌ ์ป์ ๋ค, ์ด๋ฅผ ๋ฐ์ดํฐํ๋ ์์ผ๋ก ๋ณํ ํ, ์ถ๋ ฅํ๋ค.
In:
firefox_driver = r'C:/firefoxdriver/geckodriver.exe'
driver = webdriver.Firefox(executable_path = firefox_driver)
col = ['tap', 'date', 'name', 'rank', 'overall', 'position', 'price', 'pay', 'num_user', 'season']
df_player_pref = pd.DataFrame(columns = col)
time_unit = datetime.timedelta(days = 1)
end_date = datetime.date.today()
start_date = datetime.datetime.strptime('2020-05-20', '%Y-%m-%d').date()
for i in range((end_date-start_date).days):
str_date = str(start_date+i*time_unit)
str_date = str_date.replace('-', '.')
url = 'http://fifaonline4.nexon.com/datacenter/dailysquad?strDate={}'.format(str_date)
driver.get(url)
time.sleep(5)
for j in range(1, 17):
pos_xpath = '//*[@id="middle"]/div/div/div[3]/div[7]/div[2]/div[1]/div[{}]/a'.format(j)
wait = WebDriverWait(driver, 100)
element = wait.until(EC.presence_of_element_located((By.XPATH, pos_xpath)))
pos_tab = element.find_element_by_xpath(pos_xpath)
wait = WebDriverWait(driver, 100)
element = wait.until(EC.element_to_be_clickable((By.XPATH, pos_xpath)))
driver.execute_script('arguments[0].click();', element)
time.sleep(2.5)
html = driver.page_source
bs = BeautifulSoup(html, 'lxml')
df_player_pref = pd.concat([df_player_pref, get_player_pref(bs, str_date)])
โท ๋์ ํฌ๋กค๋ง์ ์ฌ์ฉ๋๋ ๋ธ๋ผ์ฐ์ ๋ก Firefox๋ฅผ ์ ํํ์๋๋ฐ, ์ด๋ Chrome๋ณด๋ค ์๋ฌ๊ฐ ๋ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ด๋ค. Chrome ๋๋ผ์ด๋ฒ๋ ํน์ ์์๋ฅผ ์ ํํ ๋, ํญ์ ์์์ ๊ฐ์ด๋ฐ๋ง ์ ํํ๊ธฐ ๋๋ฌธ์ ๊ธฐ๋์น ๋ชปํ ์์์ ์์น์ ๋ฐ๋ผ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋๊ธฐ ๋๋ฌธ์ด๋ค.
โท ํฌ๋กค๋ง์ ์ํํ ๋, time.sleep ํจ์๋ฅผ ์ด์ฉํ์ฌ ์๊ฐ์ ์ธ ์ฌ์ ๋ฅผ ์ฃผ์๋ค. ์ฒซ ๋ฒ์งธ ์ด์ ๋ ๋ณ๊ฒฝ๋ ํ์ด๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๋๋ฐ ์ด๋ ์ ๋ ์๊ฐ์ด ๊ฑธ๋ฆฌ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ ๋ฒ์งธ ์ด์ ๋ ์๊ฐ์ ์ธ ์ฌ์ ๋ฅผ ์ฃผ์ง ์๋๋ค๋ฉด ์๋ฒ์์ DDoS ๊ณต๊ฒฉ์ผ๋ก ๊ฐ์ฃผํ๊ณ , ์ ์์ ๋ง๊ธฐ ๋๋ฌธ์ด๋ค.
โท WebDriverWair ํจ์๋ ํฌ๋กค๋ง ์์ ์ ์ํํ ๋, ํด๋น ์์ ์ด ์งํ๋ ์ ์๋๋ก ์ฌ์ ์ค๋น๊ฐ ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ฃผ๋ ์ญํ ์ ํ๋ค. ์ฒซ ๋ฒ์งธ ์ธ์๋ ์์ ์ ์ํํ๋ ๋๋ผ์ด๋ฒ, ๋ ๋ฒ์งธ ์ธ์๋ ํด๋น ์์ ์ด ์ํ๋์ง ์์์ ๋, ๊ธฐ๋ค๋ฆด ์ ์๋ ์๊ฐ์ ์๋ฏธํ๋ค. util ํจ์์ ์ธ์๋ก ์ด๋ค ์์ ์ ์ํ์ ๊ธฐ๋ค๋ฆด ๊ฒ์ธ์ง์ ๋ํ ์ ๋ณด๋ฅผ ์๋ ค์ฃผ์ด์ผ ํ๋ค.
โท ํฌ์ง์ ํญ์ ํด๋ฆญํ๋ ์์ ์ ์ํํ๊ธฐ ์ํด execute_script ํจ์๋ฅผ ์ฌ์ฉํ์๋ค. ์ด ํจ์์ ์ฒซ ๋ฒ์งธ ์ธ์๋ ์ํํ๊ณ ์ํ๋ ๋์ ์ด๋ฒคํธ์ ๋ํ ์ ๋ณด๋ฅผ, ๋ ๋ฒ์งธ ์ธ์๋ ๋๋ผ์ด๋ฒ๋ฅผ ์๋ฏธํ๋ค.
โท page_source ํจ์๋ฅผ ํตํด ๋์ ์ด๋ฒคํธ๋ฅผ ์ํํ ํ์ ํ์ด์ง๋ฅผ ์ป์ ์ ์๋ค. ์ด ๊ฒฐ๊ณผ๋ฅผ BeautifulSoup ํจ์๋ฅผ ์ด์ฉํ์ฌ ํ์ด์ง์ ๋ด์ฉ์ ์ป์ ๋ค, get_player_pref ํจ์์ ์ธ์๋ก ์ฃผ์ด, ํน์ ํฌ์ง์ ์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ดํฐํ๋ ์์ผ๋ก ์ป๋๋ค. ์ป์ ๋ฐ์ดํฐํ๋ ์์ concat ํจ์๋ฅผ ์ด์ฉํ์ฌ df_player_pref ๋ณ์์ ๋ฐ์ดํฐ๋ฅผ ์ถ์ ํ๊ฒ ๋๋ค.
โท ์ด์ค for ๋ฌธ์ ์ฒซ ๋ฒ์งธ for ๋ฌธ์์๋ ๋ ์ง๋ฅผ ์ ํํ๊ณ , ๋ ๋ฒ์งธ for ๋ฌธ์์๋ ํฌ์ง์ ์ ์ ํํ์ฌ, 5์ 20์ผ๋ถํฐ ํ์ฌ๊น์ง์ ๋ชจ๋ ํฌ์ง์ ์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์๋ค.
In:
df_player_pref.to_csv('../input/player_preference.csv', encoding = 'utf-8-sig')
โท ํฌ๋กค๋ง ์์ ์ด ๋๋ ํ, ์์ฑ๋ ๋ฐ์ดํฐํ๋ ์์ csv ํํ๋ก ์ ์ฅํ๋ค.
์ ์ฒ๋ฆฌ๋ฅผ ์ํํ ํ์ ์์ฑ๋ ๋ฐ์ดํฐํ๋ ์์ ๋ค์๊ณผ ๊ฐ๋ค.
4. ์๊ฐํ
์ฝ 5๊ฐ์๋์ ์ ์ ์ ์ ์๋ณ ์ด์ฉ์ ์ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ์ฌ, ํฌ์ง์ ๋ณ ์ ์์ ์ ํธ๋๋ฅผ ์๊ฐํํ์ฌ ๋ณด์. ์๊ฐํ๋ R์ ์ด์ฉํ์ฌ ์ํํ์๋ค.
In:
#####################
# Library & Setting #
#####################
library(readr)
library(ggplot2)
library(scales)
library(dplyr)
library(forcats)
library(stringr)
library(tidytext)
library(showtext)
font_add_google('Nanum Gothic', 'Gothic')
showtext_auto()
theme_set(theme_minimal() +
theme(plot.title = element_text(face = 'bold', colour = 'grey10'),
plot.subtitle = element_text(colour = 'grey25'),
panel.grid.major = element_line(colour = 'grey90', size = 1),
panel.grid.minor = element_line(colour = 'grey80', size = 0.5, linetype = 'dashed'),
legend.position = 'top',
legend.spacing.x = unit(0.125, 'cm'),
legend.background = element_rect(fill = NULL, linetype = 'dotted'),
strip.background = element_blank(),
strip.text = element_text(face = 'bold', colour = 'grey25', size = 11.25)))
################################
# Data Loading & Preprocessing #
################################
df_player = read_csv('C:/Users/user/Desktop/Project/Player_Preference_Analysis/Data/player_preference.csv') %>%
select(-X1)
df_player$price = gsub(',', '', df_player$price)
df_player$price = gsub(' ', '', df_player$price)
df_player$price = as.numeric(gsub('BP', '', df_player$price))
df_player$num_user = gsub(',', '', df_player$num_user)
df_player$num_user = lapply(str_extract_all(df_player$num_user, '[0-9]+'), function(x) x[1]) %>%
unlist() %>%
as.numeric()
df_player$date = as.Date(df_player$date, '%Y.%m.%d')
#######
# EDA #
#######
# player preference
df_temp = df_player %>%
group_by(tap, name, season) %>%
summarise(total_num_user = sum(num_user)) %>%
arrange(tap, -total_num_user)
length(unique(df_player$position))
FWD = c('CF', 'LW', 'RW', 'ST')
MID = c('CAM', 'CDM', 'CM', 'LM', 'RM')
DEF = c('CB', 'LB', 'LWB', 'RB', 'RWB')
df_temp$position = ifelse(df_temp$tap %in% FWD, 'FWD',
ifelse(df_temp$tap %in% MID, 'MID',
ifelse(df_temp$tap %in% DEF, 'DEF',
ifelse(df_temp$tap %in% 'GK', 'GK', 'Total'))))
df_temp$rank = 0
tap = unique(df_temp$tap)
for (i in tap) {
df_temp[df_temp$tap == i, 'rank'] = rank(-df_temp$total_num_user[df_temp$tap == i])
}
df_temp$season_name = paste(df_temp$name, '/', df_temp$season)
df_temp %>%
filter(rank <= 10, position == 'FWD') %>%
mutate(season_name = reorder_within(season_name, total_num_user, tap)) %>%
ggplot(aes(fct_reorder(season_name, total_num_user), total_num_user)) +
geom_bar(stat = 'identity', colour = 'red', fill = 'red', alpha = 0.5, size = 1) +
scale_y_continuous(label = comma) +
facet_wrap(~ tap, scales = 'free') +
coord_flip() +
scale_x_reordered() +
labs(x = NULL, y = 'Num. of Users')
df_temp %>%
filter(rank <= 10, position == 'MID') %>%
mutate(season_name = reorder_within(season_name, total_num_user, tap)) %>%
ggplot(aes(fct_reorder(season_name, total_num_user), total_num_user)) +
geom_bar(stat = 'identity', colour = 'green', fill = 'green', alpha = 0.5, size = 1) +
scale_y_continuous(label = comma) +
facet_wrap(~ tap, scales = 'free') +
coord_flip() +
scale_x_reordered() +
labs(x = NULL, y = 'Num. of Users') +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
df_temp %>%
filter(rank <= 10, position == 'DEF') %>%
mutate(season_name = reorder_within(season_name, total_num_user, tap)) %>%
ggplot(aes(fct_reorder(season_name, total_num_user), total_num_user)) +
geom_bar(stat = 'identity', colour = 'blue', fill = 'blue', alpha = 0.5, size = 1) +
scale_y_continuous(label = comma) +
facet_wrap(~ tap, scales = 'free') +
coord_flip() +
scale_x_reordered() +
labs(x = NULL, y = 'Num. of Users') +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
df_temp %>%
filter(rank <= 10, position == 'GK') %>%
ggplot(aes(fct_reorder(season_name, total_num_user), total_num_user)) +
geom_bar(stat = 'identity', colour = 'black', fill = 'black', alpha = 0.5, size = 1) +
scale_y_continuous(label = comma) +
facet_wrap(~ tap, scales = 'free') +
coord_flip() +
scale_x_reordered() +
labs(x = NULL, y = 'Num. of Users')
df_temp %>%
filter(rank <= 10, position == 'Total') %>%
ungroup() %>%
mutate(tap = 'Total') %>%
mutate(season_name = reorder_within(season_name, total_num_user, tap)) %>%
ggplot(aes(fct_reorder(season_name, total_num_user), total_num_user)) +
geom_bar(stat = 'identity', colour = 'grey', fill = 'grey', alpha = 0.5, size = 1) +
scale_y_continuous(label = comma) +
facet_wrap(~ tap, scales = 'free') +
coord_flip() +
scale_x_reordered() +
labs(x = NULL, y = 'Num. of Users')
Out:
โท ์ ์ ์ ์๋ ๊ฐ ์ ์๋ณ ์ ์ ์์ ์ด ํฉ์ ์๋ฏธํ๋ค.
โท ์ํฅ๋ฏผ ์ ์๊ฐ CF, LW, RW, LM, RM์์ ์์๊ถ์ ์์นํ ๊ฒ์ ์ ์ ์๋ค. ์ฆ, FIFA ์จ๋ผ์ธ์์ "์๋ ํด๋์ค"๋ก ๋ถ๋ฅํ ์ ์์ ๊ฒ์ด๋ค. ํจ๋ถ๋ฅดํฌ ์์ ๋ถํฐ ๋ชจ๋ ๊ณจ์ ์ง์ผ๋ณธ ํฌ์ผ๋ก์ ๋ชน์ ํ๋ญํ ๊ฒฐ๊ณผ๊ฐ ์๋ ์ ์๋ค.
์ ์ ๋ค์ด ์ ํธํ๋ ์์ฆ์ ์์๋ณด์.
In:
df_player %>%
filter(tap != '์ ์ฒด') %>%
group_by(season) %>%
summarise(total_num_user = sum(num_user)) %>%
arrange(-total_num_user) %>%
ggplot(aes(reorder(season, total_num_user), total_num_user)) +
geom_bar(stat = 'identity', colour = 'steelblue', fill = 'steelblue', alpha = 0.5, size = 1) +
scale_y_continuous(label = comma) +
coord_flip() +
labs(x = NULL, y = 'Num. of Users')
Out:
โท ์ ์ ์ ์๋ ๊ฐ ์์ฆ์ ์ ์๋ฅผ ์ฌ์ฉํ๋ ์ ์ ์ ์ ์ด ํฉ์ ์๋ฏธํ๋ค.
ํฌ์ง์ ๋ณ ์ ์ ์ ์ ์ ๊ฐ์น๋ฅผ ์์๋ณด์.
In:
df_player %>%
filter(tap != '์ ์ฒด') %>%
mutate(all_price = price*num_user,
position_cat = if_else(tap %in% FWD, 'FWD',
if_else(tap %in% MID, 'MID',
if_else(tap %in% DEF, 'DEF', 'GK')))) %>%
group_by(tap, position_cat) %>%
summarise(total_price = sum(all_price),
total_num_user = sum(num_user)) %>%
mutate(mean_price = total_price/total_num_user) %>%
ggplot(aes(reorder(tap, mean_price), mean_price)) +
geom_bar(stat = 'identity', aes(colour = position_cat, fill = position_cat), alpha = 0.5, size = 1) +
scale_y_continuous(label = comma) +
scale_colour_manual(values = c('blue', 'red', 'black', 'green')) +
scale_fill_manual(values = c('blue', 'red', 'black', 'green')) +
labs(x = NULL, y = 'Price', fill = NULL, colour = NULL) +
coord_flip() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Out:
โท ์์ ๊ฐ๊ฒฉ์ ํ ๋ช ์ ์ ์ ๊ฐ ๊ฐ ํฌ์ง์ ์ ์ฌ์ฉํ๋ ๊ธ์ก์ ํ๊ท ์ ์๋ฏธํ๋ค.
โท ์์๋๋ก ํฌ์๋, ๋ฏธ๋ํ๋, ์๋น์, ๊ณจํคํผ ์์ผ๋ก ๊ฐ์น๊ฐ ๋์ ๊ฒ์ ํ์ธํ ์ ์๋ค. ํนํ ๊ณจ์ ๊ฐ์ฅ ๋ง์ด ๋ฃ๋ ST, CF์ ๊ฐ์น๊ฐ ์๋์ ์ผ๋ก ๋์ ๊ฒ์ ์ ์ ์๋ค.
'Programming > Python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
BeautifulSoup๋ฅผ ํ์ฉํ ํฌ๋กค๋ง (0) | 2020.10.10 |
---|---|
ํด๋์ค(Class)์ ์ธ์ ๋ฐ ๋ฉ์๋(Method) (0) | 2020.07.26 |