Python
2013.04.08 10:17

BeautifulSoup로 HTML 파싱 끝내기

조회 수 42525 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

+ - Up Down Comment Print
?

단축키

Prev이전 문서

Next다음 문서

+ - Up Down Comment Print
HTML 파싱할 일이 생겼는데,
그동안은 그냥그냥 필요한 내용만 crummy에서 짬짬히 보다가,
BeautifulSoup을 한국말로 잘 정리한 사이트를 찾았다.

susukang98님의 블로그 : http://susukang98.springnote.com/pages/333771

예를 들자면, BeautifulSoup을 이용해서 특정 홈피의 내용 중, 어느 부분은 읽는다면 다음과 같이 간단하게 끝낼수 있을 것이다.
(사실 정규식을 잘 쓴다면 필요없을 것이다...)
from BeautifulSoup import BeautifulSoup
import urllib2

url = 'http://블라블라'
handle = urllib2.urlopen(url)
data = handle.read()
soup = BeautifulSoup(data)
article = str( soup('div', {'class':'article',}) ) #div내의 article class 추출
print article.decode('utf8')


위 예제 프로그램은 본문에서 div 내의 article 클래스만을 추출하는 예제이다. (ex. 티스토리)


자세한 내용은 다시 찾기 귀차니즘으로 인해, 수수깡님이 스크랩한 내용을 아래에 copy&paste 해 놓겠다.

-----------------------------------------------------------------------------------

Beautiful Soup (2.1.1)

http://www.crummy.com/software/BeautifulSoup/



웹을 가지고 놀기 위해서는 먼저 웹의 언어인 HTML을 잘 구사할 수 있어야 한다.

세상에는 프로그래머가 HTML을 잘 말하고 잘 알아듣기 위해 사용하는 HTML 파서가

무수히 많다. 그중에서 사용하기 쉬운 파서를 하나 고르자면 Beautiful Soup을 들

수 있다. Beautiful Soup은 파이선으로 작성되었으며, 동적 스크립트언어의 장점을

잘 활용한다.

#import urllib
#html_source = urllib.urlopen('http://www.naver.com').read()
html_source = '''

'''

from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup(html_source)

# 태그 이름을 변수 이름으로 사용할 수 있다.
print soup.html.head.title
# 결과:



# 계층구조의 중간단계를 생략할 수 있다.
print soup.title
# 결과:



# 태그 안에 다른 태그가 없는 경우 string 속성으로 태그 내용을 얻을 수 있다.
print soup.title.string
# 결과: 페이지 제목



# 같은 이름의 태그가 여러개 있다면 제일 먼저 나오는 태그를 알려준다.
# dictionary 문법을 사용하여 태그의 속성만 얻을 수도 있다.
print soup.p
# 결과:

첫번째 단락


print soup.p['class']
# 결과: layout



# 없는 태그를 지칭하면 (BeautifulSoup.) Null 객체를 반환한다.
print soup.body.title
# 결과: Null



# soup('p') 은 첫번째 뿐아니라 모든 p 태그 목록을 반환한다.
# 두번째 아규먼트로 태그의 속성을 제한할 수도 있다.
print soup('p')[0]
# 결과:

첫번째 단락


print soup('img', { 'name': 'main', })
# 결과: [dooly-1.png]
print soup('p', 'layout')
# soup('p', { 'class': 'layout' }) 과 같다. CSS 분류를 쉽게 지정할 수 있다.


# parent 속성은 계층구조상 한칸 위에 있는 태그를 지칭하고, 반대로 contents

# 속성은 계층구조상 한칸 아래에 있는 태그 목록을 반환한다.
# nextSibling 와 previousSibling 은 계층구조상 같은 위치에 있는 바로 앞뒤 태그를

# 지칭한다. 예제에서 첫번째 p 태그의 nextSibling 은 두번째 p 태그가 아니라

# 첫번째 p 태그와 두번째 p 태그 사이 영역이고, 이 영역에는 줄바꿈 문자 하나만 있다.
# 이는 soup('p').parent.contents 로 확인할 수 있다.
# next 와 previous 는 계층구조와 무관하게 HTML 소스에서 태그 바로 앞뒤에 위치하는

# 태그를 지칭한다. 마지막으로 태그 이름은 name 속성에 저장된다.
print soup('p')[0].nextSibling
# 결과: \n
print soup('p')[0].next
# 결과: 첫번째 단락

print soup('p')[0].next.name
# 결과: b
# 앞에서 본 string 속성은 태그 안에 다른 태그가 없는 경우에는 contents[0] 과 같고,
# 다른 태그가 있다면 Null 이다.



print len(soup('p')) # len(soup('p').contents) 와 같다.
for x in soup('p'): # for x in soup('p').contents: 와 같다.

pass



## fetch(name, attrs, recursive, limit) 함수
# 다양한 조건을 가지고 원하는 태그를 찾는 함수로, 앞의 예들은 이 함수의 축약형이다.

# tag.fetch(...) = tag(...)
# name과 attrs는 각각 태그 이름과 태그 속성을 나타내는데 다양한 방법으로 지시할 수 있다.

#
# * 문자열: fetch('img'), 모든 img 태그 목록
# * 목록: fetch(['object', 'applet!', 'embed']), 모든 object/applet!/embed 태그 목록
# * dictionary: fetch('div', { 'class': 'sidebar', 'name': 'menu' })
# * 정규표현식: fetch('div', { 'name': re.compile('list.*') }),

# name 속성이 "list"로 시작하는 모든 div 태그 목록
# * 함수: 원하는 조건인 경우 참을 반환하는 함수를 사용하여 복잡한 조건을 지시할 수 있다.

#
# recursive와 limit는 계층구조상 현재 태그 아래를 계속 찾아들어갈지, 만약 그렇다면

# 어느정도까지 들어갈지를 정한다. 기본적으로 현재 태그 아래로 끝까지 들어가면서

# 태그를 찾는다.

#
# fetch() 를 기준삼아 first(), fetchText(), firstText(), findNextSibling(),

# findPreviousSibling(), fetchNextSibling(), fetchPreviousSibling(),
# findNext(), findPrevious(), fetchNext(), fetchPrevious(), findParent(),
# fetchParent() 와 같은 함수가 있다. fetch*/*Text() 함수는 태그가 아닌 태그 안의

# 문자를 찾거나 가져오고, *Next*/*Previous*/*Parent() 함수는 현재 태그에서

# 계층구조상 아래로 내려가지 않고 대신 앞뒤 혹은 위로 이동하며 조건에 맞는 태그를

# 찾는다. 각 함수의 자세한 정보는 설명서를 참고하라.
def need_thumbnail(x):
# 가로나 세로가 60 보다 큰 img 태그라면 True, 아니면 False

if x.name == 'img':

return x.get('height', 0) > 60 or x.get('width', 0) > 60

return False
print soup.ul(need_thumbnail) # = soup.ul.fetch(need_thumbnail)
print soup.p.findNextSibling('p') # 두번째 p 태그



# 다음과 같이 HTML 소스를 수정할 수도 있다. 단, 이때는 앞에서 본 string 같은
# 축약형을 사용할 수 없고 contents 목록을 직접 수정해야 한다. 그후 prettify()

# 함수로 수정한 HTML 소스를 계층구조에 따라 들여쓰기하여 출력한다.
print soup
soup.title.contents[0] = '제목 수정'
soup.p['class'] = 'menu'
soup('p')[1].contents = ['두번째 단락 생략',]

del soup.body.contents[5]
print soup.prettify()

현재 Beautiful Soup은 두가지 문제가 있는데, 하나는 속도이고 다른 하나는 한글처리다.

Beautiful Soup은 빠른 속도를 위해 최적화하여 설계되지 않았기때문에 복잡한 HTML

소스를 처리할 때 속도가 느려진다. 이런 경우에는 자주 참조하는 태그의 공통분모를

미리 변수에 저장해두고 이 변수를 기준으로 태그들을 참조하는 식으로 부담을 덜 수 있다.

    soup('div', { 'name': 'toolbar' })[0].table('tr')[0]('td')[2].ul('li')[0]
    soup('div', { 'name': 'toolbar' })[0].table('tr')[0]('td')[2].ul('li')[1]
    soup('div', { 'name': 'toolbar' })[0].table('tr')[0]('td')[2].ul('li')[2]
    soup('div', { 'name': 'toolbar' })[0].table('tr')[0]('td')[2].ul('li')[3]
->
    ulist = soup('div', { 'name': 'toolbar' })[0].table('tr')[0]('td')[2].ul
    ulist('li')[0]
    ulist('li')[1]
    ulist('li')[2]
    ulist('li')[3]

한글처리에서는 태그의 속성값에 한글이 있는 경우 태그 속성값을 전부 무시해 버린다.
정확히는 파이선 표준 라이브러리의 sgmllib의 문제인데, BeautifulSoup.py 파일의
from sgmllib import SGMLParser, SGMLParseError
줄을
from hack_sgmllib import SGMLParser, SGMLParseError
으로 수정하고, 표준 라이브러리의 sgmllib.py 파일의 복사본을 BeautifulSoup.py 와

동일한 디렉토리에 hack_sgmllib.py 란 이름으로 저장한다. 그리고 attrfind 정규표현식에서

[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~\'"@] 부분을 [^ >] 로 수정한다. 깔끔한 방법은

아니지만 어쨌든 한글 태그 속성을 인식하게 된다.


Dreamy의 코드 스크랩

내가 모으고 내가 보는

List of Articles
번호 분류 제목 날짜 조회 수 추천 수
20 Python filter()와 reduce() 함수 2014.04.30 10986 0
19 Python collections.counter() 함수 2014.04.30 14098 0
18 Python 유용한 Python 함수 및 기능들 2014.04.30 11712 0
17 Python zip() 함수 2014.04.30 22330 0
16 Python python 내장 함수 2014.04.30 16065 0
15 Python map() 함수 2014.04.30 9903 0
14 Python pylab - Plotting with Matplotlib 2014.04.28 9744 0
13 Python Lambda 함수, 축약 함수 2014.04.25 12470 0
12 Python wxPython Tutorial 링크 2014.04.24 10564 0
11 Python distutils 개요 2014.04.24 9380 0
10 Python paramiko로 SSH 접속하기 2014.04.22 21497 0
9 Python Python 문자열 관련 함수 2013.05.07 22564 0
8 Python python 문법요약 2013.04.08 28552 0
» Python BeautifulSoup로 HTML 파싱 끝내기 2013.04.08 42525 0
6 Python BeautifulSoup으로 웹에 있는 데이터 긁어오기 2013.04.08 76920 0
목록
Board Pagination ‹ Prev 1 2 3 Next ›
/ 3

나눔글꼴 설치 안내


이 PC에는 나눔글꼴이 설치되어 있지 않습니다.

이 사이트를 나눔글꼴로 보기 위해서는
나눔글꼴을 설치해야 합니다.

설치 취소

Designed by sketchbooks.co.kr / sketchbook5 board skin

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5