Day41_Python분석_39‐42 CSS,배포,스크래핑 - bonniekwon0721/Dataanalytics-study GitHub Wiki
20/APR/2024
HTML, XML등의 마크업 언어로 작성된 문서를 꾸미는 스타일링 언어
레이아웃, 폰트, 색상, 간격 등을 제어
연관된 레이아웃을 묶어서 각 그룹의 위치를 지정해주는 방식으로 운영됩니다.
HTML 태그 내의 style 속성 사용 : 우선순위가 가장 높음 해당 요소에만 적용
⇒ 대부분의 HTML 태그에 style 속성 가능 ⇒ 몇몇 HTML 태그는 스타일 적용이 무의미/제한적 (head, title, meta,script 등) (!) 너무 많은 인라인 스타일은 코드가 복잡해질 수 있음! => 유지보수가 어려움
HTML 문서의
에 <style> 태그 사용 • 한 문서 내의 모든 요소에 적용외부 CSS 파일을 HTML 문서에 연결 • 한 문서 내의 모든 요소에 적용 + 여러 문서에서 재사용 가능
⇒ h1~h6, p, b 등
p{
color: red; # 텍스트 색상
font-family: "Aria, sans-serif; # 사용 폰트
font-size: 16px; # 텍스트 크기
font-weight: bold; # 텍스트 두께
text-align: center; # 텍스트 정렬방식
text-transform: uppercase; # 대소문자
line-height: 1.5; # 줄 높이
letter-spacing: 1px;# 문자 간의 간격
}div {
width: 300px; # 너비
height: 200px; # 높이
margin: 20px; # 외부 여백
padding: 30px; # 내부 여백
border: 1px solid black; # 테두리 (두께 타입 컬러)
background-color: green; # 배경 색상
color: white; # 텍스트 색상
display: flex;# 디스플레이 타입
justify-content: center; # 자식 요소들의 수평 정렬
align-items: center; # 자식 요소들의 수직 정렬
}⇒ span, b, i, a 등
• 상자 크기:
콘텐츠의 너비만큼만 차지 (높이, 너비 지정 불가)
• 줄 바꿈:
없음. 다른 인라인 요소나 텍스트와 같은 줄에 위치
• 용도:
주로 텍스트 스타일링에 사용⇒ div, p, h1~h6, li 등
• 상자 크기:
가능한 한 부모 요소의 전체 너비를 차지 (높이, 너비 지정 가능)
• 줄 바꿈:
자동으로 줄 바꿈이 일어남
• 용도:
주로 구조와 레이아웃에 사용• 상자 크기:
가능한 한 부모 요소의 전체 너비를 차지 (높이, 너비 지정 가능)
• 줄 바꿈:
없음• 유연성: 아이템 간의 간격, 정렬을 유연하게 조절 가능
• 자식 요소들을 모두
inline-block으로 설정하는 것과 같은 효과• 공간 차지: 화면에서 완전히 제거되어 어떠한 공간도 차지하지 않음
• 접근성: 스크린 리더에서도 읽히지 않음- 웹 브라우저 내장 도구
- 크롬, 파이어폭스, 사파리, 엣지 등 => 개발자 도구(DevTools)의 비나 기능에 약간의 차이가 있을 수 있음
- 웹 페이지의 작동 원리를 이해하고 디버깅하는 데 사용
- 주요기능
- HTML과 CSS를 실시간으로 확인하고 수정
- 에러 메시지와 로그를 확인
- 네트워크 통신과 관련된 정보 확인
- 웹 페이지의 성능을 분석
- 쿠키, 로컬 스토리지, 세션 스토리지 등 확인
<!DOCTYPE html> <!--문서유형선언-->
<html>
<head>
<meta charset="UTF-8"/>
<!--character set-->
<link rel="stylesheet" href="style.css"/> # 여기서 연결
<title>권보니 이력서</title>선택한 섹션의 구문을 선택하면 해당 부분이 하이라이트 된다.
body {
margin: 20px;
background-color:white;
}
header {
background-color: #50b3a2;
color: white;
padding: 10px 0px 10px 0px ;
text-align: center;
}
h1 {
margin: 10px 0;
}Chrome 에 display:flex를 넣어서 padding 테스트해보기
CSS 에서 마무리하기
body {
margin: 20px;
background-color:white;
}
header {
background-color: #50b3a2;
color: white;
padding: 10px 0px 10px 0px ;
text-align: center;
}
h1 {
margin: 10px 0;
}
main{
display: flex;
flex-direction: column;
gap: 30px;
background-color: whithe;
margin: 20px;
padding: 20px;
border-radius: 8px;
box-shadow: 0px 0px 10px rgba(0,0,0,0.1)
}
h2{
background-color: rgb(65,65,65);
color: white;
padding: 10px;
margin:0;
}HTML 요소의 분류 및 그룹화에 사용
- 사용 목적: 여러 요소에 동일한 스타일 및 JS 함수 적용
- 특징:
- 하나의 요소에 여러 클래스를 부여 가능
- 하나의 클래스를 여러 요소에 적용 가능
특정 HTML 요소에 고유한 식별자를 제공
- 사용 목적: 특정 요소에 접근 및 스타일 적용
- 특징:
- 1D는 문서 내에서 유일해야함 (중복X)
클래스 이름를 기반으로 스타일을 적용
- 적용 범위: 특정 클래스를 가진 모든 요소. 재사용 가능한 스타일을 정의할 때 유용.
아이디를 기반으로 스타일을 적용
- 적용 범위: 특정 아이디를 가진 단 하나의 요소
-
자식 콤비네이터 (Child Combinator)
⇒ 특정 요소의 직계 자식만을 선택
-
후손 콤비네이터 (Descendant Combinator)
⇒ 특정 요소의 모든 후손을 선택합니다.
선택을 위한 라벨링을 해주었습니다.
<!DOCTYPE html> <!--문서유형선언-->
<html>
<head>
<meta charset="UTF-8"/>
<!--character set-->
<link rel="stylesheet" href="style.css"/>
<title>권보니 이력서</title>
</head>
<body>
<header>
<h1 id="name">권다영</h1>
<p id="introduction">데이터를 통해서 비지니스 문제를 해결하고 가치를 창출하는 경험이 풍부한 데이터 분석가입니다.</p>
</header>
<main>
<section class="main-section contact-section">
<h2>Contact</h2>
<p id="mobile"><b>Mobile:</b> 010-1234-5678</p>
<p id="email"><b>E-MAIL:</b> [email protected]</p>
<p id="address"><b>Address:</b> 서울시 송파구 보니로</p>
<p><b>Social & Websites:</b>
</p>
<div id="socials-div">
<a id="linkedin_link" href="https://www.linkedin.com/">LinkedIn</a>
<a id="github_link" href="https://github.com/">GitHub</a>
<a id="instagram_link" href="https://www.instagram.com/">Instagram</a>
</div>
</section>
<section class="main-section skills-section">
<h2>Skills</h2>
<ul><!--unordered list-->
<!--list item-->
<li>Phtyon</li>
<li>R</li>
<li>SQL</li>
<li>Tableau</li>
<li>Machine Learning</li>
</ul>
</section>
<section class="main-section education-section">
<h2>Education</h2>
<ul>
<li>보니대학교 컴퓨터 공학과, 학사</li>
<li>보니대학교 데이터 사이언스, 석사</li>
</ul>
</section>
<section class="main-section projects-section">
<h2>Projects</h2>
<!--ordered list-->
<ol>
<li>고객 세그멘테이션을 위한 클러스터링 분석
<p>
이 프로젝트에서는 K-means 알고리즘을 사용하여 고객 데이터를 분석하고 세그먼트를 생성했습니다. 결과적으로 마케팅 팀이 타겟팅 전략을 더 효율적으로 수행할 수 있었습니다.
</p>
</li>
<li>시계열 데이터를 활용한 매출 예측 모델 개발
<p>
ARIMA 모델을 활용하여 회사의 분기별 매출을 예측했습니다. 이 모델은 실제 매출과 95%의 정확도로 일치하는 결과를 보였습니다.
</p>
</li>
<li>자연어 처리를 이용한 고객 리뷰 분석
<p>
고객 리뷰 데이터를 수집하여 감정 분석을 수행했습니다. 이를 통해 제품 개선 포인트와 고객 만족도를 측정할 수 있었습니다.
</p>
</li>
</ol>
</section>
</main>
</body>
</html>p,ul,ol,h2 {
margin: 0;
padding: 0;
}
body {
margin: 20px;
background-color:white;
font-size: 20px;
}
header {
background-color: #50b3a2;
color: white;
padding: 10px 0px 10px 0px ;
text-align: center;
line-height: 1.5;
}
#name {
margin: 10px 0;
}
#introduction {
font-size: 18px;
margine: 20px;
}
main{
display: flex;
flex-direction: column;
gap: 30px;
background-color: whithe;
margin: 20px;
padding: 20px;
border-radius: 8px;
box-shadow: 0px 0px 10px rgba(0,0,0,0.1)
}
.main-section {
display: flex;
flex-direction: column;
gap: 20px;
}
.main-section > h2 {
background-color: rgb(65,65,65);
color: white;
padding: 10px;
margin:0;
}
.contact-section {
gap: 10px;
}
.contact-section > p {
margin: 0 0 0 20px;
}
#socials-div {
display: flex;
justify-content: space-around;
}
ul, ol {
padding: 0 20px;
}
.projects-section ol {
list-style-type: upper-alpha;
}직접 서버를 구축하고 관리
- 제어력 높으나 관리가 복잡 (서버 유지보수, 보안 등)
- Apache나 Nginx 같은 웹 서버 소프트웨어 사용
이미 구축되어있는 서버를 일정기간, 원하는 만큼 빌려서 사용
- 확장성과 관리 편의성이 뛰어나지만, 비용이 들 수 있음
- Amazon AWS, Microsoft Azure, Google Cloud 같은 클라우드 서비스 이용
미리 만들어진 정적 웹 페이지를 호스팅하는 서비스
- 설정이 간단하고 대부분의 경우 무료로 사용 가능
- 동적인 기능(데이터베이스 연동, 서버 측 로직 등)에는 제한이 있을 수 있음
- GitHub Pages, Netlify, Vercel 등과 같은 호스팅 서비스를 사용
GitHub에서 제공하는 무료 :) 정적 사이트 호스팅 서비스
- 프로젝트의 README, 문서, 또는 개인 웹사이트를 간단하게 배포 가능
- 설정이 매우 쉽고, 커스텀 도메인 연결도 가능 (= 내가 원하는 이름의 주소)
- GitHub 저장소(Repository)와 직접 연동 => 코드 변경사항을 쉽게 웹에 반영할 수 있음
웹 자원의 위치를 지정
프로토콜
- HTTP: 데이터를 암호화하지 않고 그대로 전송 (보안 취약)
- HTTPS:HTTP에 보안 계층 추가됨 (데이터 암호화. 안전성과 무결성 보장)
- GET
- 데이터를 검색 (예: 페이지를 보여줘!)
- POST
- 데이터를 서버로 보내고 리소스 생성 (예: 신규 회원가입)
- PUT
- 데이터를 업데이트 (예: 회원정보 수정)
- DELETE
- 데이터를 삭제 (예: 회원 탈퇴)
메타데이터와 설정 정보
- 요청 헤더(Request Headers)
- User-Agent: 클라이언트의 브라우저와 운영 체제 정보
- Accept: 클라이언트가 수용할 수 있는 컨텐츠 유형
- Authorization: 인증 토큰 또는 크리덴셜
- 응답 헤더(Response Headers):
- Content-Type: 반환되는 컨텐츠의 유형 (예: text/html, application/json)
- Content-Length: 반환되는 컨텐츠의 길이
- Set-Cookie: 쿠키 설정 정보
클라이언트가 서버로 보내는 데이터
- GET
- GET 요청에서는 보통 본문이 없음 (필요시 주로 URL을 통해 데이터 전달)
- POST, PUT
- 추가 또는 업데이트할 데이터 (예: 폼데이터나 JSON 데이터 등의 형식)
서버가 클라이언트의 요청을 어떻게 처리했는지를 나타내는 세 자리 숫자
- 성공 응답 (Successful responses, 2xx)
- 200 OK, 201 Created, 204 No Content
- 클라이언트 에러 응답 (Client error responses, 4Xx)
- 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
- 서버 에러 응답 (Server error responses, 5xx)
- 500 Internal Server Error, 501 Not Implemented, 502 Bad Gateway
- 서버에 요청을 보낸다 어떻게?
- 서버에서 웹페이지 생성에 필요한 파일들을 받는다
- 웹페이지의 구조(HTML)을 파싱(=읽고 이해)한다
- 웹페이지의 디자인(CSS)를 파싱(=읽고 이해)한다
- 이해한 HTML과 CSS정보를 합쳐서 화면에 보여준다
… 이후 생략
-
Python에서 웹 서버와 HTTP/HTTPS 프로토콜을 사용하여 데이터 송수신
== HTTP 요청을 만들어서 보내고 응답을 받는다
-
용도: 웹 스크래핑, API 호출, 웹 서비스 통신 등
-
종류:
- requests 사용하기 쉽고, 다양한 HTTP 메서드를 지원. 복잡한 HTTP 작업도 간단하게 수행 가능.
- urllib Python 표준 라이브러리에 포함된 모듈. API가 조금 더 복잡하고, 여러 모듈로 나뉘어져 있음
- http.client Python 표준 라이브러리에 포함된 모듈. 매우 낮은 수준의 작업을 할 때 사용 == 높은 수준의 커스터마이징이 가능하지만, 사용이 복잡함.
%pip install requestsimport requestsurl = "https://bonniekwon0721.github.io/bonnie_resume_test"
response = requests.get(url)
responseprint(type(response))print(type(response))print('status code:',response.status_code)
print('contents:',response.content)
print('content type:',type(response.content))
print('text:',response.text)
print('test type:', type(response.text))%pip install bs4from bs4 import BeautifulSoupsoup = BeautifulSoup(response.content, 'html.parser')
type(soup)print(soup.prettify())
# prettify 하면 HTML 문서처럼 들여쓰기가 된다.%pip install bs4from bs4 import BeautifulSoupsoup = BeautifulSoup(response.content, 'html.parser')
type(soup)print(soup.prettify())
# prettify 하면 HTML 문서처럼 들여쓰기가 된다.header_tag = soup.find("header")
print(header_tag)print(type(header_tag))name_tag = soup.find(id="name")
name = name_tag.text
print(type(name_tag))
print(name)
print(type(name))mobile_tag = soup.find(class_="contact-section").find('p') # find를 두번 쓸 때는 앞의 조건이 무조건 있을 대만 사용해야 한다.
mobile_text = mobile_tag.get_text(strip=True) # 공백을 없앨 수 있다.
mobile_number = mobile_text.split(':')[-1]
mobile_numbersoup.find(class_="contact-section")contact_section_tag = soup.find(class_="contact-section")
contact_tags = contact_section_tag.find_all("p")
type(contact_tags)
for idx,tag in enumerate(contact_tags):
print(f'{idx}번째 p태그:',tag)
email_text = contact_tags[1].get_text(strip=True)
email = email_text.split(':')[-1]
emailaddress_tag = soup.find('b', string="Address:").find_parent('p')
address = address_tag.get_text(strip=True).split(':')[-1]
print(address)print('|'.join([name,mobile_number,email,address]))- 목표데이터는 리뷰 상세 페이지에서 제공함
- 리뷰 상세 페이지는 리뷰 고유번호(review id)를 사용해서 url로 접근 가능
=먼저 리뷰 고유번호를 수집해야한다! 어떻게?
- 호텔 리뷰 메인 페이지에는 1페이지당 5개 리뷰가 있음
- 각 리뷰를 담고있는 div에는 리뷰 고유번호가 “data-reviewid”라는 클래스에 담겨 있음
⇒ 페이지별로 접근해서 리뷰 고유번호를 수집해서 리스트에 담으면 되겠다! 어떻게?
- 호텔 리뷰 메인 페이지에 언어별 리뷰 개수가 있음
- 각 페이지는 5배수로 증가하는 url 패턴을 가지고 있음
⇒ 찾고자하는 리뷰 전체 개수와 url패턴을 활용해서 각 페이지에 접근하면 되겠네~
- 메인 페이지 URL로 접근해서
- 총 리뷰 개수를 구하고
- 각 페이지에 리뷰가 5개씩있는점을 사용해서 총 페이지 수를 구하자
- URL 패턴을 사용해서 리뷰 첫 페이지부터 마지막 페이지까지 차근차근 접근해서
- data-reviewid라는 클래스를 가진 div를 탐색해서
- 클래스에 부여된 값(=리뷰 고유번호)를 수집 하자
- 리뷰 고유번호를 사용해서 리뷰 상세 페이지 URL로 접근해서
- 목표데이터 14개에 접근하자! 어떻게?
import requests
from bs4 import BeautifulSoupMAIN_BASE_URL = "https://www.tripadvisor.co.kr/Hotel_Review-g297885-d21364207-Reviews{}-Grand_Hyatt_Jeju-Jeju_Jeju_Island.html"
headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"}def generate_main_url(page_num):
'''페이지 번호를 입력 받아서 해당 트립어드바이저 리뷰 페이지에 접근할 수 있는 url을 반환합니다.'''
if page_num == 1:
return MAIN_BASE_URL.format("")
return MAIN_BASE_URL.format("-or"+str((page_num-1)*5))# Scraping
[ STEPS ]
1. 메인 페이지 URL로 접근해서
(https://www.tripadvisor.co.kr/Hotel_Review-g297885-d21364207-Reviews-Grand_Hyatt_Jeju-Jeju_Jeju_Island.html)
- 총 리뷰 개수를 구하고
- 각 페이지에 리뷰가 5개씩있는점을 사용해서 총 페이지 수를 구하자
2. URL패턴을 사용해서 리뷰 첫 페이지부터 마지막 페이지까지 차근차근 접근해서
(https://www.tripadvisor.co.kr/Hotel_Review-g297885-d21364207-Reviews-or패턴-Grand_Hyatt_Jeju-Jeju_Jeju_Island.html)
- data-reviewid라는 클래스를 가진 div를 탐색해서
- 클래스에 부여된 값(=리뷰 고유번호)를 수집 하자
3. 리뷰 고유번호를 사용해서 리뷰 상세 페이지 URL로 접근해서
(https://www.tripadvisor.co.kr/ShowUserReviews-g297885-d21364207-r리뷰번호-Grand_Hyatt_Jeju-Jeju_Jeju_Island.html)
- 목표데이터 수집
[ 목표 데이터 ]
1. review_id (리뷰 고유번호 - 식별용)
2. member_id (리뷰 작성자 id - 식별용)
3. title (리뷰 제목)
4. rating_overall (종합 평점 - 5점 만점)
5. rating_date (리뷰 게시 날짜 - 년+월+일)
6. review_content (리뷰 내용)
7. stay_date (숙박 날짜 - 년+월)
8. trip_type (여행 유형)
9. rating_price (가격 평점)
10. rating_location (장소 평점)
11. rating_bed (침대의 퀄리티 평점)
12. rating_room (객실 평점)
13. rating_clean (청결도 평점)
14. rating_service (서비스 평점)response = requests.get(generate_main_url(1),headers=headers)
responsesoup = BeautifulSoup(response.content,'html.parser')
print(soup.prettify())Studied from 제로베이스 데이터스쿨
