1. 개념
동일한 키워드를 가지는 신문 기사를 논조가 다른 신문사에서 가져와 사용된 단어를 워드 클라우드로 시각화하여 분석합니다.
키워드는 '사드'를 사용하고, 신문사는 동아일보, 한겨레신문 두 신문사에서 각각 150개씩 기사를 사용합니다.
[결과]
키워드가 '사드'인 만큼, 워드 클라우드 모양을 미사일로 만들어 보았으며,
워드 클라우드를 살펴보면 '중국'과 '미국'을 가장 많이 사용했음을 알 수 있다.
분석환경은 파이썬 3.6.2버전을 사용하였으며 사용된 소스 코드는 다음과 같다.
1) [output_cleand.txt]
2) [output.txt]
3) [result_acticls1.txt]
4) [result_acticles.txt]
5) [words_rsult.txt]
6) [words_rsult1.txt]
7) [words.py]
8) [article_crawling.py]
9) [article_crawling1.py]
10) [cleaner.py]
11) [crawling.py]
2. 네이버 뉴스 크롤링
신문에서 특정 키워드를 포함하는 기사를 가져오기 전 예제로 네이버 포털의
뉴스기사를 가져오는 방법을 먼저 실습합니다.
"""네이버 뉴스 기사 웹 크롤러 모듈"""
from bs4 import BeautifulSoup
import urllib.request
# 출력 파일 명
OUTPUT_FILE_NAME = 'output.txt'
# 긁어 올 URL
URL = 'http://news.naver.com/main/read.nhn?mode=LSD&mid=shm&sid1=103&oid=055'
\'&aid=0000445667'
# 크롤링 함수
def get_text(URL):
source_code_from_URL = urllib.request.urlopen(URL)
soup = BeautifulSoup(source_code_from_URL, 'lxml', from_encoding='utf-8')
text = ''
for item in soup.find_all('div', id='articleBodyContents'):
text = text + str(item.find_all(text=True))
return text
# 메인 함수
def main():
open_output_file = open(OUTPUT_FILE_NAME, 'w', encoding='utf-8')
result_text = get_text(URL)
open_output_file.write(result_text)
open_output_file.close()
if __name__ == '__main__':
main()
위 코드는 네이버 뉴스를 가져오기 위한 크롤러 모듈이다.
코드를 하나하나 분석해 본다.
"""네이버 뉴스 기사 웹 크롤러 모듈"""
from bs4 import BeautifulSoup import urllib.request |
크롤링을 하기 위해 두 가지 라이브러리를 import 하였으며,
HTTP REQUEST를 보내고 HTTP RESPONSE를 받기 위한 urllib과 urllib을 통해
받은 RESPONSE(HTML)를 파싱하기 위한 Beautiful Soup이다.
urllib, Beautiful Soup이 import되지 않는다면 해당 라이브러리를 먼저 설치하여야 한다.
# 출력 파일 명 OUTPUT_FILE_NAME = 'output.txt' # 가져 올 URL URL = 'http://news.naver.com/main/read.nhn?mode=\ LSD&mid=shm&sid1=103&oid=055'\'&aid=0000445667' |
기사 내용을 가져와 저장할 파일명과 가져 올 기사의 URL 주소를 상수로 할당했다.
URL 주소를 백슬래시(\)를 사용해 두 줄로 나누었는데, 이는 한 행이 80자가 넘어가는 것을 방지하기 위해서이다.
신문기사 URL 주소는 크롤링하길 원하는 뉴스 기사의 URL 주소를 복사해 오면된다.
네이버 뉴스에서 동영상이 포함된 일기예보 기사를 골라 복사하였으며, 동영상이 포함된 기사였지만 일기예보 내용이 텍스트로 본문에 포함되어 있으므로 해당 기사의 본문 내용(텍스트)만 가져오도록 한다.
# 크롤링 함수 def get_text(URL): source_code_from_URL = urllib.request.urlopen(URL) soup = BeautifulSoup(source_code_from_URL, 'lxml', from_encoding='utf-8') text = '' for item in soup.find_all('div', id='articleBodyContents'): text = text + str(item.find_all(text=True)) return text |
위는 해당 URL 주소로 요청을 보내고 받아 기사 내용을 파싱해 하나의 문자열로 저장하는 함수이다.
위 코드에서 청색 코드 부분의 urlopen 메소드를 통해 URL 주소에 대한 요청을
보내 source_code_from_URL 변수에 결과를 저장한다.
결과 저장 후 HTML 코드를 파싱하기 위해 빨강색 코드의 source_from_URL을
이용하여 BeautifulSoup 객체를 생성하여 soup에 할당한다.
BeautifulSoup 객체 생성자의 2번째 인자로 ‘lxml'을 사용하여 기존 ’html'
방식 대신 ‘lxml' 방식으로 파싱하였으며, 한글 내용이 포함된 기사이기 때문
에 from_encoding 키워드 인자로 ’utf-8'을 넣어 ‘UTF-8' 방식으로 인코딩하
였다.
단, ‘lxml' 방식으로 BeautifulSoup 객체를 생성할 때 오류가 발생하면
’lxml' 라이브러리를 설치한다.
이후, soup 객체에서 원하는 부분(HTML 요소)만 가지고 와야 하므로 가지고 올
기사의 본문 내용이 포함된 태그(HTML 요소)가 무엇인지를 찾아야 한다.
예를 들어,
다음과 같이 크롬 개발자 도구를 이용하여 신문기사 페이지의 본문 내용이
포함된 태그를 찾으면 된다.
코드를 확인해 보면,
본문 내용은 id가 ‘articleBodyContents'인 ’div' 클래스 안에 담겨 있음을 알
수 있으므로 앞서 생성한 객인 soup에서 ‘div' 클래스를 가져오면 된다.
앞서 작성한 다음 코드의 text 부분을 활용한다.
# 크롤링 함수 def get_text(URL): source_code_from_URL = urllib.request.urlopen(URL) soup = BeautifulSoup(source_code_from_URL, 'lxml', from_encoding='utf-8') text = '' for item in soup.find_all('div', id='articleBodyContents'): text = text + str(item.find_all(text=True)) return text |
우선, 본문 내용을 저장하기 위해 text에 빈 문자열을 할당한다.
다음은 soup 객체의 find_all 메소드를 이용하여 id가 ‘articleBodyContents'
인 ’div' 클래스를 모두 뽑아 내고 for문을 통해 뽑아낸 요소 하나하나에
다시 직접 접근한다.
for문으로 뽑아진 각 요소 item에 find_all 메소드를 사용하여 text 키워드
인자에 True를 넣어 텍스트 요소만 뽑아 문자열로 치환한 후 text 문자열에
이어 붙인다.
그 다음은 text를 반환한다.
본문 내용이 포함된 요소가 ‘div' 클래스 하나인데, for문을 사용한 이유는
첫 번째, find_all 메소드의 반환 객체가 인자로 주어진 조건을 만족하는 모든
요소들을 순환 가능한 객체로 주어지기 때문에 사용하였으며,
두 번째, 다른 신문사의 경우 본문 내용이 동일한 id를 갖는 동일한 여러 개의
태그에 나눠야 할당되어 있는 경우도 있기 때문이다.
다음으로,
위에서 작성한 코드에 이어서
메인 함수를 별도로 만들고 __name__을 이용하여 main 함수를 실행시킨다.
# 메인 함수 def main(): open_output_file = open(OUTPUT_FILE_NAME, 'w') result_text = get_text(URL) open_output_file.write(result_text) open_output_file.close()
if __name__ == "__main__': main() |
메인 함수에서는 위에서 할당한 OUTPUT_FILE_NAME 상수를 통해 txt 파일을 생성
하고 get-text 함수를 사용하여 기사 내용을 result_text에 할당한다.
다음으로 오픈한 output_file에 기사를 쓰고 닫았다.
CMD 창에서 클롤러 모듈을 실행하여 ‘output.txt' 파일이 생성 되는지 확인한
다.
C:\~python3>python3 crawler.py
C:\~python3>dir
생성된 텍스트 파일(output.txt)을 열어서 신문기사 내용이 정상적으로 가져왔
는지 확인한다.
다만, ‘\n', '\t' 등의 문자와 워드 클라우드 시각화에 필요 없는 특수문자는
제거해야 하므로 텍스트 정제 모듈을 따로 만들어 추출된 기사에서 필요 없는
문자를 제거한다.
[텍스트 정제 모듈]
import re #정규표현식 활용 위해 re 라이브러리 import
# 입, 출력 파일명
INPUT_FILE_NAME = 'output.txt'
OUTPUT_FILE_NAME = 'output_cleand.txt'
# 클리닝 함수
def clean_text(text):
cleaned_text = re.sub('[a-zA-Z]', '', text) # 대소문자 영어 제거
cleaned_text = re.sub('[\{\}\[\]\/?.,;:|\)*
~`!^\-_+<>@\#$%&\\\=\(\'\"]', '', cleaned_text) # 특수문자 제거
return cleaned_text
# 메인 함수
def main():
read_file = open(INPUT_FILE_NAME, 'r')
write_file = open(OUTPUT_FILE_NAME, 'w')
text = read_file.read()
text = clean_text(text)
write_file.write(text)
read_file.close()
write_file.close()
if __name__ == '__main__':
main()
CMD 창에서 위 코드(정제 모듈)를 실행한다.
C:\~python3>python3 cleaner.py
C:\~python3>dir
실행 후 ‘output_cleand.txt' 파일이 생성되었는지 확인한다.
output_cleand.txt' 파일을 열어 영어와 불필요한 문자들이 제거되었는지 확인한
다.
3. 동아 및 한겨레 신문에서
‘사드’ 관련 신문기사 크롤링
동아 및 한겨레 신문에서 특정 키워드와 관련된 신문기사의 본문 내용을 대량으로 가져오는 크롤러를 다음과 같은 과정으로 만든다.
1) 특정 키워드를 통해 싱ㄴ문 기사를 검색해 관련된 기사 목록을 얻어온다.
2) 신문사의 기사 목록 페이지의 URL 주소 패턴을 분석하여 반복문으로 여러 목록
페이지를 검색하여 올라와 있는 기사 제목에 연결된 모든 링크 주소(기사 본문
URL)를 얻어온다.
3) 얻어낸 기사의 링크 주소 하나하나에 접근하여 기사 본문 내용이 담긴 HTML
요소를 찾아 해당 요소만 가져와 본문 내용을 하나의 파일에 저장한다.
[article_crawling.py]
import sys
from bs4 import BeautifulSoup
import urllib.request
from urllib.parse import quote
TARGET_URL_BEFORE_PAGE_NUM = "http://news.donga.com/search?p="
TARGET_URL_BEFORE_KEWORD = '&query='
TARGET_URL_REST =
'&check_news=1&more=1&sorting=3&search_date=1&v1=&v2=&range=3'
# 기사 검색 페이지에서 기사 제목에 링크된 기사 본문 주소 받아오기
def get_link_from_news_title(page_num, URL, output_file):
for i in range(page_num):
current_page_num = 1 + i*15
position = URL.index('=')
URL_with_page_num = URL[: position+1] + str(current_page_num) \
+ URL[position+1 :]
print("URL_with_page_num", URL_with_page_num)
source_code_from_URL =
urllib.request.urlopen(URL_with_page_num)
soup = BeautifulSoup(source_code_from_URL, 'lxml',
from_encoding='utf-8')
for title in soup.find_all('p', 'tit'):
title_link = title.select('a')
article_URL = title_link[0]['href']
get_text(article_URL, output_file)
# 기사 본문 내용 가져오기
(우 함수 내부에서 기사 본문 주소 받아 사용되는 함수)
def get_text(URL, output_file):
source_code_from_url = urllib.request.urlopen(URL)
soup = BeautifulSoup(source_code_from_url, 'lxml',
from_encoding='utf-8')
content_of_article = soup.select('div.article_txt')
for item in content_of_article:
string_item = str(item.find_all(text=True))
output_file.write(string_item)
# 메인함수
def main(argv):
if len(argv) != 4:
print("python [Module Name] [Keyword] [Take page number]
[Result file]")
return
keyword = argv[1]
page_num = int(argv[2])
output_file_name = argv[3]
target_URL = TARGET_URL_BEFORE_PAGE_NUM + TARGET_URL_BEFORE_KEWORD \
+ quote(keyword) + TARGET_URL_REST
output_file = open(output_file_name, 'w')
get_link_from_news_title(page_num, target_URL, output_file)
output_file.close()
if __name__ == '__main__':
main(sys.argv)
위 코드를 분석한다.
import sys
from bs4 import BeautifulSoup
import urllib.request
from urllib.parse import quote
위 부분은 해당 모듈에서 크롤링을 위해 사용할 라이브러리를 import한다.
해당 모듈을 실행할 때 사용자로부터 인자를 받기 위해 ‘sys.argv'를 사용하려고 ’sys'를 import한다.
요청을 보내고 응답을 받기 위해 ‘urllib'을, 받은 응답(HTML 코드)를 파싱하기 위해 ’BeautifulSoup‘을 import한다.
또한, quote는 urlopen에서 인자로 사용되는 URL 주소에 한글(UTF-8)이 포함되었을 때 이를 ASCII 형식으로 바꿔주기 위한 함수이다.
TARGET_URL_BEFORE_PAGE_NUM = "http://news.donga.com/search?p="
TARGET_URL_BEFORE_KEWORD = '&query='
TARGET_URL_REST =
'&check_news=1&more=1&sorting=3&search_date=1&v1=&v2=&range=3'
위 코드는‘urlopen'으로 요청을 보낼 타겟 주소를 세 부분으로 나누어 상수에 할당한 것이다.
위와 같이 동아일보 홈페이지에서 URL 패턴을 찾기 위해 검색 키워드로
‘사드’를 검색한다.
기사 내용 중 ‘사드’ 관련 기사만 필요하므로 검색 필터를 사용하여
[정확도순]-[동아일보]-[전체]로 다시한번 더 검색한다.
웹동아일보에서 총2800여건이 검색되고 첫 화면에 5개의 기사가 표시되고 더
많은 기사를 보기 위해 주황색으로 링크된 더보기를 클릭한다.
더보기를 클릭하면 다음과 같이 한 페이지당 15개씩 게시글이 표시된다.
위 페이지의 URL 주소를 확인해 본다.
URL을 세분해 보면,
‘check_news=1'은 뉴스로 한정지은 것이고 ’more=1'은 더보기를 누른 상태이
고 ‘sorting=3'과 ’range=3'은 각각 정확도순 정렬과 전체검색기간을,
‘query=%EC~'는 검색한 키워드를 16진수 형식으로 표시한 것이다.
다음은,
화면 하단의 페이지 숫자를 클릭하여 2페이지로 이동한다.
두 번째 페이지로 이동한 후 URL 주소를 보면 URL 주소가 달라졌다.
첫 번째 화면의 query=%EC~'위치가 앞쪽으로 이동하였으며 페이지 숫자로 추정되
는 ‘p=16'이 표시되어 있다.
이유를 확인하기 위해 화면 하단의 전/후 페이지 숫자를 클릭하고 URL 부분을 보
면 ‘p=숫자’ 형식으로 표시되는 것을 확인할 수 있다.
즉, 기사의 개수가 한 페이지에 15개 이므로 페이지가 이동될 때마다 p의 값이
15씩 늘어나거나 줄어드는 것을 확인할 수 있다.
결론적으로,
TARGET_URL_BEFORE_PAGE_NUM = "http://news.donga.com/search?p="
TARGET_URL_BEFORE_KEWORD = '&query='
TARGET_URL_REST =
'&check_news=1&more=1&sorting=3&search_date=1&v1=&v2=&range=3'
‘사드’를 통해 검색된 기사 목록 전체를 확인하기 위해서는 ‘query=사드’로
설정되어야 하며, 페이지 번호를 ‘p=1', 'p=10',...과 같이 원하는 페이지를
나타내는 수 만큼 변경시켜가며 둘러봐야 하는 것이다.
따라서, 위 코드처럼 페이지를 나타내는 ‘p=' 부분과 검색 키워드를 나타내는
’&query=' 부분의 정보를 사용자로부터 입력받아 하나의 타겟 주소로 결합하기
위해 위 코드를, 즉 타겟 주소 부분을 세 부분으로 나눈 것ㅇ니다.
타겟 주소가 결합되어지는 메인 함수 부분 코드를 분석한다.
# 메인함수
def main(argv):
if len(argv) != 4:
print("python [Module Name] [Keyword] [Take page number]
[Result file]")
return
keyword = argv[1]
page_num = int(argv[2])
output_file_name = argv[3]
target_URL = TARGET_URL_BEFORE_PAGE_NUM + TARGET_URL_BEFORE_KEWORD \
+ quote(keyword) + TARGET_URL_REST
output_file = open(output_file_name, 'w')
get_link_from_news_title(page_num, target_URL, output_file)
output_file.close()
if __name__ == '__main__':
main(sys.argv)
위와 같은 메인 코드는,
‘sys.argv'를 통해 사용자로부터 검색 키워드, 페이지 숫자, 결과 파일명을 각
각 ’keyword', 'page_num', 'output_file_name'에 입력하였다.
단, 'page_num'은 정수형을 사용해야 하므로 int형으로 변환한 것이다.
이후,
target_URL 변수에 모듈 위에서 정의해 놓은 URL 상수들을 사용자로부터 입력
받은 정보와 결합시킨다.
이때, ‘TARGET_URL_BEFORE_PAGE_NUM' 뒤에 사용자로부터 입력받은 페이지
숫자를 결합하지는 않고 검색 키워드인 ’keword'만
‘TARGET_URL_BEFORE_KEWORD' 뒤에 ’quote'(urllib.parse의 메소드)메소드만
사용하여 결합한다.
‘quote' 메소드를 ’keword'에 사용하는 이유는 검색할 때 사용하는 언어가
대부분 한글(UTF-8)이기 때문이다.
URL 주소에는 ‘ASCII' 표현 방식 이외의 문자표기법은 사용될 수 없기 때문에
’사드‘라는 ’UTF-8' 방식의 문자를 ‘ASCII' 방식으로 변환해야 하기 때문
에 ’quote' 메소드를 ‘keword'에 사용한다.
이와 같이 완성된 타겟 주소를 ‘get_link_from_news_title' 함수를 이용하여
기사를 크롤링하여 파일로 저장한다.
# 기사 검색 페이지에서 기사 제목에 링크된 기사 본문 주소 받아오기
def get_link_from_news_title(page_num, URL, output_file):
for i in range(page_num):
current_page_num = 1 + i*15
position = URL.index('=')
URL_with_page_num = URL[: position+1] + str(current_page_num) \
+ URL[position+1 :]
print("URL_with_page_num", URL_with_page_num)
source_code_from_URL =
urllib.request.urlopen(URL_with_page_num)
soup = BeautifulSoup(source_code_from_URL, 'lxml',
from_encoding='utf-8')
for title in soup.find_all('p', 'tit'):
title_link = title.select('a')
article_URL = title_link[0]['href']
get_text(article_URL, output_file)
위 코드의 함수는 메인 함수에서 클롤링하기 위한 함수인
‘get_link_from_news_title' 함수이다.
인자로는 크롤링해 올 기사 목록 수인 page_num과 타겟 주소인 URL, 그리고
본문 내용을 저장할 결과 파일명인 ‘output_file'을 인자로 받는다.
함수 안 첫 번째 반복문(for)은 여러 기사 목록을 돌며 기사 제목에 링크된
기사 본문 주소(URL 주소)를 얻어 오는 부분이다.
이 반복문에서는 기사를 가져올 페이지 수만큼 코드를 반복한다.
‘current_page_num'에 ’i'를 이용하여 가져올 페이지 수만큼의 현재 페이지를
만든다.
(i=0 일때 current_page_num=1, i=1일 때 current_page_num=16,....)
그 후,
인자로 받은 URL에서 첫 번째로 ‘=’문자가 나오는 위치를 ‘position'에 할당
한 후 해당 ’position' 뒤에 ‘current_page_num’을 스트링으로 변환한 후
삽입한다.
이렇게 만들어진 ‘URL_with_page_num'을 이용하여 ’urlopen'으로 요청을 하고
응답을 받아 ‘BeautifulSoup' 객체인 ’soup'을 만든다.
개발자 도구를 사용하여 첫 번째 기사의 제목(링크) 부분이 어디인지 찾아본다.
class가 ‘tit'인 p 태그 안의 첫 번째 a 태그에 연결된 URL 주소가 해당 기사
본문 URL가 포함된 것을 확인할 수 있다.
따라서,
위에서 만든 ‘soup' 객체에서 class='tit'인 p 태그를 모두 가져와 그 안에
있는 첫 번째 a 태그의 ’href'의 내용을 가져오면 모든 기사의 내용을 크롤링
할 수 있다.
for title in soup.find_all('p', 'tit'):
title_link = title.select('a')
article_URL = title_link[0]['href']
get_text(article_URL, output_file)
위 코드에서 생성한 ‘soup' 객체에서 ’find_all' 메소드를 통해 class가
‘tit'인 p 태그를 모두 가져와 반복문을 통해 ’title'에 하나씩 할당했으며
‘select' 메소드를 통해 모든 a 태그를 ’title_link'에 저장했다.
2개의 반복문을 통해 최종적으로 얻어진 기사 본문 URL 주소를 ‘get_text'
함수에 결과 파일명과 함께 전달한다.
‘get_text' 메소드는 실제적으로 각 기사의 본문 내용을 크롤링해오는 함수이
다.
# 기사 본문 내용 가져오기
#(우 함수 내부에서 기사 본문 주소 받아 사용되는 함수)
def get_text(URL, output_file):
source_code_from_url = urllib.request.urlopen(URL)
soup = BeautifulSoup(source_code_from_url, 'lxml',
from_encoding='utf-8')
content_of_article = soup.select('div.article_txt')
for item in content_of_article:
string_item = str(item.find_all(text=True))
output_file.write(string_item)
위 코드는 기사 본문 주소를 받아 본문 내용을 가져오는 ‘get_text' 함수이다.
이 함수는 기사 URL 주소를 통해 응답을 받아 ‘BeautifulSoup' 객체를 만들고
본문을 추출해 결과 파일에 동작을 한다.
CMD 창을 통해 크롤러 모듈을 실행하여 사드 관련 기사를 10페이지(150개)를
크롤링해 결과 파일을 ‘result_articles.txt'에 저장한다.
또한,
한겨레신문에서 기사를 크롤링해 오는 방법 또한 동아일보에서 크롤링해오는
방법과 동일하며, 다만 한겨레 신문에서 사용하는 별도의 URL 패턴이 있을 것이
며 기사 본문 내용을 구성하는 HTML 코드 또한 동아일보와 다를 것이므로 크롤
러 모듈에서 해당 사항만 한겨레 신문에 맞도록 변경하면 된다.
다음 코드는 한겨레 신문에서 크롤링하는 코드이다.
import sys
from bs4 import BeautifulSoup
import urllib.request
from urllib.parse import quote
TARGET_URL_BEFORE_KEYWORD = 'http://search.hani.co.kr/Search?command=query&' \
'keyword='TARGET_URL_BEFORE_UNTIL_DATE =
'&media=news&sort=s&period=all&datefrom=' \
'2017.01.01&dateto='TARGET_URL_REST = '&pageseq='
def get_link_from_news_title(page_num, URL, output_file):
for i in range(page_num):
URL_with_page_num = URL + str(i)
source_code_from_URL =
urllib.request.urlopen(URL_with_page_num)
soup = BeautifulSoup(source_code_from_URL, 'lxml',
from_encoding='utf-8')
for item in soup.select('dt > a'):
article_URL = item['href']
get_text(article_URL, output_file)
def get_text(URL, output_file):
source_code_from_URL = urllib.request.urlopen(URL)
soup = BeautifulSoup(source_code_from_URL, 'lxml',
from_encoding='utf-8')
content_of_article = soup.select('div.text')
for item in content_of_article:
string_item = str(item.find_all(text=True))
output_file.write(string_item)
def main(argv):
if len(sys.argv) != 5:
print("python [모듈이름] [키워드] [가져올 페이지 숫자] "
"[가져올 기사의 최근 날짜] [결과 파일명.txt]")
return
keyword = argv[1]
page_num = int(argv[2])
until_date = argv[3]
output_file_name = argv[4]
target_URL = TARGET_URL_BEFORE_KEYWORD + quote(keyword) \
+ TARGET_URL_BEFORE_UNTIL_DATE + until_date +
TARGET_URL_REST
output_file = open(output_file_name, 'w')
get_link_from_news_title(page_num, target_URL, output_file)
output_file.close()
if __name__ == '__main__':
main(sys.argv)
'Language > Python' 카테고리의 다른 글
파이참 pycharm 설치방법 (0) | 2020.02.28 |
---|---|
파이썬 python 3.8.2 설치 (0) | 2020.02.28 |
파이썬을 활용한 웹 크롤링_기본편 (0) | 2020.02.26 |
Python에서 Excel 사용 (0) | 2020.02.26 |
파이썬 - 함수와 모듈 (0) | 2020.02.26 |