[Web Crawling] BeautifulSoup
HTML
HTML 개념
- Hypertext Markup Language 약자
- 월드 와이드 웹에서 하이퍼텍스트 문서를 만들기 위한 기본언어이다.
HTML 특징
- HTML 문서의 골격은 태그의 쌍으로 구성된다.
-> <태그이름>문서의내용</태그이름>
- 태그 중에서는 <BR>, <IMG>처럼 종료 태그가 없는 경우도 있다.
HTML 기본구조
- HTML 문서는 태그로 구성되어있다.
<html>
<head>
<title>Hello</title>
</head>
<body>
<p>Hello HTML!</p>
</body>
</html>
- <HTML> ~ </HTML> : HTML로 작성된 것을 표시한다. HTML의 시작을 의미한다.
- <HEAD> ~ </HEAD> : 문서정보 기술, 문서 전체에 영향을 미치는 내용으로 화면에는 출력되지 않는다.
- <BODY> ~ </BODY> : 실질적인 페이지 내용 삽입,이 태그 안의 내용은 모두 화면에 출력된다.
HTML 태그 속성
- 태그속성은 태그에 특별한 성질을 부여하는 기능을 한다.
- 태그 속성이 없는 title 태그 : <title>test site</title>
- class와 id 속성을 가지는 title 태그 : <title class="t" id="ti">test site</title>
Parsing
- 하나의 문장을 그것을 이루고 있는 구성성분으로 분해하는 것이다.
- 구성성분 사이의 위계 관계를 분석해서 문장의 구조를 결정한다.
HTML parsing
- DOM : 웹페이지의 HTML문서를 트리 구조로 표현한 모델
- HTML Parsing : HTML 문서를 읽어 들여서 DOM으로 변환해주는 것
BeautifulSoup
- HTML이나 XML를 파싱하기 위한 라이브러리
HTML parser 종류
- lxml
- html5lib
- html.parser
HTML parsing
BeautisulSoup 이용
from bs4 import BeautifulSoup
html = """<html><head><title>test site</title></head><body><p>test1</p><p>test2</p></body></html>"""
soup = BeautifulSoup(html, 'lxml')
print(soup)
<html><head><title>test site</title></head><body><p>test1</p><p>test2</p></body></html>
print(type(soup))
>>> <class 'bs4.BeautifulSoup'>
HTML을 보기 좋게 출력하기
BeautifulSoup.prettify() 이용
print(soup.prettify())
>>> <html>
<head>
<title>
test site
</title>
</head>
<body>
<p>
test1
</p>
<p>
test2
</p>
</body>
</html>
태그 접근법
BeautifulSoup 객체에서 .<태그이름>
- 처음 만나는 태그를 가져온다.
html = """<html><head><title>test site</title></head><body><p>test1</p><p>test2</p></body></html>"""
soup = BeautifulSoup(html, 'lxml')
tag_title = soup.title
print(tag_title)
>>> <title>test site</title>
print(type(soup), type(tag_title))
>>> <class 'bs4.BeautifulSoup'> <class 'bs4.element.Tag'>
태그 객체 속성
- Tag.text : 태그에 포함된 텍스트
- Tag.string : 태그의 후손들 중에서 단 하나의 텍스만 있을 때 사용
- Tag.name : 태그의 이름
html = """<html><head><title>test site</title></head><body><p>test1</p><p>test2</p></body></html>"""
soup = BeautifulSoup(html, 'lxml')
tag_title = soup.title
print(tag_title.text)
>>> test site
print(tag_title.string)
>>> test site
print(tag_title.name)
>>> title
태그 속성
- .attr를 이용하여 모든 태그속성들을 접근
print(tag_title.attr)
>>> {'class': ['t'], 'id': 'ti'}
- 타이틀 태그의 속성 접근
- 대괄호 []안에 태그속성의 이름을 넣는다.
- class 태그 속성은 list 형태로 리턴되고 여러 개의 속성값을 가질 수 있다.
print(tag_title['calss'])
>>> ['t']
print(tag_title['id'])
>>> ti
- 없는 속성에 접근하면 에러가 발생한다.
- get() 함수를 사용하면 없는 태그속성을 접근해도 에러가 발생하지 않는다.
print(tag_title.get('class'))
print(tag_title.get('id'))
print(tag_title.get('size'))
print(tag_title.get('size','just ok'))
>>> ['t']
>>> ti
>>> None
>>> 'jusk ok'
Tag.text VS Tag.string
- Tag.text : 모든 자식 태그들의 텍스트를 연결하여 반환한다.
- Tag.string : 후손들의 태그 중에 단 하나의 텍스트가 있는 경우만 스트링을 반환한다.
여러 개의 텍스트를 가지고 있으면 None을 반환한다.
html = """<html><head><title class="t" id="ti">test site</title></head><body><p><span>test1</span><span>test2</span></p></body></html>"""
soup = BeautifulSoup(html, 'lxml')
tag_p = soup.p
data_text = tag_p.text
data_string = tag_p.string
print('text:',data_text, type(data_text))
>>> text: test1test2 <class 'str'>
print('string:',data_string,type(data_string))
>>> string: None <class 'NoneType'>
print(tag_p.span.string)
>>> test1
HTML 태그 관계
- 태그 관계
- 부모 자식 관계
- <head>는 <title>의 부모 태그이다.
- <title>은 <head>의 자식 태그이다.
- 형제 관계
- <head>와 <body>는 형제 관계이다.
자식 태그 가져오기
contents
- 리스트 형식으로 모든 자식태그를 가져온다.
soup = BeautifulSoup(html, 'lxml')
print(soup.html.contents)
>>> ['\n', <head><title>test site</title></head>, '\n', <body><p><a>test1</a><b>test2</b><c>test3</c></p></body>, '\n']
.children
- iterator 형식으로 자식태그를 가져온다.
print(list(soup.html.children))
>>> ['\n', <head><title>test site</title></head>, '\n', <body><p><a>test1</a><b>test2</b><c>test3</c></p></body>, '\n']
for tag in soup.html.contents :
if tag.name :
print(tag)
>>> <head><title>test site</title></head>
<body><p><a>test1</a><b>test2</b><c>test3</c></p></body>
부모 태그 가져오기
.parent 이용
print(soup.title.parent)
print(soup.p.parent)
>>> <head><title>test site</title></head>
>>> <body><p><a>test1</a><b>test2</b><c>test3</c></p></body>
형제 태그 가져오기
.find_next_sibling() : 다음 형제 가져오기
.find_previous_sibling() : 이전 형제 가져오기
print(soup.head.find_nect_sibling())
print(soup.body.find_previous_sibling())
>>> <body><p><a>test1</a><b>test2</b><c>test3</c></p></body>
>>> <head><title>test site</title></head>