-
파이썬 크롤링(Crawling) 연습 - BeautifulSoup Documentation #1 (html 태그로 접근, 객체 4종류 등)코딩 연습/코딩배우기 2020. 11. 7. 12:00
■ 파이썬 크롤링 BeautifulSoup Documentation 내용 정리 #1
html의 Element 구조 탐색(검색), 객체 4종류 (Tag, NavigableString, BeautifulSoup, Comment)
.contents
.children
.string
.parent
.paretns
.next_sibling
.previous_sibling
.next_element
.previous_elementBeautifulSoup은 HTML 및 XML 파일에서 데이터를 추출하는 파이썬 라이브러리이다.
BeautifulSoup version 4.9.2. 기준html_doc = '''<html><head><title>BeautifulSoup Document 기준</title></head> <body> <p class="title"><b>파이썬 크롤링 연습을 위한 포스팅</b></p> <p class="story">국회 법제사법위원회, 대검찰청 국정감사 유튜브 영상 <a href="https://youtu.be/_pOicsZstGo" class="sister" id="link1">김봉현 2차 폭로에 충격! 대검 침묵</a>, <a href="https://youtu.be/AZbCWck7or0" class="sister" id="link2">속속 드러나는 검찰 의혹..김종민 "옵티 계좌추적도 안하고 덮었다.</a> 그리고 <a href="https://youtu.be/kkfxzYaJhgI" class="sister" id="link3">김종민 가족수사 돌직구에 현타 온 윤석열</a></p> <p class="story">추가적으로, ...</p> ''' # 위 html_doc HTML코드와 파서(html.parser)를 인자로 받아 BeautifulSoup 실행하면 BeautifulSoup object를 반환한다. from bs4 import BeautifulSoup soup = BeautifulSoup(html_doc, 'html.parser') print(type(soup)) # <class 'bs4.BeautifulSoup'> print(soup.prettify()) # prettify()는 파싱 처리 후 트리 형태로 리턴하는 함수 ''' <html> <head> <title> BeautifulSoup Document 기준 </title> </head> <body> <p class="title"> <b> 파이썬 크롤링 연습을 위한 포스팅 </b> </p> <p class="story"> 국회 법제사법위원회, 대검찰청 국정감사 유튜브 영상 <a class="sister" href="https://youtu.be/_pOicsZstGo" id="link1"> 김봉현 2차 폭로에 충격! 대검 침묵 </a> , <a class="sister" href="https://youtu.be/AZbCWck7or0" id="link2"> 속속 드러나는 검찰 의혹..김종민 "옵티 계좌추적도 안하고 덮었다. </a> 그리고 <a class="sister" href="https://youtu.be/kkfxzYaJhgI" id="link3"> 김종민 가족수사 돌직구에 현타 온 윤석열 </a> </p> <p class="story"> 추가적으로, ... </p> </body> </html> ''' ### html_doc의 Element 구조를 탐색(검색)해보기 ### print(soup.title) ## title 태그 코드 # <title>BeautifulSoup Document 기준</title> print(soup.title.name) ## title 태그명 # title print(soup.title.string) ## title 태그의 문자열 # BeautifulSoup Document 기준 print(soup.title.parent.name) ## title 태그의 바로 위 태그 # head print(soup.p) ## p 태그 코드 (첫번째 p 태그) # <p class="title"><b>파이썬 크롤링 연습을 위한 포스팅</b></p> print(soup.p['class']) ## p 태그의 class 속성 값(리스트로 반환) # ['title'] print(soup.a) ## a 태그 코드 (첫번째 a 태그) # <a class="sister" href="https://youtu.be/_pOicsZstGo" id="link1">김봉현 2차 폭로에 충격! 대검 침묵</a> print(soup.find_all('a')) ## a 태그를 모두 찾아서 리스트로 반환 # [<a class="sister" href="https://youtu.be/_pOicsZstGo" id="link1">김봉현 2차 폭로에 충격! 대검 침묵</a>, # <a class="sister" href="https://youtu.be/AZbCWck7or0" id="link2">속속 드러나는 검찰 의혹..김종민 "옵티 계좌추적도 안하고 덮었다.</a>, # <a class="sister" href="https://youtu.be/kkfxzYaJhgI" id="link3">김종민 가족수사 돌직구에 현타 온 윤석열</a>] print(soup.find(id="link3")) ## id가 link3인 태그 찾아 반환(class='link3'인 경우 find()는 첫번째 하나만 반환함) # <a class="sister" href="https://youtu.be/kkfxzYaJhgI" id="link3">김종민 가족수사 돌직구에 현타 온 윤석열</a> for link in soup.find_all('a'): ## 반환된 리스트 객체에 대해 for문 적용 print(link.get('href')) ## 속성 href의 값 추출 # https://youtu.be/_pOicsZstGo # https://youtu.be/AZbCWck7or0 # https://youtu.be/kkfxzYaJhgI print(soup.get_text()) ## 모든 문자열 추출 # 파이썬 크롤링 연습을 위한 포스팅 # 국회 법제사법위원회, 대검찰청 국정감사 유튜브 영상 # 김봉현 2차 폭로에 충격! 대검 침묵, # 속속 드러나는 검찰 의혹..김종민 "옵티 계좌추적도 안하고 덮었다. 그리고 # 김종민 가족수사 돌직구에 현타 온 윤석열 # 추가적으로, ... for tag in soup.find_all('p'): ## .attrs는 dict로 속성:속성값 반환 print(tag.attrs) # {'class': ['title']} # {'class': ['story']} #{'class': ['story']} for tag in soup.find_all('a'): print(tag.attrs) # {'href': 'https://youtu.be/_pOicsZstGo', 'class': ['sister'], 'id': 'link1'} # {'href': 'https://youtu.be/AZbCWck7or0', 'class': ['sister'], 'id': 'link2'} # {'href': 'https://youtu.be/kkfxzYaJhgI', 'class': ['sister'], 'id': 'link3'}
객체 4종류 (Tag, NavigableString, BeautifulSoup, Comment)
# Tag soup = BeautifulSoup('<b class="boldest">볼드체</b>', 'html.parser') tag = soup.b print(tag) # <b class="boldest">볼드체</b> print(type(tag)) # <class 'bs4.element.Tag'> print(tag.name) # b tag.name = 'blockquote' ## 태그명 변경 print(tag) # <blockquote class="boldest">볼드체</blockquote> print(tag.attrs) ## 태그의 속성(attrs)명과 속성값을 dict로 반환 # {'class': ['boldest']} print(tag['class']) ## dict 키로 접근 # ['boldest'] tag = BeautifulSoup('<b id="boldest">BOLD</b>', 'html.parser').b print(tag['id']) # boldest print(tag.attrs) # {'id': 'boldest'} ### 다수의 속성값이 있는 경우 ### css_soup = BeautifulSoup('<p class="body"></p>', 'html.parser') print(css_soup.p['class']) # ['body'] css_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html.parser') print(css_soup.p['class']) # ['body', 'strikeout'] id_soup = BeautifulSoup('<p id="my id"></p>', 'html.parser') print(id_soup.p['id']) # my id rel_soup = BeautifulSoup('<p>홈으로 가기[<a rel="index">Home</a>]</p>', 'html.parser') print(rel_soup.a['rel']) # ['index'] rel_soup.a['rel'] = ['index', 'contents'] print(rel_soup.p) # <p>홈으로 가기[<a rel="index contents">Home</a>]</p> soup = BeautifulSoup('<b class="boldest">Extremely bold</b>', 'html.parser') tag = soup.b print(tag.string) # Extremely bold print(type(tag.string)) # <class 'bs4.element.NavigableString'> unicode_string = str(tag.string) print(unicode_string) # Extremely bold print(type(unicode_string)) # <class 'str'> tag.string.replace_with('No longer bold') ## replace_tith() print(tag) ### Comments ### markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>" soup = BeautifulSoup(markup, 'html.parser') comment = soup.b.string print(comment) # Hey, buddy. Want to buy a used parser? print(type(comment)) # <class 'bs4.element.Comment'>
### .contents and .children
markup = ''' <html> <head> <title>The Dormouse's story</title> </head> ''' soup = BeautifulSoup(markup, 'html.parser') head_tag = soup.head print(head_tag) #<head> #<title>The Dormouse's story</title> #</head> print(head_tag.contents) # ['\n', <title>The Dormouse's story</title>, '\n'] ## 줄바꿈 문자까지 대상으로 포함 print(len(head_tag.contents)) # 3 print(head_tag.contents[0]) # \n print(head_tag.contents[1]) # <title>The Dormouse's story</title> markup = '''<html><head><title>The Dormouse's story</title></head>''' soup = BeautifulSoup(markup, 'html.parser') head_tag = soup.head print(head_tag.contents) # [<title>The Dormouse's story</title>] print(len(head_tag.contents)) # 1 print(type(head_tag.contents)) # <class 'list'> print(head_tag.contents) # [<title>The Dormouse's story</title>] print(head_tag.contents[0]) # <title>The Dormouse's story</title> print(head_tag.contents[0].contents) # ["The Dormouse's story"] print(soup.contents) # [<html><head><title>The Dormouse's story</title></head></html>] print(soup.contents[0]) # <html><head><title>The Dormouse's story</title></head></html> print(soup.contents[0].name) # html print(soup.contents[0].contents) # [<head><title>The Dormouse's story</title></head>] #print(soup.contents[0].contents.contents) ## list에 .contents 불가 # AttributeError: 'list' object has no attribute 'contents' for h in soup.contents[0].contents: ## list에 대해 for문으로 처리 print(h.contents) ## == head.contents (soup.head.contents) # [<title>The Dormouse's story</title>] print(soup.contents[0].contents[0].contents) ## == head.contents # [<title>The Dormouse's story</title>] print('---',soup.contents[0].contents[0].contents[0]) ## == head.contents[0] # <title>The Dormouse's story</title> print(soup.contents[0].contents[0].contents[0].contents) ## == title.contents # ["The Dormouse's story"] for child in soup.contents[0].contents[0].contents[0]: print(child) ## == title.contents[0] # The Dormouse's story print(soup.contents[0].contents[0].children) ## .children은 generator # <list_iterator object at 0x0000016F5351EAC8> for child in soup.contents[0].children: print(child) # <head><title>The Dormouse's story</title></head>
### .string
markup = '''<html><head><title>The Dormouse's story</title></head>''' soup = BeautifulSoup(markup, 'html.parser') print(soup.string) # The Dormouse's story ## 태그 내에 하나 이상의 문자열이 있으면, .string은 참조하는 것이 불분명하여 None을 반환함 markup = '''<html><head><title>The Dormouse's story</title></head><body><p>and ...</p>''' soup = BeautifulSoup(markup, 'html.parser') print(soup.string) # None ## 태그 내에 하나 이상의 문자열이 있으면, .strings 제너레이터를 사용하여 해결함 for string in soup.strings: print(repr(string)) #"The Dormouse's story" #'and ...' ## .strings는 공백문자들이 포함되는데, 이를 제거하기 위해서는 .stripped_strings를 사용함 markup = ''' <html> <head> <title>The Dormouse's story</title> </head> <body> <p> and ... so, </p>''' soup = BeautifulSoup(markup, 'html.parser') for string in soup.strings: print(repr(string)) #"The Dormouse's story" #'and ...' #'\n' #'\n' #'\n' #"The Dormouse's story" #'\n' #'\n' #'\n' #' and ...\n so, \n' for string in soup.stripped_strings: print(repr(string)) #"The Dormouse's story" #'and ...\n so,'
### .parent and .paretns
markup = '''<html><head><title>The Dormouse's story</title></head>''' soup = BeautifulSoup(markup, 'html.parser') print(soup.title) # <title>The Dormouse's story</title> print(soup.title.parent) # <head><title>The Dormouse's story</title></head> print(soup.title.string) # The Dormouse's story print(soup.title.string.parent) # <title>The Dormouse's story</title> print(soup.html.parent) # <html><head><title>The Dormouse's story</title></head></html> print(type(soup.html.parent)) # <class 'bs4.BeautifulSoup'> print(soup.title) # <title>The Dormouse's story</title> print(soup.title.parents) # <generator object PageElement.parents at 0x0000016F53617318> for parent in soup.title.parents: print(parent) #<head><title>The Dormouse's story</title></head> #<html><head><title>The Dormouse's story</title></head></html> #<html><head><title>The Dormouse's story</title></head></html> for parent in soup.title.parents: print(parent.name) #head #html #[document]
### .next_sibling and .previous_sibling
## 트리 구조에서 동일 레벨 상의 요소를 사용할 수 있음 sibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></b></a>", 'html.parser') print(sibling_soup.prettify()) #<a> # <b> # text1 # </b> # <c> # text2 # </c> #</a> print(sibling_soup.b.next_sibling) # <c>text2</c> print(sibling_soup.c.previous_sibling) # <b>text1</b> print(sibling_soup.b.previous_sibling) # None print(sibling_soup.c.next_sibling) # None ## 문자열(string)은 sibling 안됨 print(sibling_soup.b.string) # text1 print(sibling_soup.b.string.next_sibling) # None ## sibling 사용 시, 주의사항 ## 태그와 태그 사이의 개행이나 콤마 등도 요소로 취급함에 주의! markup = ''' <p>Three sisters</p> <a href="#" class="sister" id="link1">Elsie</a>, <a href="#" class="sister" id="link2">Lacie</a>, <a href="#" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well. ''' soup = BeautifulSoup(markup, 'html.parser') print(repr(soup.p.next_sibling)) # '\n' print(soup.p.next_sibling.next_sibling) # <a class="sister" href="#" id="link1">Elsie</a> print(repr(soup.a.next_sibling)) # ',\n' print(repr(soup.a.next_sibling.next_sibling)) # <a class="sister" href="#" id="link2">Lacie</a> ## .next_siblings and previous_siblings ## 태그 sibling 전체 다루기 print(soup.p.next_siblings) # <generator object PageElement.next_siblings at 0x0000016F53615C78> for sibling in soup.p.next_siblings: print(sibling) # #<a class="sister" href="#" id="link1">Elsie</a> #, # #<a class="sister" href="#" id="link2">Lacie</a> #, # #<a class="sister" href="#" id="link3">Tillie</a> #; #and they lived at the bottom of a well. # #<a class="sister" href="#" id="link3">Tillie</a> #; #and they lived at the bottom of a well. #
### .next_element and .previous_element
last_a_tag = soup.find("a", id="link3") print(last_a_tag) # <a class="sister" href="#" id="link3">Tillie</a> print(last_a_tag.next_sibling) #; #and they lived at the bottom of a well. print(last_a_tag.next_element) ## a 태그의 다음 문장이 아닌 그 자체의 단어임 # Tillie ## 마크 업에서 <a> 태그, "Tillie", </a> 태그, 세미콜론, 나머지 문장 중에서 ## 세미콜론은 <a> 태그와 같은 수준에 있지만 "Tillie"라는 단어가 먼저 발견되었음 print(repr(last_a_tag.previous_element)) # ',\n' for element in last_a_tag.next_elements: ## next_elements print(repr(element)) #'Tillie' #'\nand they lived at the bottom of a well.\n'
[참고] Beautiful Soup 4.9.0 documentation https://www.crummy.com/software/BeautifulSoup/bs4/doc/
'코딩 연습 > 코딩배우기' 카테고리의 다른 글
파이썬으로 아스키(ASCII) Code 출력, 그리고 영문자에 대한 진수값들 (0) 2020.11.08 파이썬 크롤링(Crawling) 연습 - BeautifulSoup Documentation #2 (find_all, find, select 등) (0) 2020.11.08 파이썬 크롤링(Crawling) 연습 - 네이버 영화 평점/리뷰, 영화코드 추출 (0) 2020.11.04 파이썬 크롤링(Crawling) 연습 - BeautifulSoup 활용 기초 (0) 2020.11.03 파이썬 크롤링(Crawling) 연습 - Daum에서 검색한 전화번호의 기본 정보 추출 (0) 2020.11.01