자연어 처리를 공부하던 중 문득 인터넷 상의 글들을 긁어모아서 학습해보면 재밌겠다 싶어서 웹 크롤링을 공부했다. 최근 게시물의 경향은 이미지 위주의 글이기 때문에 글 위주의 게시물이 있는 곳이 없을까 생각하다가 네이트판을 떠올렸다.
간단한 웹 크롤링은 requests 모듈과 bs4의 BeautifulSoup 모듈만 있으면 가능하다.
pip 모듈을 이용해 라이브러리를 설치해주자.
pip install requestspip install bs4
웹 크롤링을 하기에 앞서 크롤링을 하고자 하는 웹 페이지의 구조를 분석해야 한다. 크롤링하려는 네이트판 랭킹 페이지 주소는 다음과 같다.
https://pann.nate.com/Talk/Ranking?rankingType=total
분석하고자 하는 요소에 오른쪽 버튼을 클릭하여 검사를 누르면 손쉽게 분석이 가능하다. 이 페이지에서 내가 가져오고자 하는 것은 글들의 제목과 내용이다. 내용은 링크를 클릭하여 볼 수 있으므로 현재 가져올 정보는 제목, 글의 링크가 된다.
글 목록 요소를 검사하면 위와 같이 <ul class="post_wrap"> 밑에 <li> 태그로 글 목록이 만들어져있으며,
각 <li> 태그를 좀 더 자세히 살펴보면 <dt> 태그 밑에 링크가 있고 해당 링크의 텍스트가 제목으로 되어있다.
추가적으로 네이트판 랭킹 페이지는 두 페이지로 구성되어 있다.
이제 분석이 끝났으니 웹 크롤러를 만들어보자.
제목과 링크 목록 얻기
x
import requestsfrom bs4 import BeautifulSoupdef 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 속성 값을 얻어 실제 링크를 얻는다.
네이트판 글 내용만 추출하기
xxxxxxxxxxdef 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> 태그로 감싸져 있는 경우도 있었다. 그래서 모든 글의 내용을 성공적으로 추출하려면 아래와 같이 수정해야 한다.
xxxxxxxxxxdef 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 |
댓글