파이썬으로 웹 크롤러 만들기 - 2장

Jajuna_99·2022년 9월 25일
0

2장 고급 HTML 분석

데이터가 깊숙히 파묻혀 있거나 (여러 태그들 속에) 졍형화되지 않을수록, 예상치 못한 결과가 나온다. -> (p.38)에 주의사항을 한번 보자.

위 같은 상황을 위해서 이번 장에서는 태그의 위치, 문맥, 속성, 콘택츠에 따라 태그를 선택하는 방법에 대해 다시말해, 스킬에 대해 배운다.

다시 BeautifulSoup (p.39)

웹 페이지를 파헤치는 첫 번째 방법으로 CSS 스타일시트의 속성을 통해 검색하는 방법이 있다.

from urllib.request import urlopen
from bs4 import BeautifulSoup

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

nameList = bs.findAll('span', {'class': 'green'})
for name in nameList:
    print(name.get_text())

위처럼 BS의 findAll 함수를 호출하면, 페이지 전체의 태그들을 그 중 속성이 green인 태그의 text들만 출력하게 된다. -> 본인 깃헙에 주석과 같이 올림

findAll()와 find()

위에서 사용한 findAll()와 find() 함수를 알아보자

  • findAll(tag, attributs, recursive, text, limit, keywords)
  • find(tag, attributs, recursive, text, keywords)
    • tag - 태그 이름, 리스트(딕셔너리)로 받아서 일치하는 태그들을 찾는다.
    • attribute - 속성 이름
    • recursive - 불리언 값을 받으며, True일 시 매개변수에 일치하는 태그와 그 모든 자식 태그들을 검색한다. False일 시 최상위 부모 태그만 검색. (findAll()은 기본적으로 True)
    • text - 태그안에 컨텐츠를 검색하는 변수를 받는 매개변수
    • limit - 검색하는 항목의 개수를 받는 매개변수(findAll()에서만 사용)
    • keyword - 특정 속성이 포함된 태그를 선택할 때 사용 (p.42)참고

BeautifulSoup 객체

책에서는 4가지 BS 객체를 소개한다.

  • BS 객체 - 이전 코드 예제에서 bs롤 가져와서 사용한 형태
  • Tag 객체 - 리스트 호출 또는 BS 객체에 find, findAll을 호출해서 탐색 ex)bs.div.h1

위에 2객체는 이미 구현 해보았다.

  • NavigableString 객체 - 태그 안에 들어 있는 텍스트를 찾는데 사용
  • Comment 객체 - HTML 주석을 찾는데 사용

트리 이동

위에서는 트리를 단방향으로 이동하면서 찾는 방법만 찾아봤다. -> ex) bs.div.h1

문서 안에서의 위치를 기준으로 태그를 찾는 방법도 있다.

from urllib.request import urlopen
from bs4 import BeautifulSoup

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

img = bs.div.findAll("img")

for child in bs.find('table',{'id' : 'giftList'}).children:
    print(child, img)
    
for siblings in bs.find('table',{'id' : 'giftList'}).tr.next_siblings:
    print(siblings)

print(bs.find('img',{'src' : '../img/gifts/img1/jpg'}).parent.previous_sibling.get_text())

역시 명료한 코드이다. 자세한 내용은 깃헙에.

주의사항

  • children()함수 대신 descendants()함수를 쓴다면 자식들만 검색하는게 아니라 테이블에 포함된 모든 태그들을 검색한다.
  • siblings for문에서는 .tr로 해도 같은 결과가 나온다. -> 시시각각 변하는 레이아웃에 대응하지 못하기 때문에 위와 같이 복잡하게 작성

정규 표현식(regular expression)(p.49)

정규 표현식 - 선형 규칙을 연달아 적용해 생성할 수 있는 문자열 즉, 조합논리 AND, OR등을 조합해 문자열 표현한 것이다.

널리 쓰이는 정규 표현식을 테이블로 작성해 놓은 (p.50)참고

정규 표현식과 BeautifulSoup(p.53)

정규 표현식을 BS에 사용할 수 있다.

from urllib.request import urlopen
from bs4 import BeautifulSoup
#정규 표현식
import re

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

역시 자세한 설명은 넘어가겠다.

속성에 접근하기(p.54)

print(bs.find(myImgTag.attrs['src']))

위와 같은 방법으로 이미지의 소스 위치를 찾을 수 있다.

람다 표현식(lambda expression)(p.55)

람다 표현식 - 다른 함수에 변수로 전달되는 함수 다시말해, 다변수 함수, 그 안에 함성함수 등 맘대로 표현하는 것이다.

#태그들 중 속성이 정확히 2개 있는 
print(bs.findALL(lambda tag: len(tag.attrs) == 2))

#결과는 같으나 bs 기본 함수로도 같은 결과를 낼 수 있다는 것을 보여줌
print(bs.findALL(lambda tag: tag.get_text() == 'Or maybe he\'s only resting?'))
print(bs.findALL('', text= 'Or maybe he\'s only resting?'))

역시 설명은 생략.

작가님 말로는 람다 함수의 문법을 이해, 기억하면 나머지 문법을 다 잊어도 원하는 일(아마 검색인듯 하다.)을 모두 할 수 있다고 한다. 🙄

요약

여러가지 스크레이퍼 필터링 검색 기법을 알아보는 장이었다.

profile
Learning bunch, mostly computer and language

0개의 댓글