python을 이용한 클리앙 파서만들기 - BeautifulSoup 사용편
지난 HTML 분석편에서 확인했듯이 우리는 <td class="mytr">을 가져와 category,subject,post_name 이 3가지를 출력하려고 합니다. 우선 BeautifulSoup를 설치해야겠지요?
pip install BeaautifulSoup4
BeautifulSoup에선 third-party Python parser인 lxml과 html5lib도 지원하지만 저는 Python의 기본 내장 파서를 사용하려고합니다.
from bs4 import BeautifulSoup from urllib.request import Request,rulopen from urllib.paarse import urljoin
첫 from bs4 import BeautifulSoup은 BeautifulSoup를 사용하기 위해 추가해주는것이며 from urllib.request importRequest,urlopen 은 url을 이용하여 해당 페이지에 접속하기 위해 추가해 줍니다. 마지막 from urllib.parse import urljoin은 다음과 같이 해당 글의 url을 상대경로로 표시되어있습니다. 이를 절대경로로 변경하여 주기 위하여 추가해 줍니다.
우선 clien 팁과강좌 게시판을 여는 코드를 작성해 보겠습니다.
base_url = "http://www.clien.net/cs2/bbs/board.php?bo_table=lecture" url_request = Request(base_url,headers={'User-Agent': 'Mozilla/5.0'}) clien_tip_board = urlopen(url_request).read()
Request의 headers={'User-Agent': 'Mozilla/5.0'}는 적어주시지 않으면 봇으로 간주하여 해당 페이지를 열수 없게 하는경우가 있기에 User-Agent를 조작하여 접속을 하게 됩니다.
이곳까지 작성하였다면 우리는 clien 팁과강좌 게시판을 가져오는데 성공하였습니다 : ^)
BeautifulSoup을 이용하여 원하는 부분 출력하기
이제 본격적으로 BeautifulSoup을 이용하여 원하는 부분들만 가져와서 출력을 하면됩니다.
bs4_clien = BeautifulSoup(clien_tip_board,"html.parser") find_mytr = bs4_clien.find_all("tr",attrs={'class':"mytr"}) for t in find_mytr: print(t.find('td',attrs={'class':'post_category'}).get_text(strip=True)) print("제목 : "+t.find('td',attrs={'class':'post_subject'}).get_text(strip=True).encode('cp949','ignore').decode('cp949')) print("url : "+urljoin(base_url,t.find('td',attrs={'post_subject'}).a.get('href'))) print("글쓴이 : "+t.find('td',attrs={'class' : 'post_name'}).get_text(strip=True))
우선은 find_all()함수를 사용할 것인데요. bs4_clien.find_all() 함수는 find_all 말그대로 bs_clien에서 해당하는것들을 모두 가져 오는 함수입니다. 우리는 1페이지의 모든 </td><tr class="mytr">을 가져오기로 했었습니다. 따라서 다음과 같은 코드가 필요합니다.
find_mytr = bs4_clien.find_all("tr",attrs={'class':"mytr"})
다음은 이제 mytr을 가져왔으니 그안에 있는 post_category,post_subject,post_name을 가져 와보도록 하겠습니다.
for t in find_mytr: print(t.find('td',attrs={'class':'post_category'}).get_text(strip=True)) print("제목 : "+t.find('td',attrs={'class':'post_subject'}).get_text(strip=True).encode('cp949','ignore').decode('cp949')) print("url : "+urljoin(base_url,t.find('td',attrs={'post_subject'}).a.get('href'))) print("글쓴이 : "+t.find('td',attrs={'class' : 'post_name'}).get_text(strip=True))
다 공통된 부분인데요 find()함수는 해당하것을 가져오는 함수입니다. find_all()함수와는 다르게 첫번째것만을 가져오기때문에 첫번째것 하나만 필요하게 되면 훨씬 효율적인 코드가 되겠지요.
<td class="post_category">를 가져오기위하여
find('td',attrs={'class':'post_category'})
를 사용하였습니다. 그뒤 .get_text(strip=True)는 해당태그 안에있는 텍스트를 가져오는 함수인데요 strip=True는 앞뒤공백문자를 지워주는 옵션입니다.
</td><td class="post_subject"> 도 마찬가지로 find()함수와 get_text()함수를 사용하여 가져옵니다.
url주소는 </td><td class="post_subject"> 태그 안에있는 <a href=""> 에 존재하고있습니다. 따라서 t.find('td',attrs={'post_subject'}).a.get('href')이러한 방법으로 url 주소를 가져오게 됩니다. find함수로 </a></td><td class="post_subject">를 가져오고 그안에 있는 a 태그의 href를 가져오는 방법입니다. 위에서 말했듯 이곳엔 상대경로인 ../~로 시작된 주소가 포함되어있는데요. 이것을 절대경로 즉 우리가 접속하는 주소로 바꿔주는 함수가 바로 처음에 추가해주었던 urljoin()함수입니다.
자 이제 Clien 팁과강좌 게시판을 파싱하는 법이 끝났습니다. 전에 올린 트위터강좌와 연계하여 사용한다면 자신이 원하는 글이 올라오면 Twitter를 통하여 DM으로 받을 수 있겠네요.
제목부분에 encode후 decode를 하였는데요. 사실 이것때문에 BeautifulSoup편 강좌가 늦어졌습니다. 저는 윈도우를 사용하기때문에 cmd창에서 cp949를 사용하여 출력을하는데 한분이 강좌를 올려주신 글에 cp949에서 없는 글자인지 자꾸 오류를 뿜더군요. 그래서 cp949로 인코딩을 하며 없는 문자는 그냥 제거를 해버렸습니다.