고급 HTML 분석

Koo·2023년 8월 7일
post-thumbnail

Scraping을 할 때는 원하지 않는 내용을 깍아내서 필요한 정보만을 얻어야 한다

주의점

여러 줄의 코드를 이용해 정보를 추출할 때는 곧바로 코드를 짜지 말고, 방법에 대해 고민하는 과정이 필요

  • '페이지 인쇄'같은 링클 찾거나, 더 나은 HTML 구조를 갖춘 모바일 버전 사이트를 사용
  • javascript 파일에 숨겨진 정보 사용
  • page URL 정보 사용
  • 다른 web site에 같은 데이터가 있는지 확인

BeautifulSoup 활용

  1. 속성을 통해 tag를 검색하는 방법
  2. tag 목록을 다루는 방법
  3. tree navigation을 분석하는 방법

1. 속성을 통해 tag를 검색하는 방법

  • 모든 web site에는 stylesheet가 존재
  • CSS는 html 요소를 구분하여 서로 다른 스타일을 적용

    <span class="green"> </span>, <span class="red"> </span>와 같은 tag가 있을 때,
    ->클래스를 이용해 쉽게 tag를 구분 가능

from urllib.request import urlopen
from bs4 import BeautifulSoup

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

nameList = bsObj.findAll('span', {'class': 'green'}) # span tag 중 class가 green인 tag
for name in nameList:
	print(name.get_text())

findall 함수

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

  • tag - 문자열을 넘기거나 tag 이름으로 이루어진 list를 전달
  • attributes - dict를 받아, 그 중 하나에 일치하는 tag를 탐색
  • recursive: boolean - 매개변수와 일치하는 tag를 찾은 후, 그 자손 tag까지 탐색
  • text: boolean - tag의 속성이 아니라 text에서 매개변수와 일치하는 값을 탐색
  • limit: int - 최대 몇 개의 tag를 탐색할지
  • keyword - 특정 속성이 포함된 tag를 탐색

findall 함수에 속성 목록을 넘기면 OR 필터처럼 동작하기 때문에 태그 목록이 길어진다.
keyword 매개변수는 AND 필터처럼 동작

BeautifulSoup 객체

  1. BeautifulSoup 객체
    • html 파일을 parsing하여 객체로 지정
  2. Tag 객체
    • find 함수나 findAll 함수를 호출하여 탐색하여 얻음
  3. NavigableString 객체
    • tag 자체가 아니라 tag 안에 들어있는 텍스트를 나타냄
    • 일부 함수는 NavigableString을 다루거나 반환
  4. Comment 객체
    • 주석 tag 안에 들어있는 HTML 주석을 찾을 때 사용

2. tree 이동

문서 안에서의 위치를 기준으로 tag를 찾을 때 tree navigation을 사용

자식과 자손

  • 자식(children) - 부모 tag보다 한 tag 아래 tag
    • 자식만 찾을 때는 .children 사용
  • 자손(descendants) - 부모 tag 아래 존재하는 모든 하위 tag들
    • findAll 함수를 사용하면 하위에 있는 tag들을 모두 포함시킬 수 있음

next_siblings

  • next_siblings 함수를 사용하면 table에서 data를 쉽게 수집 가능
  • table에 title행이 있을 때 유용
from urllib.request import urlopen
from bs4 import BeautifulSoup

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

for sibling in bsObj.find('table', {'id': 'giftList'}).tr.next_siblings:
	print(sibling)
  • 객체의 형제(sibling)를 가져올 때, 객체 자신은 해당 목록에서 제외된다
  • title 행을 선택하고 next_siblings를 사용하면 title행을 제외한 모든 table 행을 선택하게 됨

previous_siblings

  • tag 목록의 마지막에 있는 tag를 쉽게 선택할 수 있을 때 사용

parent

  • 보통 맨 위 계층에서 시작하여 아래로 내려가며 데이터를 탐색
  • 아래에서 시작하여 부모를 찾는 경우 parent를 사용
from urllib.request import urlopen
from bs4 import BeautifulSoup

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

print(bsObj.find('img', {'src': '../img/gifts/imgs1.jpg'
		}).parent.previous_siblings.get_text())

정규표현식

기호 의 미 예 제 일치하는 문자열 예제
* 바로 앞에 있는 문자, 하위표현식, 대괄호로 묶인 문자를 0번 이상 나타냄 a*b* ab, aabbb, abb, aaab, ''(빈 문자열)
+ 바로 앞에 있는 문자, 하위표현식, 대괄호로 묶인 문자를 1번 이상 나타냄 a+b+ ab, aaabb, abbb, aaaaaaabbbbb
[] 대괄호 안에 있는 문자 중 하나를 나타냄 [A-Z]* APPLES, CAPITALS, QWERTY
() group으로 묶인 하위 표현식. 정규 표현식 평가시 가장 먼저 평가되는 항목 (a*b)* aabaab, abaaba, ababaaaaab, bbbbbb
{m, n} 바로 앞에 있는 문자, 하위표현식, 대괄호로 묶인 문자들을 m번 이상, n번 이상 나타냄 a{2, 3}b{2, 3} aabbb, aaabbb, abb
[^] 대괄호 안에 있는 문자를 제외한 문자를 나타냄 [^A-Z]* apple, lowercase, qwerty
| |로 분리된 문자, 하위표현식 중 하나를 나타냄 b(a|i|e)d bad, bid, bed
. 문자하나를 나타냄 (와일드 카드) b.d bad, bzd, b$d, b d ...
^ 바로 뒤에 오는 문자 혹은 하위표현식이 문자열의 맨 앞에 나타남 ^a apple, asdf, a
\ 특수 문자를 원래 문자 그대로 사용 \., \|, \\ ., |, \
$ 정규표현식 마지막에 주로 사용.
바로 앞에 오는 문자 또는 하위표현식이 문자열의 마지막에 나타남
[A-Z]*[a-z]$ ABCabc, zzzyx, Bob
?! 포함하지 않는다는 의미. 바로 다음에 오는 문자는 해당 위치에 나타나지 않음
특정 문자를 완전히 배제하려면 ^, $와 함께 사용
^((?![A-Z]).)*$ no-caps-here, $ymb0ls a4e fine

정규 표현식을 사용하면 내가 원하는 tag만을 추출할 수 있음
tag 자체를 식별하는 무언가를 찾아야 한다

from urllib.request import urlopen
from bs4 import BeautifulSoup

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

images = bsObj.findAll('img', {'src': re.compile('\.\.\/img\/gifts/img.*\.jpg')})
for image in images:
print(image['src'])

정규 표현식을 이용하면 매우 유연하게 원하는 tag를 탐색 가능

속성에 접근

  • web scraping을 할 때는 tag의 내용이 아닌 tag의 속성의 관심이 있는 경우도 존재
  • URL의 href 속성에 있는 a tag, image가 src 속성에 있는 img tag 등 ...
myTag.attrs
myImgTag.attrs['src'] # dict 객체임을 감안하여 접근 가능

labmda 표현식

lambda 표현식을 이용해 탐색을 할 수 있다

soup.findAll(lambda tag: len(tag.attrs) == 2) # 속성이 2개인 tag 탐색

# <div class="body" id="content"></div>
# <span style="color:red" class="title"></span>
profile
스터디를 해보자

0개의 댓글