본문 바로가기
Python/BeautifulSoup

[파이썬 Python] 웹크롤링 : BeautifulSoup 간단히 살펴보기 (with Code)

by newstellar 2017. 12. 31.
반응형

1.2.2.

import urllib
from bs4 import BeautifulSoup
from urllib.request import urlopen

html = urlopen("http://pythonscraping.com/pages/page1.html")
bs0bj = BeautifulSoup(html.read(), "html.parser")
print(bs0bj.html.body.h1, bs0bj.h1)

 


1.2.3.

from urllib.request import urlopen, HTTPError
from bs4 import BeautifulSoup

try:
    html = urlopen("http://www.pythonscraping.com/pages/error.html")
except HTTPError as e:
    print(e)    # null을 반환하거나, break문을 실행하거나, 기타 다른 방법 사용
else:
    bs0bj = BeautifulSoup(html.read(), "html.parser")
    print(bs0bj)    -> HTTP Error 404: Not Found

 

def getTitle(url):
    try:
        html = urlopen(url)
    except HTTPError as e:
        return None
        
    try:
        bs0bj = BeautifulSoup(html.read(), "html.parser")
        title = bs0bj.body.h1
    except AttributeError as e:
        return None
        
    return title
    
title = getTitle("http://pythonscraping.com/pages/page1.html")
if title == None:
    print("Title could not be found")
else:
    print(title)

 


2.2.0.

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("http://www.pythonscraping.com/pages/warandpeace.html")
bs0bj = BeautifulSoup(html, "html.parser")

nameList = bs0bj.findAll("span", {"class":"green"})
for name in nameList:
    print(name.get_text())# get_text()는 태그를 제거한 문자열만 반환. 
    #마지막까지 태그 구조를 가능한 유지해야 하기때문에 최종 데이터 출력 직전에만 씀.
print(len(bs0bj.findAll(text = "the prince")))

 

 

 

2.2.1. find()와 findAll() 

 

(1) findAll(tag, attributes, recursive, text, limit, keywords)

(2) find(tag, attributes, recursive, text, keywords)

 

  • .findAlll({"h1", "h2", "h3", "h4", "h5", "h6"}) 은 문서의 모든 헤더 태그 리스트를 반환합니다.
  • .findAll("span", {"class":{"green", "red"}}) 은 녹색과 빨간색 span 태그를 모두 반환합니다.

 

# recursive 매개변수가 True이면 그에 일치하는 태그를 찾아, 자식과 자식의 자식을 검색합니다. False이면 최상위 태그만 검색하게 됩니다.

 

 

# text 매개변수는 태그의 속성이 아니라 텍스트 콘텐츠에 일치합니다.

 

 

# keyword 매개변수는 특정 속성이 포함된 태그를 선택할 때 사용합니다.

bs0bj.findAll(id="text")[0].get_text()

 

 

# class는 파이썬 예약어이므로 _나 따옴표 안에 넣어서 변수로 씁니다.

bs0bj.findAll(class="green")

 -> 오류가 납니다.

 

    

# 태그 목록을 .findAll()에 속성 목록으로 넘기면 or처럼 동작하여 모든 태그 목록을 선택하게 됩니다. (불필요한 것도 잔뜩 선택됩니다.) 대신 keyword 매개변수는 and처럼 동작하므로 그런 문제는 없으니 안심해도 됩니다.

 

 

 

 


2.2.2. 기타 BeautifulSoup 객체

 

1. Tag 객체 : 리스트 호출 또는 BeautifulSoup객체에 find와 findAll을 호출해서 탐색.

    bs0bj.div.h1

    

2. NavigableString 객체 : 태그 자체가 아닌 태그 안의 텍스트.

 

3. Comment 객체 : 주석 태그 안의 HTML주석(<!-- like this one-->)을 찾는데 사용

 


2.2.3. 트리 이동

  • 이름과 속성에 따라 태그를 찾는 findAll과 달리 위치를 기준으로 찾자.

  •  bs0bj.tag.subTag.anotherSubTag
    - 단방향으로 BeautifulSoup 트리를 이동.

  •  BeautifulSoup함수는 항상 현재 선택된 태그의 자손을 다룹니다. 자식만 찾을 때는 .children을 사용합니다.

 

ex) bs0bj.body.h1은 body의 자손인 첫 번째 h1태그를 선택합니다. body 바깥의 태그에는 동작하지 않습니다.

 

ex) bs0bj.div.findAll("img")는 첫 번째 div를 찾고 그 자손인 모든 img 태그 목록 가져옵니다.

 

 

# 자식과 자손.
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bs0bj = BeautifulSoup(html, "html.parser")

for child in bs0bj.find("table", {"id":"giftList"}).children:
    print(child)

    

 

  • children() 대신 descendants()를 썼으면 테이블에 포함된 태그가 20개 이상 출력됐을 것입니다.
    - img, span, td 등
# 형제 다루기
for sibling in bs0bj.find("table", {"id":"giftList"}).tr.next_siblings:
    print(sibling)      # child랑 비교하면, sibling은 제품 테이블의 첫 번째 행을 제외한 제품 행임.

    

 

  • 태그 속성 활용!
    - 페이지 레이아웃을 잘 변하므로 스크레이퍼 견고성을 위해 태그를 명확히 선택하자.
# 부모 다루기
print(bs0bj.find("img", {"src":"../img/gifts/img1.jpg"}).parent.previous_sibling.get_text())
    # 위 코드는 이미지가 나타내는 객체의 가격을 출력. 마지막 <td>와 부모가 같은 바로 위 형제인 가격 <td>를 선택.

    


2.3. 정규 표현식과 BeautifulSoup

  • 제품 이미지 URL을 수집할 때는 모든 이미지 태그를 가져오는 대신 정규표현식을 통해 불필요한 태그를 없앱니다.
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bs0bj = BeautifulSoup(html, "html.parser")
images = bs0bj.findAll("img", {"src":re.compile("\.\.\/img\/gifts/img.*\.jpg")})
for image in images:
    print(image["src"])

    


2.4. 속성에 접근

  •  예를 들어 이미지의 소스 위치는 myImgTag.attrs['src']와 같이 찾을 수 있습니다.

 


2.5. 람다 표현식

  • 람다 표현식은 다른 함수에 변수로 전달되는 함수입니다.

  • BS에서는 특정 타입의 함수를 findAll에 매개변수로 넘길 수 있습니다.

  • 모든 태그 객체를 이 함수에서 평가하고, true로 평가된 태그만 반환합니다.
    (불리언만 반환되는 제약)

 

ex)

soup.findAll(lambda tag: len(tag.attrs) == 2)

> <div class="body" id="content"></div>

> <span style="color:red" class="title"></span>

 

 

  • 약간의 코드로 정규 표현식을 대체하는 선택자를 만들 수 있다는 점에서 람다 함수를 씁니다.
반응형

댓글