본문 바로가기

IT.모바일/배움

파이썬으로 업무 자동화하기 - 웹 데이터 자동 수집 크롤링

by FrankUniq 2023. 6. 12.
SMALL
tag_list = soup.select("a[href]")		# a[href] 추출
for tag in tag_list:				# tag_list 내 데이터를 하나씩 읽어오기
	print(tag.text, tag.attrs["href"])		# 텍스트와 URL 출력
    
# 결과
# 다음 바로가기 http://www.daum.net
# 네이버 바로가기 http://www.naver.com
# 구글 http://www.google.com​
목표: 10개씩 데이터 표시되는 특정 웹사이트. 총 2만여 건의 데이터를 페이지 넘기며 자동 수집.

1. 웹 크롤링 개요
o절차, o패키지, oHTML 기초, oCSS 기초, o개발자도구 웹 구조

2. 웹 데이터 자동 수집
oHTML 소스 가져오기, o데이터로 변환, 실습-서점 베스트셀러 가져오기

3. 웹 브라우저 제어
selenium 개요, 웹 로드 및 HTML 소스 가져오기, 웹 브라우저 제어, 실습-네이버환율수집하여 csv로 저장, 실습-사업자번호 휴폐업 조회

 

URL 웹 페이지 가져오는 requests 모듈

HTML 소스 분석하는 BeautifulSoup 모듈

 

- 웹브라우저에서 해당 리소스의 위치인 URL을 웹 서버에 요청 -> 웹 서버가 웹 브라우저를 통해 요청한 리소스를 보내준다. 받은 리소스의 Content-Type이 HTML 형태이면 웹 브라우저가 렌더링해서 사용자에게 보여주고, 텍스트 형식이 아닌 이진 파일은 로컬 PC에 다운로드할 수 있다.

 

- requests:웹 페이지에 HTTP 요청을 보내고 응답 데이터를 수집하는 패키지

-- HTML, JSON, 이미지, 음성, PDF 수집 기능. 정형/비정형 데이터 크롤링에 많이 사용.

-- HTTP request에 필요한 기능 지원(get/post 방식 선택, parameter/form data/cookie 보내기 등)

-- 웹 브라우저 없이 구동하므로 코드 짧고, 속도 빠르고, 크롤링 안정적.

-- !pip install requests

 

HTML 소스 가져오기 - GET / POST

- 파라미터를 URL 뒤에 붙이는 GET 방식; 웹 브라우저가 웹 서버에 데이터를 요청할 때 사용.

-- requests.get() 함수에 파라미터로 URL과 verify를 사용.

verify를 False로 지정하면 SSL 인증서 오류 문제가 발생해도 URL에 입력한 웹 페이지를 가져올 수 있다.

-- 가져온 내용 출력 방법

(1) print(res.content) // 웹 페이지에서 응답한 HTML 형식의 데이터를 보여준다. 텍스트, 이미지, zip 등.

(2) print(res.text) // 한글 출력 가능. 텍스트 위주의 웹 페이지일 경우 유용하다.

import requests
res = requests.get("http://www.naver.com", verify = False)
print(res.content) # get으로 네이버 가져와서, 내용(content) 출력

-- GET 방식으로 요청할 때 파라미터를 전달하는 방법

(1) 파라미터 속성 사용

parameters = {"code" : "005930"}
res = requests.get("https://finance.naver.com/item/sise.nhn", params = parameters, verify = False)
print(res.url)
print(res.text)

(2) URL에 ?, = 기호를 사용해 파라미터 붙여서 요청.

res = requests.get("https://finance.naver.com/item/sise.nhn?code=005930", verify = False)
print(res.text)

 

- 파라미터를 URL에 붙이지 않고 request body에 넣어 요청하는 POST 방식; 웹 브라우저가 웹 서버에 데이터를 전달하기 위해 사용.

-- URL에 파라미터가 노출되지 않아 보안에 유리하다. <form> 태그를 사용해 사용자로부터 정보를 입력받는 경우, 서버로 전송해야 할 데이터 용량이 클 경우 사용.

res = requests.post("https://finance.naver.com/item/sise.nhn = 005930", verify = False)
print(res.text)

+ 파라미터가 두 개 이상일 때는 파라미터들을 딕셔너리 형태로 전달해야 한다. requests.post() 함수의 data 매개변수를 사용하여 파라미터를 전달할 수 있다. 파라미터들을 딕셔너리로 만들고 data 매개변수에 전달한다. (챗GPT)

import requests

params = {
    'param1': '값1', # param1, param2를 원하는 파라미터의 이름으로 교체
    'param2': '값2' # 값1, 값2는 실제로 전달하고자 하는 값으로 교체
}

res = requests.post("https://finance.naver.com/item/sise.nhn", data=params, verify=False)

 

HTML 소스를 구조화된 데이터로 변환하기: Parsing

- BeautifulSoup 패키지를 통해 Parsing.

- CSS Selector를 지원하여 데이터 탐색 간편, 원하는 데이터만 추출해 별도로 정리 가능.

- HTML 데이터 수집은 requests로, 수집한 데이터의 필터링과 선택은 BeautifulSoup로 수행.

- !pip install bs4

- BeautifulSoup의 find(), find_all() 함수는 HTML 태그를 통해 원하는 부분을 찾는다.

-- find() 함수는 해당 조건에 맞는 첫 번째 태그만 가져온다.

-- find_all() 함수는 해당 조건에 맞는 모든 태그들을 가져와서 리스트 자료형으로 만든다.

from bs4 import BeautifulSoup
html_txt = "<p class = 'weather' id = 'tw'>오늘의 날씨</p> <h1> 한때 소나기 </h1>" # 실습용 HTML 소스 생성
soup = BeautifulSoup(html_txt, "html.parser") # 파싱. 분석 가능한 데이터로 변환

tag = soup.find("p") # p 태그를 찾아 tag에 저장

print(tag)			# tag 출력
print(tag.name)			# tag 이름 출력
print(tag.attrs) 		# tag 속성 출력
print(tag.attrs["class"])	# tag 속성 중 class만 출력
print(tag.attrs["id"])		# tag 속성 중 id만 출력
print(tag.text)			# tag 내 텍스트 출력

# 'div' 태그 안에 'p' 태그를 찾는다면 soup.find("div").find("p")처럼 find() 함수를 중첩 사용

- select(), select_one() 함수는 HTML 태그와 CSS를 이용해 원하는 속성을 정확하게 찾는다.

from bs4 import BeautifulSoup		# BeautifulSoup 모듈 불러오기
 		 	# 실습용 HTML 소스 생성
html_txt = """
<html>
<head><title>BS page</title></head>
<body>

<h1 class="portal_cls">검색포털</h1>
<p>
<a href="http://www.daum.net">다음 바로가기</a><br>
<a href="http://www.naver.com">네이버 바로가기</a>
</p>
<a href="http://www.google.com" class="alink_cls">구글</a>
<a target="_테스트_"> 테스트</a>
<p class="footage_cls" id="company"> 2021, ABC Company </p>
<p class="footage_cls" id="addr">Korea</p>
</body>
</html>
"""
soup = BeautifulSoup(html_txt, "html.parser")		# 파싱. 분석 가능한 데이터 형태로 변환. S 대문자 주의

-- select_one()은 조건에 맞는 태그를 하나만 가져온다. 

# <h1> 태그를 slect_one()으로 찾아 텍스트만 출력
tag = soup.select_one("h1")
print(tag.text)
-----------------------------------------------
검색포털

# find()와 비교되게 <p> 태그로 예시가 있었으면

# <p> 태그를 slect_one()으로 찾아 텍스트만 출력
tag = soup.select_one("p")
print(tag.text)
-----------------------------------------------
다음 바로가기
네이버 바로가기
+(챗GPT) `select_one()` 메서드는 조건에 맞는 첫 번째 태그를 선택하고 반환합니다. 따라서 `tag = soup.select_one("p")` 코드는 HTML 문서에서 첫 번째로 발견되는 `<p>` 태그를 선택하게 됩니다.
그러나 HTML 문서에서는 <p> 태그가 두 개 있습니다:
1. 첫 번째 <p> 태그: <a href="http://www.daum.net">다음 바로가기</a><br><a href="http://www.naver.com">네이버 바로가기</a> 내용을 가지고 있습니다.
2. 두 번째 <p> 태그: "2021, ABC Company" 내용을 가지고 있습니다.
select_one() 메서드는 첫 번째 <p> 태그만 선택하지만, 선택된 태그의 내용에는 <a> 태그들도 포함됩니다. 따라서 tag.text를 출력하면 "다음 바로가기\n네이버 바로가기"가 출력되는 것입니다.
select_one() 메서드를 사용하여 하나의 태그만 선택하고자 한다면, 조건을 더 명확하게 지정해주어야 합니다. 예를 들어, soup.select_one("p:nth-of-type(1)")와 같이 nth-of-type() 선택자와 인덱스를 이용하여 첫 번째 <p> 태그만 선택할 수 있습니다.
즉, tag = soup.select_one("p:nth-of-type(1)")를 사용하면 "다음 바로가기"만 결과로 출력됩니다.

 

- select()는 태그를 추출하면 리스트형 자료로 반환되기 때문에 반복문을 활용해 데이터를 하나씩 가져와야 한다.

tag_list = soup.select("h1")	# <h1> ~ </h1> 태그 추출 
for tag in tag_list:		# tag_list 내 데이터를 하나씩 읽어오기
	print(tag.text)		# 텍스트만 출력
    
 #결과
 검색포털

- 자식/자손 태그 찾기

-- 자식 태그: soup.select("body p > a")는 <body>의 p 태그 하위에 있는 a 태그를 모두 추출.

-- 자손 태그: soup.select("body p a")는 <body>의 p 태그 하위에 있는 a 태그를 추출하고, 그 하위에 있는 모든 태그도 추출.

tag_list = soup.select("body p > a")	# <body><p> 태그 하위의 <a> 태그 추출
for tag in tag_list:			# tag_list 내 데이터를 하나씩 읽어오기
print(tag.text)				# 텍스트만 출력

- CSS 클래스 선택자로 태그 찾기: select() 함수의 파라미터에 .클래스명 입력

tag_list = soup.select(".footage_cls")	# footage_cls 클래스 추출
for tag in tag_list:				# tag_list 내 데이터를 하나씩 읽어오기
	print(tag.text)				# 텍스트만 출력

# 결과
# 2021, ABC Company
# Korea

- CSS ID 선택자로 태그 찾기: select() 함수의 파라미터에 #아이디명 형식으로 지정.

tag_list = soup.select("#company")		# id가 company인 태그 추출
for tag in tag_list:				# tag_list 내 데이터를 하나씩 읽어오기
	print(tag.text)				# 텍스트만 출력
    
# 결과
# 2021, ABC Company

- 태그 속성값(attribute)로 태그 찾기: soup.select("a[href]")는 a 태그 중 속성 값 href를 갖는 태그 추출.

tag_list = soup.select("a[href]")		# a[href] 추출
for tag in tag_list:				# tag_list 내 데이터를 하나씩 읽어오기
	print(tag.text, tag.attrs["href")	# 텍스트와 URL(href 속성값) 출력
    
# 결과
# 다음 바로가기 http://www.daum.net
# 네이버 바로가기 http://www.naver.com
# 구글 http://www.google.com

 

실습 - 교보문고 베스트셀러 도서, 저자, 가격 정보 가져오기

 

1. 수집할 데이터 확인; URL 확인, 웹 페이지에서 크롤링할 데이터 확인하기

(1) URL 확인; 교보문고 월간 베스트셀러 웹 페이지 접속

(2) 데이터 위치 확인; 어떤 웹 페이지에 어떤 데이터가 있는지 확인해야 한다. 도서 제목 클릭-도서별 상세 페이지에는 도서명, 저자, 가격 등이 일관성있게 배치되어 있음을 확인.

 

2. 웹 구조 파악; 크롬 개발자 도구로 웹 페이지 구조 파악하기

(1) F12, Inspect 이용해 도서 목록에서 마우스를 움직이면서 원하는 도서 전체 영역의 HTML 코드 확인

(2) 웹 구조 파악 - 태그 분석; 도서는 <li> 태그로 구성되어 있고 하위 구성요소로 'prod_chk_group', 'prod_area horizontal', 'prod_order_state', 'prod_btn_wrap'라는 클래스를 가지고 있다. <div class="prod_area horizontal"> 하위 클래스로 이미지를 담은 <div class="prod_thumb_box size_lg">, 책 정보를 담은 <div class="prod_info_box"> 클래스를 확인할 수 있다. <div class="prod_info_box"> 하위 요소로 prod_rank, prod_badge, prod_name, prod_author, prod_price, prod_introduction, prod_bottom 등의 클래스도 확인할 수 있다.

 

3. 데이터 태그 파악; 크롤링할 데이터의 HTML 태그, 클래스 파악하기

 

4. 코딩 및 실행; 패키지 불러오기, 코딩 및 실행 결과 확인하기

댓글