정적 크롤링은 어느 상황에서나 같은 주소에서 변하지 않는 데이터를 기대할 수 있는경우 사용하며 수집대상에 한계가 있으나 속도가 빠르다는 장점이 있다.
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가지 종류가 있다.
- lxml
- c 언어로 구현되어 속도가 가장 빠르다는 장점이 있다.
- html5lib
- 웹브라우저 형태로 HTML을 분석한다.
- 속도는 가장 느리지만 가장 안정적으로 파일을 가져온다는 장점이 있다.
- 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 |