자연어 처리를 공부하던 중 문득 인터넷 상의 글들을 긁어모아서 학습해보면 재밌겠다 싶어서 웹 크롤링을 공부했다. 최근 게시물의 경향은 이미지 위주의 글이기 때문에 글 위주의 게시물이 있는 곳이 없을까 생각하다가 네이트판을 떠올렸다.
간단한 웹 크롤링은 requests
모듈과 bs4의 BeautifulSoup
모듈만 있으면 가능하다.
pip 모듈을 이용해 라이브러리를 설치해주자.
pip install requests
pip install bs4
웹 크롤링을 하기에 앞서 크롤링을 하고자 하는 웹 페이지의 구조를 분석해야 한다. 크롤링하려는 네이트판 랭킹 페이지 주소는 다음과 같다.
https://pann.nate.com/Talk/Ranking?rankingType=total
분석하고자 하는 요소에 오른쪽 버튼을 클릭하여 검사를 누르면 손쉽게 분석이 가능하다. 이 페이지에서 내가 가져오고자 하는 것은 글들의 제목과 내용이다. 내용은 링크를 클릭하여 볼 수 있으므로 현재 가져올 정보는 제목, 글의 링크가 된다.
글 목록 요소를 검사하면 위와 같이 <ul class="post_wrap">
밑에 <li>
태그로 글 목록이 만들어져있으며,
각 <li>
태그를 좀 더 자세히 살펴보면 <dt>
태그 밑에 링크가 있고 해당 링크의 텍스트가 제목으로 되어있다.
추가적으로 네이트판 랭킹 페이지는 두 페이지로 구성되어 있다.
이제 분석이 끝났으니 웹 크롤러를 만들어보자.
제목과 링크 목록 얻기
x
import requests
from bs4 import BeautifulSoup
def nate_pann_ranking():
titles = []
links = []
for i in range(1, 3):
res = requests.get("https://pann.nate.com/talk/ranking?rankingType=total&page="
+ str(i))
res.raise_for_status()
res.encoding = None
html = res.text
soup = BeautifulSoup(html, 'html.parser')
ranking_list = soup.find('ul', {'class': 'post_wrap'}).findAll('dt')
for dt in ranking_list:
link = dt.find('a')
real_link = 'https://pann.nate.com' + link.get('href')
titles.append(link.text)
links.append(real_link)
return {'title': titles, 'link': links}
네이트 판 랭킹 페이지는 총 두 페이지이므로 두 번 반복함으로써, 각 페이지 링크마다 크롤링하여 모든 랭킹 목록을 가져오게 된다. 그 다음 한글 깨짐을 방지하기 위해 res.encoding = None
을 해준다.
requests
모듈을 통해 얻어온 html 문서를 BeautifulSoup
객체로 변환한다. 그런 뒤 BeautifulSoap
의 find
메서드를 통해 <ul class="post_wrap" >
태그를 찾고 그 내부의 <dt>
태그를 전부 찾아 반환한다.
마지막으로 각 <dt>
태그 내부에 있는 <a>
태그를 찾아 제목 텍스트를 찾고 href
속성 값을 얻어 실제 링크를 얻는다.
네이트판 글 내용만 추출하기
xxxxxxxxxx
def get_nate_pann_content(link):
res = requests.get(link)
res.raise_for_status()
res.encoding = None
html = res.text
soup = BeautifulSoup(html, 'html.parser')
contentArea = soup.find('div', {'id': 'contentArea'})
parags = contentArea.findAll('p')
content = ""
for parag in parags:
content += parag.text.replace(' ', '') + '\n'
return content.strip()
네이트 판 게시글도 위와 같이 똑같이 html 문서를 분석하는 과정을 거치면, <div id="contentArea">
밑에 본 글이 있는 것을 알 수 있다. 보통 글이 <p>
태그를 이용하여 단락 구성을 하기 때문에 위와 같이 코딩했다.
x
info = nate_pann_ranking()
for link in info['link'][:5]:
print(link)
get_nate_pann_content(link)
이제 위 코드를 입력하면 글의 내용만 볼 수 있다. 그러나 글의 내용이 아예 나오지 않는 경우도 있었다. 무슨 일인가 보니 아예 <p>
태그가 없는 경우도 있었고 오로지 사진만 <p>
태그로 감싸져 있는 경우도 있었다. 그래서 모든 글의 내용을 성공적으로 추출하려면 아래와 같이 수정해야 한다.
xxxxxxxxxx
def get_nate_pann_content(link):
res = requests.get(link)
res.raise_for_status()
res.encoding = None
html = res.text
soup = BeautifulSoup(html, 'html.parser')
contentArea = soup.find('div', {'id': 'contentArea'})
parags = contentArea.findAll('p')
if len(parags) == 0:
return contentArea.text.strip()
content = ""
for parag in parags:
content += parag.text.replace(' ', '') + '\n'
if content == '\n':
return contentArea.text.strip()
return content.strip()
'R, Python' 카테고리의 다른 글
[python] PyQt5로 이미지 뷰어 만들기 (간단한 라벨링 툴 만들기 1단계) (6) | 2019.11.14 |
---|---|
[C/C++/C#] 콘솔에서 글자 색 변경하기 (예시: KMP 알고리즘) (0) | 2019.11.05 |
[Python] 5분만에 음성 인식 구현하기 (4) | 2019.02.05 |
python 로딩(애니메이션) 쉽게 구현하기 (1) | 2019.01.23 |
R을 이용한 텍스트 마이닝 및 워드 클라우드(word cloud) 만들기 (0) | 2018.12.07 |
댓글