본문 바로가기

Tensorflow

네이버 뉴스 크롤링하기 (퍼옴)


네이버 뉴스 크롤링하기


이번 글에서는 동아일보와 한겨레신문에서 특정 키워드를 포함하는 기사를 긁어오기 전 예제로 네이버포털의 뉴스기사를 긁어 오는 것을 먼저 연습하도록 하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
"""네이버 뉴스 기사 웹 크롤러 모듈"""
 
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')
    result_text = get_text(URL)
    open_output_file.write(result_text)
    open_output_file.close()
    
 
if __name__ == '__main__':
    main()
cs

위 코드는 네이버뉴스를 긁어오기 위한 크롤러 모듈 입니다.

그럼 코드를 하나하나 살펴보도록 하겠습니다.



1
2
3
4
5
"""네이버 뉴스 기사 웹 크롤러 모듈"""
 
from bs4 import BeautifulSoup
import urllib.request
 
cs
크롤링을 하기 위해 두 가지 라이브러리를 임포트했습니다.

HTTP REQUEST를 보내고 HTTP RESPONSE를 받기 위한 urllib과 

urllib을 통해 받은 RESPONSE(HTML)를 파싱하기 위한 Beautiful Soup 입니다.

urllib, Beautiful Soup이 임포트되지 않는다면 해당 라이브러리를 먼저 설치하시기 바랍니다.



6
7
8
9
10
11
# 출력 파일 명
OUTPUT_FILE_NAME = 'output.txt'
# 긁어 올 URL
URL = 'http://news.naver.com/main/read.nhn?mode=LSD&mid=shm&sid1=103&oid=055'\
      '&aid=0000445667'
 
cs
그 후에 기사내용을 긁어와 저장할 파일명과 긁어 올 기사의 URL주소를 상수로 할당했습니다.

URL주소를 백슬래시를 사용해 두 줄로 나누었습니다. 이는 한 행이 80자가 넘어가는 것을 방지하기 위해서 입니다.

신문기사 URL주소는 본인이 크롤링하길 원하는 뉴스기사의 URL주소를 복사해 오시면 됩니다. 



저는 네이버 뉴스에서 동영상이 포함된 일기예보 기사를 골라 복사해왔습니다.

동영상이 포함된 기사였지만 일기예보 내용이 텍스트로 본문에 포함되어 있으므로 해당 기사의 본문 내용(텍스트)만 긁어오도록 하겠습니다.



13
14
15
16
17
18
19
20
# 크롤링 함수
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
cs

위는 해당 URL주소로 요청을 보내고 받아 기사 내용을 파싱해 하나의 문자열로 저장하는 함수입니다.



14
15
16
def get_text(URL):
    source_code_from_URL = urllib.request.urlopen(URL)
    sou= BeautifulSoup(source_code_from_URL, 'lxml', from_encoding='utf-8')
cs

우선 15번째 줄에서 urlopen메소드를 통해 URL주소에 대한 요청을 보내 source_code_from_URL 변수에 그 결과를 저장했습니다. 

그 후, HTML코드를 파싱하기 위해 16번째 줄에서 source_code_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'클래스를 가져오기만 하면 됩니다.



17
18
19
20
21
    text = ''
    for item in soup.find_all('div', id='articleBodyContents'):
        text = text + str(item.find_all(text=True))
    return text
 
cs

우선 본문 내용을 저장하기 위해 text에 빈 문자열을 할당합니다.

이 후, soup객체의 find_all 메소드를 이용해 id가 'articleBodyContents'인 'div'클래스를 모두 뽑아내고, for문을 통해 뽑힌 요소 하나하나에 다시 한번 직접 접근합니다.

for문으로 뽑혀진 각 요소 item에 find_all 메소드를 사용, text 키워드 인자에 True를 넣어 텍스트 요소만 뽑아 문자열로 치환한 후, text 문자열에 이어 붙였습니다. 

그 후, text를 반환했습니다.

좀 더 자세 BeautifulSoup객체의 사용법은 공식 문서를 참조하시기 바랍니다.


본문 내용이 포함된 요소가 'div'클래스 하나인데 for문을 쓴 이유는 첫번째로는 find_all 메소드의 반환 객체가 인자로 주어진 조건을 만족하는 모든 요소들을 순환가능한 객체(그 타입이 리스트인지 아닌지는 잘 모르겠네요...)로 주어지기 때문에 사용했으며, 두번째로는 다른 신문사의 경우, 본문 내용이 동일한 id를 갖는 동일한 여러개의 태그에 나뉘어 할당되어있는 경우도 있기 때문입니다.



23
24
25
26
27
28
29
30
31
32
# 메인 함수
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()
cs

위는 그 이후의 코드입니다. 

메인 함수를 별도로 만들고 __name__을 이용해 main함수를 실행시켰습니다.

메인함수에서는 위에서 할당한 OUTPUT_FILE_NAME상수를 통해 txt파일을 생성하고, get_text함수를 사용해 기사내용을 result_text에 할당했습니다. 

이 후, 오픈한 output_file에 기사를 쓰고 닫았습니다.



터미널에서 해당 크롤러모듈을 실행한 결과 'output.txt' 파일이 생성되었으며



'output.txt' 파일의 내용 또한 우리가 긁어오고자 한 신문기사의 내용이 성공적으로 긁어와졌음을 확인할 수 있습니다.

다만 '\n', '\r'등의 문자와 워드클라우드 시각화에 필요 없는 특수문자의 제거가 필요해 보입니다. 

따라서 텍스트 정제 모듈을 따로 만들어 추출된 기사에서 필요없는 문자를 제거하였습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
""" 텍스트 정제 모듈
    영어, 특수기호 모두 제거
"""
 
import re
 
# 입,출력 파일명
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()
cs

위 코드는 텍스트 정제 모듈입니다.



1
2
3
4
5
6
7
8
9
10
""" 텍스트 정제 모듈
    영어, 특수기호 모두 제거
"""
 
import re
 
# 입,출력 파일명
INPUT_FILE_NAME = 'output.txt'
OUTPUT_FILE_NAME = 'output_cleand.txt'
 
cs

정규표현식을 활용하기 위해 're' 라이브러리를 임포트하고, 정제할 파일의 이름을 INPUT_FILE_NAME으로, 결과 파일 이름을 OUTPUT_FILE_NAME으로 할당했습니다.



12
13
14
15
16
17
# 클리닝 함수
def clean_text(text):
    cleaned_text = re.sub('[a-zA-Z]''', text)
    cleaned_text = re.sub('[\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]',
                          '', cleaned_text)
    return cleaned_text
cs

이 후, 문자열을 입력 받아 영어와 특수문자를 제거하는 클리닝 함수를 정의했습니다.

14번째 줄은 대소문자 영어를 제거하는 코드, 15번째 줄은 특수문자를 제거하는 코드입니다.

're'라이브러리의 자세한 사용법은 공식 문서를 참조하시기 바랍니다.



20
21
22
23
24
25
26
27
28
29
30
31
32
# 메인 함수
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()
cs

이번 모듈도 마찬가지로 main를 정의하고 __name__을 이용해 main함수를 실행했습니다.

main함수에서 위에서 상수로 정의한 입력파일명을 이용해 입력파일에서 문자열을 읽고, clean_text함수를 이용해 본문 내용을 정제했습니다.

이후 출력파일명을 이용해 출력파일을 열고,  출력파일에 정제한 본문 내용을 썼습니다.



터미널을 통해 해당 정제모듈을 실행한 결과 'output_cleand.txt'이 생성되었고,



'output_cleand.txt' 파일을 열어 본 결과, 영어와 불필요한 문자들이 제거되었음을 확인할 수 있습니다.



위에서 설명한 크롤러모듈과 정제모듈을 저처럼 따로 나눌 필요는 없습니다. 한 개의 모듈에 모두 구현해 사용해도 무방합니다. 

다음 글에서는 이번에 다룬 크롤러 모듈을 수정, 확장해 동아일보와 한겨레일보에서 '사드' 키워드를 갖는 신문기사를 대량으로  크롤링해보도록 하겠습니다.



출처: http://yoonpunk.tistory.com/4 [윤빵꾸의 공부노트]

'Tensorflow' 카테고리의 다른 글

tensorflow dev summit 2019 요약  (0) 2019.03.21
ms word python 에서 사용하기  (0) 2017.03.12
Tensorflow 소스 코드 분석  (0) 2017.02.18
ReLU (Rectified Linear Unit)  (0) 2017.02.18
Machine learning 종류  (0) 2017.02.12