데이터 분석가 핵심 역량 두 가지
- 왜 프로젝트를 시작했는지 설명하기
- 문제를 어떻게 정의하는지가 중요, 그래서 어떤 방법을 정의했는지가 중요
데이터 수집 방법
- SQL
- Open API
- 웹 스크레이핑
❓웹 스크레이핑
- 인터넷 상의 웹 페이지를 자동으로 탐색해 정보를 추출하는 프로세스
- 데이터 수집, 분석 및 처리를 자동화
- 대표적 도구는 BeautifulSoup, Selenium
Robot.txt
- 웹 스크레이핑을 할 때 해당 웹사이트의 =robots.txt= 를 통해 웹 크롤링에 대한 지침을 설명
- 일반적으로 웹페이지의 URL에 /robots.txt를 추가해 해당 파일을 찾을 수 있음
정적 페이지 vs. 동적 페이지
- 정적 페이지: 새로운 정보를 노출할 때 url이 변경
- 동적 페이지: 새로운 정보를 노출할 때 url이 변경되지 않고 변동사항이 반영
웹 스페레이핑의 프로세스
장점 | 단점 |
Requests | 빠름 |
BeautifulSoup | 빠름 |
Selenium | 1. 내외부 데이터 사용 가능 2. 모든 데이터를 가져올 수 있음 3. 브라우저 조작 가능 |
프로세스: 라이브러리 호출, URL 접속, HTML 받아오기, 정보 찾기, 저장하기 순으로 진행
| 방법1 | 방법2 | 방법3 |
라이브러리 호출 | Requests | Selenium | Selenium |
URL 접속 | Requests | Selenium | Selenium |
HTML 받아오기 | Requests | Selenium | Selenium |
정보찾기 | BeautifulSoup | Requests | Selenium |
저장하기(excel, csv, db) | | | |
❗️정적 스크레이핑 vs 동적 스크레이핑(Bot)
정적 스크레이핑
- 웹 스크레이핑 프로세스 방법 : 1, 2
- 정적 웹 스크레이핑은 웹 페이지의 HTML 코드를 가져와서 정보를 추출하는 방법
- 이 방법은 대부분의 경우 적용 가능하지만, JavaScript와 같은 클라이언트 측 기술을 사용하여 동적으로 업데이트되는 웹 페이지에는 적용 불가
동적 스크레이핑
- 웹 스크레이핑 프로세스 방법 : 3
- 동적 웹 스크레이핑은 웹 페이지를 브라우저와 같은 방식으로 렌더링하여 정보를 추출하는 방법
- 이 방법은 정적 웹 스크레이핑보다 더 많은 정보를 추출할 수 있으며, 클라이언트 측 기술을 사용하여 동적으로 업데이트되는 웹 페이지에 적용가능
- 동적 웹 스크레이핑에는 Selenium(웹 브라우저를 제어하여 웹 페이지를 렌더링하고 정보를 추출하는 도구)과 같은 도구가 사용됨
데이터 분석을 위한 Source 분석
기준 | SQL | Open API | 웹 스크레이핑 |
정의 | 관계형 데이터베이스 관리 시스템에서 데이터를 관리하는 언어 | 서로 다른 소프트웨어 간의 상호작용을 위한 규약 | 웹사이트에서 데이터를 추출하는 기술 |
주요 사용 사례 | 기업 데이터베이스, 고객 관리 시스템 등 | 소셜 미디어 데이터, 날씨 정보, 주식 시세 등 | 온라인 뉴스, 쇼핑 정보, 사용자 리뷰 등 |
장점 | - 표준화된 언어 - 강력한 데이터 조작 기능 - 보안 | - 용이한 통합 - 표준화된 데이터 형식 - 실시간 데이터 접근 | - 유연성 - 비용 효율성 |
단점 | - 데이터 접근 제한 - 학습 곡선 | - API 제한 - 의존성 | - 법적 문제 - 데이터 구조 변화에 취약 - 기술적 복잡성 |
SQL은 지속적으로 가져가야할 필요가 있음 |
HTML
- HTML은 Hyper Text Markup Language의 약자. 웹 페이지의 구조와 콘텐츠를 정의하는 마크업 언어. HTML은 브라우저에서 해석되어 사용자에게 웹 페이지가 어떻게 보이는지를 보여줌. HTML 태그를 사용하여 구조, 콘텐츠, 이미지, 비디오 등을 정의할 수 있음
HTML Element
- =html= : HTML 문서의 루트 요소
- =head= : 문서의 메타데이터를 포함하는 요소
- =title= : 문서의 제목을 정의하는 요소
- =body= : 문서의 본문을 포함하는 요소
부모와 자식 관계
- HTML의 자식 요소는 HTML 태그 내에 중첩된 요소를 가리킴
- 이 중첩된 요소는 자식 요소(child elements) 또는 하위 요소(descendants) 라고도 함
- 예를 들어 body 태그는 header, nav, section, article, footer와 같은 다양한 자식 요소를 포함할 수 있음
- 마찬가지로 ul 태그는 목록을 만들기 위해 li와 같은 자식 element를 포함할 수 있음
- 자식 요소는 자체 자식 요소를 가질 수도 있으며, 계층 구조를 형성함
CSS
❓CSS(Cascading Style Sheets)
- HTML로 작성된 콘텐츠의 스타일링을 가능하게 해주는 스타일 시트 언어
- CSS를 사용하면 웹 개발자들은 문서의 내용과 디자인을 분리
- 여러 웹 페이지의 디자인을 한 번에 유지·보수하고 수정할 수 있음
CSS Selector
HTML 요소를 스타일링하기 위해 선택하는 패턴. 선택자는 웹 페이지에서 특정 요소를 대상으로 CSS 스타일을 적용하는 데 사용
요소 선택자(Element Selector)
- h1, p, ul과 같은 특정 유형의 모든 요소 선택
클래스 선택자(Class Selector)
- .my-class와 같이 특정 클래스의 이름을 가진 요소 선택
- ID 선택자(ID Selector) : #my-id와 같이 특정 ID를 가진 요소를 선택
- 속성 선택자(Attribute Selector) : [type=“text”]와 같이 특정 속성 값이 있는 요소를 선택
- CSS 클래스 : HTML 요소를 식별하기 위해 사용되는 이름으로, 여러 요소에 적용될 수 있으며, 동일한 클래스를 가진 요소는 동일한 스타일을 공유함. 클래스 이름은 대소문자를 구분하며, . 으로 시작합니다. 예를 들어, .my-class 클래스는 HTML 요소에 적용할 수 있음
<div class="my-class"> 이 요소는 my-class 클래스를 가지고 있습니다. </div>
CSS ID
- HTML 요소를 구체적으로 식별하기 위해 사용되는 이름으로, ID는 한 번만 사용할 수 있으며, HTML 문서에서 고유해야 함
- ID 이름은 대소문자를 구분하며, #으로 시작함. 예를 들어, #my-id ID는 HTML 요소에 적용할 수 있음
- CSS에서 ID를 선택할 때는 클래스와 유사하게 선택자를 사용함
- 클래스와 ID는 CSS에서 미리 정의된 스타일을 적용하는 데 사용됨
- 클래스는 여러 요소에서 공유할 수 있으므로, 스타일을 일관되게 적용하는 데 유용
- ID는 한 번만 사용할 수 있으므로 보다 구체적인 스타일을 적용하는 데 유용함
<div id="my-id"> 이 요소는 my-id ID를 가지고 있습니다. </div>
HTML vs JS vs CSS
- HTML은 웹 페이지의 뼈대로, 구조와 내용을 정의
- JavaScript는 웹페이지의 근육으로, 움직임과 반응을 제공하는 기능을 담당(웹 페이지를 동적으로 만들어줌)
- CSS는 웹 페이지의 옷으로, 스타일과 외관을 제공하여 시각적으로 매력적이고 사용하기 쉬운 페이지를 만들어 줌(HTML로 작성된 콘텐츠의 디자인과 레이아웃을 관리할 수 있게 해줌)
정적 스크레이핑 실습 준비
#ⓐ requests 라이브러리 설치하기 ! pip install requests #ⓑ 라이브러리 호출, URL 접속, HTML 받아오기 import requests # 라이브러리 호출 response = requests.get('https://www.naver.com') # URL 접속 print(response) print(response.text) # HTML 받아오기 #ⓒ beautifulsoup4 라이브러리 설치하기 ! pip install beautifulsoup4 #ⓓ beautifulsoup4 기본적인 사용 형태 from bs4 import BeautifulSoup html_doc = ''' <html> <head> <title>웹 페이지 제목</title> </head> <body> <div id="content"> <h1>웹 페이지 내용</h1> <p>스크래핑을 위한 예시 문장입니다.</p> </div> </body> </html> ''' soup = BeautifulSoup(html_doc, 'html.parser') title = soup.find('title') h1 = soup.find('h1') p = soup.find('p') print(title.text) print(h1.text) print(p.text)
Naver Finance에서 인기 검색 종목 가져오기
# 라이브러리 호출 import requests from bs4 import BeautifulSoup # URL 접속 response = requests.get('https://finance.naver.com/') print(response) # HTML 받아오기 HTML = response.text soup = BeautifulSoup(HTML, 'html.parser') # 정보 찾기 popular_stock_table = soup.find('div', class_ = 'aside_area aside_popular') popular_stock = popular_stock_table.find_all('tr', class_ = ['up', 'down', 'same']) # 저장 stock_list = [] for i in range(len(popular_stock)): stock_name = popular_stock[i].find('a').text stock_list.append(stock_name) stock_list
<Response [200]> [‘LS머트리얼…’, ‘에코프로머티’, ‘에코프로’, ‘에코프로비엠’, ‘삼성전자’]
기상청 Top5 리스트 가져오기
# 라이브러리 호출 import requests from bs4 import BeautifulSoup # URL 접속 response = requests.get('https://www.weather.go.kr/w/index.do#dong/1120069000') print(response) # HTML 받아오기 HTML = response.text soup = BeautifulSoup(HTML, 'html.parser') # 정보 가져오기 #1. find version top5 = soup.find('div', class_ = 'weblog-top10') top5_list = top5.find_all('a', class_ = 'link') #2. select version top5 = soup.select_one('#lnb > div.tab > div.tab-item.on > div') top5_list = top5.select('a.link') # 저장 result = [] for i in top5_list: result.append(i.text) result
YES24 1P 책 제목 가져오기
import request from bs4 import BeautifulSoup #URL 접속 response = requests.get('https://www.yes24.com/Product/Search?domain=ALL&query=%EC%9E%90%EC%97%B0%EC%96%B4%20%EC%B2%98%EB%A6%AC') #HTML 받아오기 HTML = response.text soup = BeautifulSoup(HTML, 'html.parser') #정보 가져오기 book_list_html = soup.select_one('#yesSchiList') book_list = book_list_html.select('a.gd_name') title = [i.text for i in book_list] title
네이버 금융 배당 페이지 웹 스크레이핑 후 데이터 프레임으로 만들기
import pandas as pd # URL 접속 response = requests.get('https://finance.naver.com/sise/dividend_list.naver') # HTML 받아오기 HTML = response.text soup = BeautifulSoup(HTML, 'html.parser') # 정보 가져오기(컬럼) columns_html = soup.select_one('#contentarea_left > table.type_1.tb_ty > thead') columns_th = columns_html.select('th') columns = [i.text for i in columns_th] columns.remove('과거 3년 배당금') # 정보 가져오기(로우) table_body = soup.select_one('#contentarea_left > table.type_1.tb_ty > tbody') row_html = table_body.select('tr') df_values = [] for i in range(len(row_html)): if row_html[i].select_one('.txt').text != '\xa0': title = row_html[i].select_one('.txt').text values = [i.text for i in row_html[i].select('.num')] result = [title] + values df_values.append(result) # for i in row_html: # if i.select_one('.txt').text != '\xa0': # title = i.select_one('.txt').text # values = [i.text for i in i.select('.num')] # result = [title] + values # print(result) # 데이터 프레임 만들기 df = pd.DataFrame(df_values, columns=columns) df.head()
네이버 금융 배당 페이지 전체를 웹 스크레이핑 후 데이터 프레임으로 만들기
# 마지막 페이지 가져오기 # 속성에 있는 값에 접근할 때 .get 활용 last_page = int(soup.select_one('td.pgRR > a').get('href').split('&page=')[-1]) last_page # 데이터 프레임으로 만들 수 있도록 함수 선언 def getPageData(page_num): response = requests.get(f'https://finance.naver.com/sise/dividend_list.naver?&page={page_num}') HTML = response.text soup = BeautifulSoup(HTML, 'html.parser') columns_html = soup.select_one('#contentarea_left > table.type_1.tb_ty > thead') columns_th = columns_html.select('th') columns = [i.text for i in columns_th] columns.remove('과거 3년 배당금') table_body = soup.select_one('#contentarea_left > table.type_1.tb_ty > tbody') row_html = table_body.select('tr') df_values = [] for i in range(len(row_html)): if row_html[i].select_one('.txt').text != '\xa0': title = row_html[i].select_one('.txt').text values = [i.text for i in row_html[i].select('.num')] result = [title] + values df_values.append(result) df = pd.DataFrame(df_values, columns=columns) return df
# 최종결과 empty_df = pd.DataFrame() for i in range(1, last_page+1): empty_df = pd.concat([empty_df, getPageData(i)]) empty_df = empty_df.reset_index(drop=True) empty_df
'AI데이터 엔지니어, 새싹' 카테고리의 다른 글
75th_12_20(Wed)_API활용 웹 크롤링 (1) | 2024.01.08 |
---|---|
70th_12_14(Mon)_시계열 데이터 분석 (0) | 2024.01.08 |
62th_121_Overfitting (0) | 2023.12.04 |
61th_11_30(Thu)_ResNet (1) | 2023.11.30 |
60th_11_29(Wed)_GoogLeNet (0) | 2023.11.29 |