cs/크롤링

[크롤링] 고급 HTML 분석 (findAll/get_text()/트리이동/정규표현식/람다표현식)

신_이나 2023. 2. 28. 20:20

 

 

 

[파이썬으로 웹 크롤러 만들기 - 라이언 미첼, 한빛미디어] 의 내용을 바탕으로 공부한 내용입니다.

작성한 글의 모든 저작권은 한빛미디어에 있습니다.

 

 

part1. 스크레이퍼제작 - chapter 1~2

 

저자가 제시하는 페이지를 통해 초록색 글씨만 추출해보자!

 

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen('https://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())

라는 코드를 작성하면 위 페이지에서 초록색으로 쓰인 글자만 추출이 된다.

 
 
from urllib.request import urlopen
from bs4 import BeautifulSoup
 
urllib.request 라는 명령어는 처음 봤는데 이는 url을 열기 위한 확장 가능한 라이브러리다
urlopen 을 통해 url 을 열 수 있다.
그리고 아래는 여러 tag 들을 불러올 수 있는 BeautifulSoup 를 선언하였다.
 
 
 
bs = BeautifulSoup(html, 'html.parser')

책에서 제공하는 페이지를 열었고 url 을 html 에 저장하였다.

html.parser 란 원하는 부분만 가져오기 위해서 사용하는 모듈이다. 구문 분석기라고도 한다. 구문 분석기에는 파서 말고도 여러가지가 있는데, 형식을 지키지 않은 '지저분한' html 코드를 분석할 때는 html.parser 대신 lxml 을 사용해줄 수 있다. 예를 들어, 닫히지 않은 태그, <head> 등의 태그가 없는 등의 문제를 해결할 수 있다. 또한 html5lib 는 lxml 보다 더 다양한 에러를 수정할 수 있지만 앞서 말한 두 개의 분석기보다 조금 느리다는 단점이 있다. html.parser 를 계속 사용할 예정인데 그 이유는 파이썬을 설치할 때 같이 설치되어 따로 다운받을 필요가 없기 때문이다! (비교적 간단한 이유)

 

BeautifulSoup 괄호 안에 있는 첫 번째 매개변수는 html 의 text 이다. 뒤에는 구문 분석기다.

 

 

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

findAll 라는 함수는 고유명사로 이루어진 파이썬 리스트를 추출할 수 있다.

get_text() 는 현재 문서에서 모든 태그를 제거한 뒤 유니코드 텍스트에만 들어 있는 문자열을 반환하는 함수다. 출력하기 직전에 사용해야만 한다. 왜냐면 일반적으로는 문서의 태그 구조를 유지해야 하기 때문이다.

 

 

---------------------------------------------------------------------------------------------------

 

자식과 자손의 구분

 

for child in bs.find('table', {'id': 'giftList'}).child:
	print(child)

위와 같은 코드가 있었다고 가정할 때, .child 와 .descendants 는 다른 결과를 나타낸다.

child 는 giftList 의 자식만 추출되는 반면에 descendants 는 테이블에 포함된 태그가 자손까지 추출된다. 결과를 비교해보자

 

 

- .child 

더보기

<tr><th>

Item Title

</th><th>

Description

</th><th>

Cost

</th><th>

Image

</th></tr>

 

 

<tr class="gift" id="gift1"><td>

Vegetable Basket

</td><td>

This vegetable basket is the perfect gift for your health conscious (or overweight) friends!

<span class="excitingNote">Now with super-colorful bell peppers!</span>

</td><td>

$15.00

</td><td>

<img src="../img/gifts/img1.jpg"/>

</td></tr>

 

 

<tr class="gift" id="gift2"><td>

Russian Nesting Dolls

</td><td>

Hand-painted by trained monkeys, these exquisite dolls are priceless! And by "priceless," we mean "extremely expensive"! <span class="excitingNote">8 entire dolls per set! Octuple the presents!</span>

</td><td>

$10,000.52

</td><td>

<img src="../img/gifts/img2.jpg"/>

</td></tr>

 

 

<tr class="gift" id="gift3"><td>

Fish Painting

</td><td>

If something seems fishy about this painting, it's because it's a fish! <span class="excitingNote">Also hand-painted by trained monkeys!</span>

</td><td>

$10,005.00

</td><td>

<img src="../img/gifts/img3.jpg"/>

</td></tr>

 

 

<tr class="gift" id="gift4"><td>

Dead Parrot

</td><td>

This is an ex-parrot! <span class="excitingNote">Or maybe he's only resting?</span>

</td><td>

$0.50

</td><td>

<img src="../img/gifts/img4.jpg"/>

</td></tr>

 

 

<tr class="gift" id="gift5"><td>

Mystery Box

</td><td>

If you love suprises, this mystery box is for you! Do not place on light-colored surfaces. May cause oil staining. <span class="excitingNote">Keep your friends guessing!</span>

</td><td>

$1.50

</td><td>

<img src="../img/gifts/img6.jpg"/>

</td></tr>

 

- .descendants

더보기

<tr><th>
Item Title
</th><th>
Description
</th><th>
Cost
</th><th>
Image
</th></tr>
<th>
Item Title
</th>

Item Title

<th>
Description
</th>

Description

<th>
Cost
</th>

Cost

<th>
Image
</th>

Image



<tr class="gift" id="gift1"><td>
Vegetable Basket
</td><td>
This vegetable basket is the perfect gift for your health conscious (or overweight) friends!
<span class="excitingNote">Now with super-colorful bell peppers!</span>
</td><td>
$15.00
</td><td>
<img src="../img/gifts/img1.jpg"/>
</td></tr>
<td>
Vegetable Basket
</td>

Vegetable Basket

<td>
This vegetable basket is the perfect gift for your health conscious (or overweight) friends!
<span class="excitingNote">Now with super-colorful bell peppers!</span>
</td>

This vegetable basket is the perfect gift for your health conscious (or overweight) friends!

<span class="excitingNote">Now with super-colorful bell peppers!</span>
Now with super-colorful bell peppers!


<td>
$15.00
</td>

$15.00

<td>
<img src="../img/gifts/img1.jpg"/>
</td>


<img src="../img/gifts/img1.jpg"/>




<tr class="gift" id="gift2"><td>
Russian Nesting Dolls
</td><td>
Hand-painted by trained monkeys, these exquisite dolls are priceless! And by "priceless," we mean "extremely expensive"! <span class="excitingNote">8 entire dolls per set! Octuple the presents!</span>
</td><td>
$10,000.52
</td><td>
<img src="../img/gifts/img2.jpg"/>
</td></tr>
<td>
Russian Nesting Dolls
</td>

Russian Nesting Dolls

<td>
Hand-painted by trained monkeys, these exquisite dolls are priceless! And by "priceless," we mean "extremely expensive"! <span class="excitingNote">8 entire dolls per set! Octuple the presents!</span>
</td>

Hand-painted by trained monkeys, these exquisite dolls are priceless! And by "priceless," we mean "extremely expensive"! 
<span class="excitingNote">8 entire dolls per set! Octuple the presents!</span>
8 entire dolls per set! Octuple the presents!


<td>
$10,000.52
</td>

$10,000.52

<td>
<img src="../img/gifts/img2.jpg"/>
</td>


<img src="../img/gifts/img2.jpg"/>




<tr class="gift" id="gift3"><td>
Fish Painting
</td><td>
If something seems fishy about this painting, it's because it's a fish! <span class="excitingNote">Also hand-painted by trained monkeys!</span>
</td><td>
$10,005.00
</td><td>
<img src="../img/gifts/img3.jpg"/>
</td></tr>
<td>
Fish Painting
</td>

Fish Painting

<td>
If something seems fishy about this painting, it's because it's a fish! <span class="excitingNote">Also hand-painted by trained monkeys!</span>
</td>

If something seems fishy about this painting, it's because it's a fish! 
<span class="excitingNote">Also hand-painted by trained monkeys!</span>
Also hand-painted by trained monkeys!


<td>
$10,005.00
</td>

$10,005.00

<td>
<img src="../img/gifts/img3.jpg"/>
</td>


<img src="../img/gifts/img3.jpg"/>




<tr class="gift" id="gift4"><td>
Dead Parrot
</td><td>
This is an ex-parrot! <span class="excitingNote">Or maybe he's only resting?</span>
</td><td>
$0.50
</td><td>
<img src="../img/gifts/img4.jpg"/>
</td></tr>
<td>
Dead Parrot
</td>

Dead Parrot

<td>
This is an ex-parrot! <span class="excitingNote">Or maybe he's only resting?</span>
</td>

This is an ex-parrot! 
<span class="excitingNote">Or maybe he's only resting?</span>
Or maybe he's only resting?


<td>
$0.50
</td>

$0.50

<td>
<img src="../img/gifts/img4.jpg"/>
</td>


<img src="../img/gifts/img4.jpg"/>




<tr class="gift" id="gift5"><td>
Mystery Box
</td><td>
If you love suprises, this mystery box is for you! Do not place on light-colored surfaces. May cause oil staining. <span class="excitingNote">Keep your friends guessing!</span>
</td><td>
$1.50
</td><td>
<img src="../img/gifts/img6.jpg"/>
</td></tr>
<td>
Mystery Box
</td>

Mystery Box

<td>
If you love suprises, this mystery box is for you! Do not place on light-colored surfaces. May cause oil staining. <span class="excitingNote">Keep your friends guessing!</span>
</td>

If you love suprises, this mystery box is for you! Do not place on light-colored surfaces. May cause oil staining. 
<span class="excitingNote">Keep your friends guessing!</span>
Keep your friends guessing!


<td>
$1.50
</td>

$1.50

<td>
<img src="../img/gifts/img6.jpg"/>
</td>


<img src="../img/gifts/img6.jpg"/>

 

 

<정리>

 

child : 자식만 추출

descendants : 자손까지 추출

next_siblings : 첫 번째 타이틀 행을 제외한 모든 행 추출 (chlid 의 부모행를 제외한 나머지 행)

previous_siblings : 형제 태그의 마지막에 있는 태그 선택 (child의 부모행 바로 앞 행)

next_sibling, previous_sibling :  위와 똑같지만 태그 하나만 반환

.parent : 부모행

.previous_sibling : 부모행 바로 앞 행

 

 

 

 

---------------------------------------------------------------------------------------------------

 

 

 

정규표현식 정리

 

 

* : 바로 앞에 있는 문자가 0번 이상 나타남

+ : 바로 앞에 있는 문자가 1번 이상 나타남

   // 위 두개는 순서의 영향을 받음. 예를 들어 (a*b*) 라면 aaabbb, ab 를 의미하고 aba 를 의미하지는 않는다.

 

[] : 대괄호 안에 있는 문자 중 하나가 나타남

() : 그룹으로 묶인 하위표현식

{m,n} : 바로 앞에 있는 문자를 m 번 이상, n 번 이하 나타남

   // 예를 들어 a{1,3} => aa

 

[^] : 대괄호를 제외한 문자가 나타남

¦ : 분리된 문자, 문자열, 하위 표현식 중 하나가 나타남 (도대체 이 문자가 키보드 어디에 있는지 모르겠음)

a.b : a 와 b 사이에 문자 하나가 나타남

^ : 바로 뒤에 문자 혹은 하위 표현식이 문자열의 맨 앞에 나타남

\ : 특수 문자를 원래 의미대로 쓰이게 함

$ : 정규 표현식 마지막에 쓰이며 바로 앞에 있는 문자 또는 하위 표현식이 문자열의 마지막이라는 의미

?! : 이 기호 바로 뒤에 있는 문자를 포함하지 않는다는 의미, 완벽하게 배제하고 싶다면 *$ 와 같이 쓰는 것을 권장

 

 

[^A-Z]+@[A-Za-z]+\.(com¦org¦edu¦net) 

=> A부터 Z 까지를 제외한 문자가 한 개 이상 온 뒤, @ 표시를 하고 A부터 Z까지나 a부터 z까지의 문자가 온 뒤 . 을 표시하고 com,org,edu,net 중 하나가 온다는 정규표현식을 만들었다.

 

이를 통해서 꼭 이를 포함해야지만 출력되게끔 할 수 있는데

예를 들어, bs.findAll('ing', {'src': re.compile('\.\.\/img\/gifts/img.*\.jpg')}) 로 표현할 수 있다. 

 

 

 

---------------------------------------------------------------------------------------------------

 

 

 

람다표현식

 

BeautifulSoup 의 문법을 모르더라도 정규표현식을 사용할 수 있는 방법이 바로 람다표현식인데, 예를 들어 

bs.findAll(lamda tag: len(tag.attrs) == 2) 라는 식은 len(tag.attrs) 가 2일 때 성립하기 때문에 이 함수가 true 로 평가되면 findAll 함수가 그 태그를 반환할 수 있다.

저자도 이 부분을 한 장 밖에 사용하지 않았고 더 자세한 내용은 없기 때문에 이쯤에서,,, 마무리,,,