이번에는 BeautifulSoup 이라는 강력한 파이썬 모듈을 이용하여 HTML 문서를 일고 파싱하는 방법에 대해서 알아보도록 하겠습니다.

자세한 내용은 공식 문서에서 확인 바랍니다.


설치

일단은 아래 명령어를 통해서 BeautifulSoup의 설치를 하도록 하겠습니다.

$ pip install BeautifulSoup4

그리고 URL을 열려면 urlopen이란 메소드도 필요합니다. 아래 명령어를 통해서 설치를 하도록 하겠습니다.

$ pip install urlopen

HTML이나 XML을 읽어서 BeautifulSoup 인스턴스 만들기

아래와 같이 BeautifulSoup()안에 urlopen(웹 사이트 주소)를 입력하면 웹 사이트 주소의 HTML을 읽어와서 BeautifulSoup의 인스턴스로 만들어 줍니다.

가장 기본 형태는 아래와 같습니다.

# 웹에서 가져오기
soup = BeautifulSoup(urlopen("웹 사이트 주소").read(), "Parser 종류")

또 다른 사용법은 아래와 같이 open()을 통해서 로컬 파일도 읽어올 수 있습니다. 두 번째 매개변수는 Parser 종류입니다.

# 로컬 파일에서 가져오기
soup = BeautifulSoup(open("로컬 파일 경로"), "Parser 종류")

지원하는 Parser 종류

  • "html.parser" : 빠르지만 유연하지 않기 때문에 단순한 HTML문서에 사용합니다.
  • "lxml" : 매우 빠르고 유연합니다.
  • "xml" : XML 파일에만 사용합니다.
  • "html5lib" : 복잡한 구조의 HTML에 대해서 사용합니다.

기본적인 사용 방법

BeautifulSoup 인스턴스가 만들어지면 아래와 같이 사용할 수 있습니다.

아래 예제에서 soupBeautifulSoup 인스턴스입니다. 그 다음 원하는 태그를 넣으면 해당 태그에 해당하는 것만 가져옵니다.

soup.태그

아래와 같이 사용할 수 있습니다.

soup = BeautifulSoup(urlopen("http://naver.com").read(), "html.parser")

soup.body # 위에서 가져온 문서의 body 태그만 가져옵니다.
soup.title # 위에서 가져온 문서의 title 태그만 가져옵니다.

soup.태그를 하면 해당 하는 태그를 가져올수 있습니다

(** 대신 여러개 있는 경우에는 맨 처음 발견한 하나만 가져옵니다.)

soup.head # <head> ... </head>에 해당하는 것들 가져옴
soup.body # <body> ... </body>에 해당하는 것들 가져옴
soup.a # <a> ... </a>에 해당하는 것들 가져오는데, 첫 발견 하나만 가져옴

그래서 여러개를 가져오고 싶을때, findall()을 이용하면 특정 태그에 해당하는 것만 모두 가져와서 리스트로 반환을 합니다.

soup.findAll("태그") # 이렇게 하면 "태그"에 해당하는 모든 글자를 가져와서 리스트로 반환합니다.

soup.findAll("a") # 이렇게 하면 a태그에 해당하는걸 모두 가져와서 리스트로 반환합니다.

아래와 같이 제한을 줄 수도 있습니다.

soup.find_all("a", limit=2) # a 태그에서 2개만 가져옴

title에서 String만 가져옵니다.(태그 제외)

soup.title.find_all(string=True)

limit를 이용해서 개수 제한을 둘 수도 있습니다.

soup.find_all("a", limit=2) # a 태그를 두개만 가져옴

get_text()를 이용해서 태그를 제외하고 글자만 가져오기

name_list = soup.findAll("span", {"class": "green"})

for name in name_list:
    print(name.get_text()) # get_text()는 현재 문서에서 모든 태그를 제거하고 텍스트만 들어 있는 문자열을 반환합니다


p 태그와 속성 값이 title 이 있는거

soup.find_all("p", "title")

) <p class="title"></p>

아래와 같이 조건을 좀 더 넣어서 응용 할 수도 있습니다.

soup.findAll("태그", "조건") # 이렇게 하면 "태그"에 해당하는 모든 글자를 찾아서 그 중에 "조건"에 해당하는 것을 리스트로 반환합니다.

soup.findAll("a", {"class":"hello"}) # 이렇게 하면 a태그에 해당하는걸 모두 가져와서 class가 hello인것만 가져옵니다.

['태그1', '태그2']을 이용해서 여러개의 태그를 동시에 검색할 수도 있습니다. (or 조건)

soup.find_all(["a", "b"]) # a 태그와 b 태그 찾기

속성 값 가져오기

soup.p['class']
soup.p['id']

보기 좋게 출력

soup.b.prettify()

간단한 검색

soup.body.b # body 태그 아래의 첫번째 b 태그
soup.a # 첫번째 a 태그

사용 예제

아래 예제는 NYT기사에서 p 태그 중에 class : story=body-text인 것들만 읽어서 text로 뽑는 예제입니다.

위의 내용들과 아래 예제를 참고하면 여러가지 응용을 할 수 있습니다.

# coding=utf-8
from bs4 import BeautifulSoup
from urllib import urlopen

# 웹 페이지를 읽고 soup을 만든다.
url = "https://www.nytimes.com/2018/03/15/world/europe/germany-food-bank-migrant-ban.html?hp&action=click&pgtype=Homepage&clickSource=image&module=photo-spot-region&region=top-news&WT.nav=top-news"
html = urlopen(url)
soup = BeautifulSoup(html.read(), "html.parser")

# 본문만 읽어오기
paragraph_list = soup.find_all("p", {"class":"story-body-text"})

for a in paragraph_list:
    print a.get_text()