저번 포스팅에 이어서 원하는 탭으로 이동하였고 원하는 정보를 수집할 수 있게 되었다. 이번에는 셀레니움을 이용하여 로딩한 페이지의 html을 추출하고 beautifulsoup 사용 방법을 간단하게 정리하였다.
1. Beautifulsoup 설치
먼저 html을 크롤링하고 파싱하기 위해서는 BeautifulSoup 패키지가 필요하다. 아나콘다를 사용하면 이미 설치되어 있지만 아니라면 pip 를 이용하여 패키지를 설치해야한다.
$ pip install bs4
2. selenium으로 로딩한 페이지의 HTML 파싱
먼저 selenium을 통해 해당 페이지의 html 소스를 가져온다. 이 html 소스를 beautifulsoup에 넣어주면 태그명, css 클래스명, id, css selector 등으로 html 파싱이 가능하다.
# 페이지 소스 가져오기
html = driver . page_source
# soup에 넣어주기
soup = BeautifulSoup ( html , 'html.parser' )
print ( soup . text )
3. BeautifulSoup 시작하기
예시 HTML 구조로 BeautifulSoup 문서에 있는 html 코드를 이용하였다.
from bs4 import BeautifulSoup
html = """<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>and they lived at the bottom of a well.</p>
<p class="story">...</p>"""
soup = BeautifulSoup ( html , 'html.parser' )
html 파일을 예쁘게 보고싶다면 아래의 함수를 이용하여 출력 가능하다.
print ( soup . prettify ())
soup을 이용한 html 구조는 트리 구조를 띈다. 따라서 soup을 이용하여 다음과 같은 접근이 가능하다.
# soup 내의 text 모두 추출
print ( soup . get_text ())
# "The Dormouse's story\n\nThe Dormouse's story\nOnce upon a time there were three little sisters; and their names were\nElsie,\nLacie and\nTillie;\nand they lived at the bottom of a well.\n..."
soup . title
# <title>The Dormouse's story</title>
soup . title . name
# 'title'
soup . title . string
# "The Dormouse's story"
4. BeautifulSoup 태그 파싱
위의 html 구조 예시에서 a 태그를 모두 수집하고 싶다면 위처럼 단순 트리구조가 아닌 find_all()이라는 함수를 이용하면 된다. find_all() 함수는 해당 조건에 맞는 모든 값들(여러개)을 리스트로 반환해준다. 맨 처음 1개의 값만 받고 싶다면 find() 함수를 사용하면 된다. find_all() 사용방법은 아래와 같다.
# 단순히 tree 구조로 검색하면 맨 위에 있는 a 태그만 추출할 수 있다.
soup . a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
# 태그명으로 찾기(a 태그 모두 수집)
soup . find_all ( 'a' )
#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
css 클래스 명과 태그 id로도 파싱이 가능하다. python의 class와 구분하기 위해서 파라미터는 class_ 를 사용한다.
# css class 명으로 찾기(class 이름이 sister인 태그 모두 수집)
soup . find_all ( class_ = 'sister' )
#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
# a 태그의 css class 이름이 'sister'인 태그 모두 수집
soup . find_all ( 'a' , class_ = 'sister' )
#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
# id 가 link1인 태그 수집
soup . find_all ( id = 'link1' )
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
css selector를 이용한 파싱도 가능하다. find_all() 함수 대신 select()라는 함수를 사용한다. css selector 값은 크롬 개발자 도구를 이용하면 쉽게 값을 알아낼 수 있다.(태그 select -> 마우스 오른쪽 버튼 -> copy -> copy selector)
soup . select ( 'title' )
# [<title>The Dormouse's story</title>]
# 3번째 p 태그
soup . select ( 'p:nth-of-type(3)' )
# [<p class="story">...</p>]
# body 태그 안의 a 태그 모두
soup . select ( 'body p' )
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup . select ( 'body > a' )
# [] -> '>'를 사용할 때는 태그 순서를 고려해야한다.
# 반드시 '>' 양 옆에는 띄어쓰기를 해야한다. (body>a 는 올바른 결과를 찾을 수 없음)
# p 태그 안의 a 태그 모두
soup . select ( 'p > a' )
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
# p 태그 안에 id가 link1인 태그
soup . select ( 'p > #link1' )
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
# id가 link1과 link2인 태그 모두
soup . select ( '#link1, #link2' )
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
# a태그이고 id가 link1인 태그
soup . select ( 'a#link1' )
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
# css 클래스가 sister인 태그 모두(두 코드 결과 같음)
soup . select ( '.sister' )
soup . select ( '[class~=sister]' )
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
# id가 link1이고 css 클래스가 sister인 태그의 자매(sibilings) 태그들 (같은 계층)
# '~' 양 옆에 띄어쓰기 필수
soup . select ( '#link1 ~ .sister' )
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
# id가 link1이고 css 클래스가 sister인 태그의 바로 옆의 자매(sibling) 태그
# '+' 양 옆에 띄어쓰기 필수
soup . select ( '#link1 + .sister' )
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
이외에도 find_next_siblings(), find_next_sibling(), find_previous_siblings(), find_previous_sibling() 같은 탐색 함수와 다양한 기능의 파싱 함수들도 제공한다. 위의 내용은 beautifulsoup를 다루기 위한 기본적인 내용들이며 자세한 사항들은 beautifulsoup 공식 문서 를 참고하면 예시와 함께 자세히 설명되어 있다.
reference
https://kiddwannabe.blog.me/221288079822
https://www.crummy.com/software/BeautifulSoup/bs4/doc/