- 파이썬 모듈인 BeautifulSoup 파서사용법을 알아보자
- urljoin, find_all, select_one, next_sibiling, previous_sibiling 을 사용하여 파싱을 진행하겠다.
아나콘다 프롬프트 실행 후 section2를 활성화 시키자
pip install beautifulsoup4 명령어를 입력 후 패키지를 다운받는다.
conda list 명령어를 통해 설치가 완료됨을 확인 후
atom 명령어 실행 후 atom을 실행시킨다.
파일을 생성 후 다음 코드를 입력해보자
1
2
3
4
5
6
7
8
|
from urllib.parse import urljoin
baseUrl = "http://test.com/html/a.html" #주소를 객체에 저장한다
print(">>", urljoin(baseUrl, "b.html")) # >> http://test.com/html/b.html 치환시킴
print(">>", urljoin(baseUrl, "sub/b.html")) # >> http://test.com/html/sub/b.html
print(">>", urljoin(baseUrl, "../index.html")) # >> http://test.com/index.html
print(">>", urljoin(baseUrl, "../img/img.jpg")) # >> http://test.com/img/img.jpg
print(">>", urljoin(baseUrl, "../css/img.css")) # >> http://test.com/css/img.css
|
cs |
download2-5-1.py
urllib.parse 컴포넌트 의 urljoin 메서드를 사용했다.
상대경로 입력 시 기본 도메인 이후가 변경된다.
아래 urljoin의 라이브러리를 확인해보자
url 경로를 치환시키는 법을 알아봤으면 다음으로는 html 코드를 BeautifulSoup를 통해 객체로 담아와보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
from bs4 import BeautifulSoup
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8') #한글 인코딩을 위해서라면
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8') #입력해야 합니다.
html = """
<html>
<body>
<h1>파이썬 BeautifulSoup 공부</h1>
<p>태그 선택자</p>
<p>두번째 태그 선택자</p>
</body>
</html>
"""
soup = BeautifulSoup(html, 'html.parser') # soup 객체에 html를 넣어준다
print("soup type : ", type(soup)) # <class 'bs4.BeautifulSoup'>
print('prettify : ', soup.prettify()) # prettify 매서드는 html코드를 자동정렬 해준다
h1 = soup.html.body.h1 #soup 객체의 html > body > h1 에 접근하여 담아온다.
print('h1 type : ', type(h1)) # <class 'bs4.element.Tag'>
print('h1 : ', h1) # h1에 담긴 h1 태그가 출력된다
print(h1.string) # string은 해당 태그 안의 내용만을 가져온다.
print('\n')
p1 = soup.html.body.p
print('p1 : ',p1) # p1은 p태그가 출력된다. html 코드에 p가 2개이상인데, 이땐 가장 상위의 것을 가져온다.
print('\n')
p2 = p1.next_sibiling # next_sibiling은 해당 태그의 바로 다음 요소를 나타낸다.
print('p2 : ', p2) # None이 출력된다. 두번째 p 태그가 담겨야 하는데 왜일까? 그 이유는 사이에 개행인 \n가 안보이게 존재하여 None을 담게되는것이다.
print('\n')
p2 = p1.next_sibling.next_sibling # 위의 문제점을 해결하기 위해 next_sibiling을 두번 사용한다.
print('p2 : ', p2) # 두번째 p 태그가 담긴것을 확인할 수 있다.
print('\n')
p3 = p1.previous_sibling.previous_sibling # previous_sibling은 해당 태그의 바로 이전 요소를 나타낸다.
print('p3 : ', p3) # p3는 p1 객체의 이전 요소를 담고있다. 여기도 역시 previous_sibling을 두번 사용했다.
print('\n')
print('h1 내용 : ', h1.string) # string은 해당 태그 안의 내용만을 가져온다.
print('p1 내용 : ', p1.string) # string은 해당 태그 안의 내용만을 가져온다.
print('p2 내용 : ', p2.string) # string은 해당 태그 안의 내용만을 가져온다.
print('p3 내용 : ', p3.string) # string은 해당 태그 안의 내용만을 가져온다.
|
cs |
download2-5-2.py
코드 우측 주석 설명을 참조하고 위 코드를 실행해서 실제 실행 내용을 확인해보자.
위 방법은 단점이 한가지가 있는데, p1= soup.html.body.p 같은 형식으로 객체에 담으면 p태그의 객체가 여러개 존재하여도 가장 상위의 p태그 하나밖에 담아오질 못한다.
그러므로 크롤링 할 때 잘 활용되지는 않는다.
그럼, 같은 태그가 여러개 존재 할때 묶어서 한번에 담아오는 방법이 필요할 것이다.
아래 코드를 통해 어떻게 할 수 있는지 확인해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
from bs4 import BeautifulSoup
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
html = """
<html><body>
<ul>
<li><a href="http://www.naver.com">naver</a></li>
<li><a href="http://www.daum.net">daum</a></li>
<li><a href="http://www.daum.co.kr">daum</a></li>
<li><a href="http://www.google.com">google</a></li>
<li><a href="http://www.tistory.com">tistory</a></li>
</ul>
</body></html>
"""
soup = BeautifulSoup(html, "html.parser")
links = soup.find_all("a") # find_all을 사용하여 a태그 모두를 담아온다. find_all은 파라미터로 전달된 태그 모두를 리스트 형태로 담는다.
print('links : ', links) # a태그 5개가 리스트의 형태로 들어감을 확인할 수 있다.
print('\n')
a = soup.find_all("a", string="daum") # 태그 안 내용이 daum인 노드만 가져온다.
print('a : ', a) # 위 html에서 string이 daum인 두 태그를 가져온다.
print('\n')
##### b = soup.find("a")와 같이 find로 "a"태그를 찾게되면 html 순서 상 가장 상위의 a태그 하나만을 가져온다.
b = soup.find_all("a", limit=3) # limit 제한을 걸어 상위 3개만 가져올 수 있다.
print('b : ', b) #b [<a href="http://www.naver.com">naver</a>, <a href="http://www.daum.net">daum</a>, <a href="http://www.daum.co.kr">daum</a>]
print('\n')
c = soup.find_all(string=["naver", "google"]) # 파라미터에 태그를 넣어주지 않았으므로 string이 "naver", "google"인 것 모두 찾아서 c에 리스트 형태로 담아준다.
print('c : ', c) # ['naver', 'google']
print('\n')
#links 리스트를 for문을 돌려 출력
for a in links :
href = a.attrs['href'] #어트리뷰트 속성은 https://www.crummy.com/software/BeautifulSoup/bs4/doc/ 에서 확인가능하다. 키를 파라미터로 전달하면 dictionary 형태로 객체에 담긴다.
txt = a.string
print('txt >> ', txt, 'href >> ', href)
|
cs |
download2-5-3.py
해당 코드의 주석을 참고 후 실행해보자.
find_all 매서드를 사용하여 태그 전체를 가져와 파싱할 수 있다.
html 코드 파싱을 조금 살펴봤으니 선택자를 통한 파싱 방법을 확인해보겠다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#css 선택자
#https://www.w3schools.com/cssref/css_selectors.asp 레퍼런스 참고
from bs4 import BeautifulSoup
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
html = """
<html><body>
<div id="main">
<h1>강의목록</h1>
<h1>강의목록2</h1>
<ul class="lecs">
<li>Java 초고수 되기</li>
<li>파이썬 기초 프로그래밍</li>
<li>파이썬 머신러닝 프로그래밍</li>
<li>안드로이드 블루투스 프로그래밍</li>
</ul>
</div>
</body><html>
"""
soup = BeautifulSoup(html,"html.parser") # soup객체에 저장
h1 = soup.select("div#main > h1") # select 매서드를 통해 div 태그의 id=main 내 h1 전체를 담는다
h2 = soup.select_one("div#main > h1") # select_one 매서드를 통해 div 태그의 id=main 내 가장 상단 h1을 담는다.
print('h1 : ', h1)
print('h2 : ', h2)
# print(h1.string) # h1는 list object는 속성이기 때문에 string으로 출력 불가
print('h2 : ', h2.string) # h2는 리스트 형태가 아니기 때문에 스트링으로 바로 가져올 수 있다.
print('\n')
for z in h1 :
print(z.string) #다음과 같이 for문을 통해 list형태를 string으로 출력 시킬 수 있다.
list_li = soup.select("div#main > ul.lecs > li") # select 매서드를 통해 div 태그의 id=main 내 클래스명이 lecs인 ul태그 내 li 전체를 가져온다.
for li in list_li :
print("li >>>", li.string) #다음과 같이 for문을 통해 list형태를 string으로 출력 시킬 수 있다.
|
cs |
download2-5-4.py
주석을 참고하면서 내용을 실행해보자.
선택자를 통하여 요소에 쉽게 접근이 가능하고, 값을 가져와서 출력 및 조작이 가능할 것이다.
'언어 > python&웹 크롤링' 카테고리의 다른 글
[python&웹 크롤링] 11. 네이버 금융 정보 가져오기 (0) | 2021.01.01 |
---|---|
[python&웹 크롤링] 10. BeautifulSoup 사용 및 웹 파싱 기초(2) (0) | 2020.12.28 |
[python&웹 크롤링] 8. youtube 동영상 다운로드 및 mp3 변환 (2) | 2020.12.09 |
[python&웹 크롤링] 7. urllib을 활용한 필요 데이터 추출하기(2) (0) | 2020.12.08 |
[python&웹 크롤링] 6. urllib을 활용한 필요 데이터 추출하기(1) (0) | 2020.11.26 |