티스토리 뷰

728x90
반응형

 

 

 

BeautifulSoup4 으로 크롤링을 하게 되면 기본적으로 두 가지 방식을 사용해서 크롤링을 하게 됩니다.

 

첫 번째, find 또는 find_all 방식으로 태그 요소와 속성을 중점으로 찾을 수 있습니다.

cartoons = soup.find_all('a', attrs={'class':'title'})

두 번째, select 또는 select_one 방식으로 CSS Selector 방식으로 요소들을 찾을 수 있습니다.

cartoons = soup.select('a.title')

 

둘 중에 한 가지만 사용해도 또는 둘 모두 동시에 사용해도 됩니다. 그리고 실제로 위 두 가지 방식의 사용 예시의 결과도 모두 동일합니다. 다만, 살짝 다른 점이라면 find_all 함수는 ResultSet 타입을 반환하는가하면 select는 list 타입으로 결과 값을 반환합니다.

>>> print(type(soup.find('a')))
<class 'bs4.element.Tag'>
>>> print(type(soup.select_one('a')))
<class 'bs4.element.Tag'>
>>> print(type(soup.find_all('a')))
<class 'bs4.element.ResultSet'>
>>> print(type(soup.select('a')))
<class 'list'>

 

만약 CSS Selector에 익숙하신 분이라면 select 방식을 사용하시는 것이 편할 것입니다. 다만 select 방식은 모든 CSS Selector을 지원하지 않고 가장 보편적으로 사용되는 케이스만 사용가능할 뿐더러 BeautifulSoup 이전 버전에서는 몇몇 selector을 아예 지원하지 않는 케이스도 있습니다. 이런 부분에서는 다소 불편함이 있을 수 있습니다.

 

하지만 현재 시점 기준으로 가장 최신버전이 4.9.3 버전입니다. 만약 4.7.0 이상 버전을 사용하고 계시다면 최근에 BeautifulSoup4에 추가된 CSS Selector 관련 모듈으로 SoupSieve 라고 있는데, 이 패키지가 포함되면서 CSS Selector 기능에 좀 더 보완이 되었다고 합니다. 최신버전을 사용하신다면 염려를 조금 덜 수 있을 것으로 보입니다.

 

그리고 find와 find_all 함수의 경우에는 BeautifulSoup 모듈에서 가장 대표적인 검색 API입니다. 그렇기 때문에 모듈 자체적으로 관련해서 정말 유용하고 다양한 API들을 사용할 수 있게 해줍니다. 그리도 당연히 select 함수와 마찬가지로 기본적으로 태그 요소, 속성 요소 모두 가릴 것 없이 잘 선택할 수 있습니다.

 

find 와 select 는 정말 분명한 차이가 있습니다. 동일한 기능을 할 수 있지만, 그 난이도 차이가 분명합니다. CSS Selector에 대해서 정말 깊게 알고 있지 않으면 select는 사용하기 쉽지 않습니다. 물론 작업의 난이도에 따라서도 달라집니다. 간단한 구조의 문서를 크롤링하는 것이라면 상관없지만, 엄청 복잡한 구조로 이루어진 문서를 크롤링하기 위해서는 그만큼 요소를 선택하는 문장도 복잡해질 것입니다.

 

아래 목록은 select 함수로 CSS Selector를 사용한 예시입니다. 당장에 아래 문법들에 익숙지 않다면 find 함수를 사용하는 것을 추천드립니다. (참고로 아래 예시는 복잡한 사용 예시가 아닙니다)

soup.select("title")
soup.select("p:nth-of-type(3)")
soup.select("body a")
soup.select("html head title")
soup.select("head > title")
soup.select("p > a")
soup.select("p > a:nth-of-type(2)")
soup.select("p > #link1")
soup.select("body > a")
soup.select("#link1 ~ .sister")
soup.select("#link1 + .sister")
soup.select(".sister")
soup.select("[class~=sister]")
soup.select("#link1")
soup.select("a#link2")
soup.select("#link1,#link2")
soup.select('a[href]')
soup.select('a[href="http://example.com/elsie"]')
soup.select('a[href^="http://example.com/"]')
soup.select('a[href$="tillie"]')
soup.select('a[href*=".com/el"]')

 

반면에 find 함수는 기본적으로 find_all 함수 뿐만 아니라 find_all_previous, find_previous, find_all_next, find_next, find_previous_siblings, find_previous_sibling, find_next_siblings, find_next_sibling, find_parents, find_parent 로 다양하게 지원하고 있으며, 다양한 키워드 매개변수로 name, attrs, string(text), limit, recursive 도 지원하고 있습니다.

soup.find_all(string="Elsie")
# ['Elsie']

soup.find_all(string=["Tillie", "Elsie", "Lacie"])
# ['Elsie', 'Lacie', 'Tillie']

soup.find_all(string=re.compile("Dormouse"))
# ["The Dormouse's story", "The Dormouse's story"]

def is_the_only_string_within_a_tag(s):
    """Return True if this string is the only child of its parent tag."""
    return (s == s.parent.string)

soup.find_all(string=is_the_only_string_within_a_tag)
# ["The Dormouse's story", "The Dormouse's story", 'Elsie', 'Lacie', 'Tillie', '...']

soup.find_all("p", class_="body strikeout")
# [<p class="body strikeout"></p>]

soup.find_all("a", attrs={"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>]

data_soup.find_all(attrs={"data-foo": "value"})
# [<div data-foo="value">foo!</div>]

soup.find_all(id=True)
# [<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.find_all(href=re.compile("elsie"), id='link1')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

soup.find_all("a", limit=2)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

위에서 string 은 이전 버전에서 text로 사용된 매개변수입니다. string은 단순 문자열 뿐만 아니라 list, 정규식, True/False, 심지어 Function 까지 들어갈 수 있습니다.

 

어떻게 보면 select, select_one 의 CSS Selector 방식과는 달리 find, find_all 방식은 BeautifulSoup 버전에 따라 달라지는 점에 대해 영향이 더 심하게 받을 수도 있겠다고 생각이 듭니다.

 

 

두 함수의 자세한 차이점에 대해서는 본 BeautifulSoup4 문서를 참고하시면 될 것 같습니다.

https://www.crummy.com/software/BeautifulSoup/bs4/doc/#find-all

 

Beautiful Soup Documentation — Beautiful Soup 4.9.0 documentation

Non-pretty printing If you just want a string, with no fancy formatting, you can call str() on a BeautifulSoup object (unicode() in Python 2), or on a Tag within it: str(soup) # ' I linked to example.com ' str(soup.a) # ' I linked to example.com ' The str(

www.crummy.com

 

728x90
반응형
댓글