본문 바로가기
Python

파이썬 정적 크롤링

by 승환파크 2023. 5. 10.

정적 크롤링은 어느 상황에서나 같은 주소에서 변하지 않는 데이터를 기대할 수 있는경우 사용하며 수집대상에 한계가 있으나 속도가 빠르다는 장점이 있다.

 

BeautifulSoup

요청 모듈로 가져온 HTML 코드를 파이썬이 쓸 수 있는 형태로 변환해주는 역할을 한다.

from bs4 import BeautifulSoup
from urllib.request import urlopen

# url 정보를 url 변수에 담음
url = "http://www.naver.com"

# urlopen() 함수에서 url 정보를 담은 변수로
# 해당 url에 보내서 page 정보를 가져온 후 page 변수에 담는다
page = urlopen(url)

# html 코드 정보가 BeautifulSoup이 해석해서
# 파이썬이 사용할 수 있는 html로 변경한 후 soup 변수에 담는다.
soup = BeautifulSoup(page, "lxml")

print(soup)
# 코드가 너무 길어 결과값은 생략

파서(parser)

내가 원하는 데이터를 특정 패턴이나 순서로 추출하여 정보를 가공해주는 프로그램이다.

파서에는 3가지 종류가 있다.

  1. lxml
    • c 언어로 구현되어 속도가 가장 빠르다는 장점이 있다.
  2. html5lib
    • 웹브라우저 형태로 HTML을 분석한다.
    • 속도는 가장 느리지만 가장 안정적으로 파일을 가져온다는 장점이 있다.
  3. html.parser
    • lxml 과 html5lib 의 중간속도이며 안정성도 중간이다.

 

 

속성 데이터

html = """<html> <head><title class="t" id="ti">test site</title></head> <body> <p>test</p> <p>test1</p> <p>test2</p> </body></html>"""

이런 HTML 생김새를 풀어쓰면 아래의 내용처럼 보인다.

<html>

    <head>

        <title class="t" id="ti">

            test site

        </title>

    </head>

    <body>

        <p>

            test

        </p>

        <p>

            test1

        </p>

    </body>

</html>

 

soup = BeautifulSoup(html, "lxml")
soup
# 결과값
# <html> <head><title class="t" id="ti">test site</title></head> <body> <p>test</p> <p>test1</p> <p>test2</p> </body></html>

tag_title = soup.title
print(tag_title)
print(tag_title.attrs) # 태그의 속성 가져오기
print(tag_title["class"]) # 키가 없다면 에러 발생
print(tag_title["id"])
# 결과값
# <title class="t" id="ti">test site</title>
# {'class': ['t'], 'id': 'ti'}
# ['t']
# ti

print(tag_title["class1"])
# KeyError: 'class1'

# tag 타입은 딕셔너리처럼 접근할 수 있고 딕셔너리 문법을 그대로 적용할 수 있다.
print(tag_title.get("class1", "default_value"))
# default_value
print(tag_title.get("class", "default_value"))
# ['t']

 

 

태그 접근

soup.태그이름 의 형태로 첫 번째 등장하는 태그의 정보를 가져올 수 있다.

tag_title = soup.title # title 태그

print(tag_title)
print(tag_title.text)
print(tag_title.string)
print(tag_title.name)

# 결과값
# <title class="t" id="ti">test site</title> -> 태그 전체
# test site -> 태그 안의 내용
# test site -> 태그 안의 내용
# title -> 태그 이름

 

text와 string 의 차이점

# text 와 string 의 차이
tag_body = soup.body

data_text = tag_body.text
data_string = tag_body.stirng

print(tag_body)
# <body> <p>test</p> <p>test1</p> <p>test2</p> </body>

print("text :", data_text, type(data_text))
print("text :", data_string, type(data_string))
# 결과값
# text : test test1 test2 <class 'str'>
# string : None <class 'NoneType'>

text : 자신의 태그 안에 text 정보와 자식 태그 안의 text 정보까지 모두 가져온다.

string: 자신의 태그 안의 text 정보만 가져온다.

 

만약 p 태그의 내용을 body 태그 안에서 String 으로 찾고싶다면 . 으로 이어서 작성해주면 된다.

print(tag_body.p.string)
# 결과값
# test

 

 

원하는 요소에 접근하기

find_all()

원하는 태그들을 리스트 형태로 가져오는 메서드

html = html = """<html> <head><title>test site</title></head> <body> <p id="i" class="a">test1</p><p id="d" class="d">test2</p><p class="c">test3</p><a>a tag</a> <b>b tag</b></body></html>"""

soup = BeautifulSoup(html, "lxml")

print(soup.find_all("title"))
# 결과값
# [<title>test site</title>]

print(soup.find_all("p"))
# 결과값
# [<p class="a" id="i">test1</p>, <p class="d" id="d">test2</p>, <p class="c">test3</p>]

 

id 값으로 태그 가져오기

soup.find_all(id ="d")
# 결과값
# [<p class="d" id="d">test2</p>]

# id의 존재 여부로 가져오기
soup.find_all(id = True)
# 결과값
# [<p class="a" id="i">test1</p>, <p class="d" id="d">test2</p>]

 

원하는 태그와 원하는 id 값으로 태그 가져오기

print(soup.find_all("p", id = "d"))
# 결과값
# [<p class="d" id="d">test2</p>]

 

원하는 태그와 원하는 클래스 값으로 태그 가져오기

클래스는 class_ 로 작성해서 값을 가져와야 한다.

print(soup.find_all("p", class_ = "d"))
print(soup.find_all("p", class_ = "c"))
# 결과값
# [<p class="d" id="d">test2</p>]
# [<p class="c">test3</p>]

 

 

find()

하나의 요소만 가지고 오는 태그이다. 찾고자 하는 요소가 한개 뿐일 때 주로 사용한다.

print(soup.find("p", class_ = "i"))
print(soup.find("p", id = "i"))
print(soup.find(id = "i"))

# 결과값
# <p class="d" id="d">test2</p>
# <p class="a" id="i">test1</p>
# <p class="a" id="i">test1</p>

 

find 는 연속으로 사용이 가능하다.

soup.find("body").find("p", class_ = "d")
# 결과값
# <p class="d" id="d">test2</p>

 

 

select()

find_all() 과 마찬가지로 매칭되는 모든 결과를 리스트로 반환한다.

select_one()으로 하나의 결과만 반환하는 것도 가능하다.

클래스는 마침표(.), 아이디는 샵(#)으로, 자손태그는 띄어쓰기로 구분한다.

print(soup.select("p")) # p태그
print(soup.select(".d")) # class가 d인 태그
print(soup.select("p.d")) # class가 d인 p태그
print(soup.select("#i")) # id가 i인 태그
print(soup.select("p#i")) # id가 i인 p 태그

# 결과값
# [<p class="a" id="i">test1</p>, <p class="d" id="d">test2</p>, <p class="c">test3</p>]
# [<p class="d" id="d">test2</p>]
# [<p class="d" id="d">test2</p>]
# [<p class="a" id="i">test1</p>]
# [<p class="a" id="i">test1</p>]

 

html = html = """<html> <head><title>test site</title></head> <body> <div><p id="i" class="a">test1</p><p class="d">test2</p></div><p class="d">test3</p></p> <a>a tag</a> <b>b tag</b></body></html>"""

soup = BeautifulSoup(html, "lxml")
print(soup.select("body p")) # body 의 자손인 p 태그
print(soup.select("body .d")) # body의 자손중에서 클래스가 d인 태그
print(soup.select("body p.d")) # body의 자손중에서 클래스가 d인 p태그
print(soup.select("body #i")) # body의 자손중에서 id가 i인 태그
print(soup.select("body p#i")) # body의 자손중에서 id가 i인 p태그
print(soup.select("div p")) # div 자손인 p 태그
# 결과값
# [<p class="a" id="i">test1</p>, <p class="d">test2</p>, <p class="d">test3</p>]
# [<p class="d">tst2</p>, <p class="d">test3</p>]
# [<p class="d">test2</p>, <p class="d">test3</p>]
# [<p class="a" id="i">test1</p>]
# [<p class="a" id="i">test1</p>]
# [<p class="a" id="i">test1</p>, <p class="d">test2</p>]

'Python' 카테고리의 다른 글

파이썬으로 MySQL 연동하기  (0) 2023.05.26
파이썬 동적 크롤링  (1) 2023.05.11
파이썬 웹 크롤링  (1) 2023.05.10
파이썬 상속  (0) 2023.05.10
파이썬 프라이빗 변수와 getter, setter  (1) 2023.05.10