[python] requests와 BeautifulSoup으로 웹 크롤러 만들기
requests와 BeautifulSoup으로 웹 크롤러 만들기
Requests
Requests 설치
pip install requests
Requests 를 이용하여 데이타 가져오기
import requests
..........
req = requests.get('https://onstory.fun')
requests timeout 설정 및 retry
검색을 해보면 좀더 고급진 방법들도 많은데 여기서는 BeautifulSoup과 함께 간단히 사용하는 함수를 소개새 드립니다.
def get_bs_obj(self, url):
# url = "https://finance.naver.com
session = requests.Session()
for _ in range(5): # 5 번 시도
try:
result = session.get(url, headers=headers(), timeout=3) # time out 설정
bs_obj = BeautifulSoup(result.content.decode('euc-kr', 'replace'), "html.parser") # html.parser 로 파이썬에서 쓸 수 있는 형태로 변환
return bs_obj
except requests.exceptions.ConnectTimeout:
time.sleep(5)
except requests.exceptions.ConnectionError: # 네이버 크롤링시 종종 발생
time.sleep(5)
return f"Could not process {url}"
BeautifulSoup
BeautifulSoup 설치하기
pip install bs4
예제
import requests
from bs4 import BeautifulSoup
## HTTP GET Request
req = requests.get('https://onstory.fun')
## HTML 소스 가져오기
html = req.text
## BeautifulSoup으로 html소스를 python객체로 변환하기
## 첫 인자는 html소스코드, 두 번째 인자는 어떤 parser를 이용할지 명시.
soup = BeautifulSoup(html, 'html.parser')
## Selector를 통해 html요소들을 찾아낸다.
links = soup.select('a')
for link in links:
## Tag안의 텍스트
print(link.text)
## Tag의 속성을 가져오기(ex: href속성)
print(link.get('href'))
select : HTML 내 필요한 부분 선택하기
# 원하는 정보가 있는 위치 찾기
soup.select('원하는 정보') # select('원하는 정보') --> 단 하나만 있더라도, 복수 가능한 형태로 되어있음
soup.select('태그명')
soup.select('.클래스명')
soup.select('상위태그명 > 하위태그명 > 하위태그명')
soup.select('상위태그명.클래스명 > 하위태그명.클래스명') # 바로 아래의(자식) 태그를 선택시에는 > 기호를 사용
soup.select('상위태그명.클래스명 하~위태그명') # 아래의(자손) 태그를 선택시에는 띄어쓰기 사용
soup.select('상위태그명 > 바로아래태그명 하~위태그명')
soup.select('.클래스명')
soup.select('#아이디명') # 태그는 여러개에 사용 가능하나 아이디는 한번만 사용 가능함! ==> 선택하기 좋음
soup.select('태그명.클래스명)
soup.select('#아이디명 > 태그명.클래스명)
soup.select('태그명[속성1=값1]')
select_one
select와 사용법은 동일하나 하나의 결과만 가져온다.
find
Find 는 태그만을 가져온다.
여러개의 값이 있더라도 처음 하나만을 가져온다.
from bs4 import BeautifulSoup
html = "<div class='my-class' id='my-id'> Hello World! </div>" \
"<p class='my-class'>Welcome To Python</p>"
soup = BeautifulSoup(html, 'html.parser')
# 태그 특정
result1 = soup.find('div')
print(result1)
# 태그 속성만 특정
result2 = soup.find(class_='my-class')
print(result2)
# 속성을 이용하여 특정
result3 = soup.find(attrs = {'id':'my-id'})
print(result3)
# 태그 이름과 클라스 모두 특정
result4 = soup.find('p', class_='my-class')
print(result4)
결과
<div class="my-class" id="my-id"> Hello World! </div> # result1
<div class="my-class" id="my-id"> Hello World! </div> # result2
<div class="my-class" id="my-id"> Hello World! </div> # result3
<p class="my-class">Welcome To Python</p> # result4
find_all
find와 사용법은 동일하나 find가 하나만 가져오는 반면 find_all은 일치하는 모든 것을 가져온다.
Find를 이용해 가져온 태그의 속성들을 출력
#태그의 이름
print(result1.name) # 결과: 'div'
#태그에 담긴 텍스트
print(result1.text) # 결과: ' Hello World! '
# 태그의 속성과 속성값
print(result1.attrs) # 결과: {'class': ['my-class'], 'id': 'my-id'}