[천재교육] 프로젝트 기반 빅데이터 서비스 개발자 양성 과정 9기
학습일 : 2024.07.17
📕 학습 목록
- HTML 구조
- 요청과 응답
- HTML 파싱
- 웹 브라우저 자동화 도구
- 웹 페이지 상호작용
📗 기억할 내용
1) HTML 구조
- class : 모든 요소에 적용되는 속성
- id : 고유 식별자를 지정. 각 요소마다 고유한 id를 가짐
- <form></form>과 <input> : 사용자에게 정보를 입력 받고, 해당 정보를 서버로 제출
2) 요청과 응답
- HTTP 프로토콜 : 사용자 - 웹 서버가 서로 대화하기 위한 약속
- HTTP 상태 코드
- 200 : 요청을 성공적으로 처리
- 400 : 잘못된 요청
- 404 : 요청한 결과물을 찾을 수 없음
- 500 : 서버 오류 발생
- HTML 문서 출력
# HTTP 요청에 대한 응답의 본문을 반환
import requests
response = requests.get('http://example.com')
status_code = response.status_code
if status_code == 200:
print(response.text)
else:
print('잘못된 요청입니다.')
3) HTML 파싱
① 파싱
- 파싱(Parsing) : 텍스트 데이터를 분석&구조화 (→ 특정 데이터를 추출)
- 크롤링(Crawling) : 웹 크롤러 봇이 자동으로 웹 사이트를 이동하며 정보를 수집
* robots.txt : 웹 크롤러 봇의 접근 권한을 관리하는 파일. 개발자는 이 파일을 통해 콘텐츠 접근에 대한 허용/차단을 관리
- 스크래핑(Scraping) : 특정 웹 페이지의 특정 정보를 수집
- Beautiful Soup : HTML 문서를 분석&구조화하는 도구. 파싱을 위한 도구(크롤링X)
* BeautifulSoup 객체 : HTML 문서를 분석 → 파이썬's 구조화된 객체로 변환한 것. 개발자가 문서를 탐색 가능하게 해주는 객체
* response.text : 구조화 되지 않은 문자열. 탐색 불가능
import requests
from bs4 import BeautifulSoup
response = requests.get('http://example.com') # status_code 반환
soup = BeautifulSoup(response.text, 'html.parser') # html 언어로 구조화된 문자열 반환
② 요소 탐색
- 태그 조건을 만족하는 요소 탐색
- 단일 요소 탐색 : soup.find('태그명', attrs) * attrs : 속성 조건을 딕셔너리로 작성 ex : {'class': 'example'}
- 복수 요소 탐색 : soup.find_all('태그명', attrs)
- 특정 class를 포함한 요소 탐색
- 단일 요소 탐색 : soup.find(attrs={'class': '클래스명'}
- 복수 요소 탐색 : soup.find_all(attrs={'class': '클래스명'}
- 이중 반복문을 활용한 요소 내부의 요소 탐색
import requests
from bs4 import BeautifulSoup
url = "https://quotes.toscrape.com/"
response = requests.get(url)
status_code = response.status_code
if status_code == 200:
soup = BeautifulSoup(response.text, "html.parser")
# 문서 내부 class에 quote가 포함된 요소 모두 찾기
class_quote_list = soup.find_all(
attrs={"class": "quote"}
)
# 찾은 요소 리스트의 개별 요소(원소)를 순회
# 요소 내부에서 또 다른 요소를 탐색
for class_quote in class_quote_list:
quote_text = class_quote.find("span", attrs={"class": "text"})
# 요소의 텍스트 출력; 앞뒤 태그 제거
print(quote_text.text)
else:
print("비정상 요청입니다.")
- 여러 페이지 탐색
import requests
from bs4 import BeautifulSoup
# 참고 주소 https://quotes.toscrape.com/page/1/
# 요청할 주소의 기본이 되는 주소
base_url = "https://quotes.toscrape.com/"
# page 변수: 페이지 이동을 위한 페이지 번호
# 반복문을 활용하여 2개 이상의 페이지에 요청
for page in range(1, 11):
# 베이스 주소와 페이지 번호로 탐색할 주소 조합
url = f"{base_url}/page/{page}/"
# 반복문에 의해 페이지 번호만 바뀌고 여러번 요청을 합니다.
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
class_quote_list = soup.find_all(attrs={"class": "quote"})
print(f"{page} 페이지 인용문")
for class_quote in class_quote_list:
quote_text = class_quote.find("span", attrs={"class": "text"})
print(quote_text.get_text())
[TIP]
.text: 태그 내의 모든 텍스트(하위 태그의 텍스트 포함)를 문자열로 반환
.string: 태그의 직접적인 텍스트가 단일 문자열일 때만 반환. 하위 태그가 있으면 None을 반환
③ 속성(attribute) 추출
- 속성 목록 추출 : attrs → 요소의 속성 목록을 딕셔너리 형태로 반환
- 속성 값 추출 : attrs[속성 명]
import requests
from bs4 import BeautifulSoup
url = "https://quotes.toscrape.com/"
response = requests.get(url)
status_code = response.status_code
if status_code == 200:
soup = BeautifulSoup(response.text, "html.parser")
class_author_list = soup.find_all(attrs={"class": "author"})
for class_author in class_author_list:
# 요소의 속성 목록 출력
print(class_author.attrs)
# 요소의 itemprop 속성 값 추출
print(class_author["itemprop"])
else:
print("비정상 요청입니다.")
{'class': ['author'], 'itemprop': 'author'}
{'class': ['author'], 'itemprop': 'author'}
{'class': ['author'], 'itemprop': 'author'}
{'class': ['author'], 'itemprop': 'author'}
author
author
author
4) 웹 브라우저 자동화 도구
① Selenium
- 웹 브라우저를 자동으로 제어하는 도구
- 사람 대신 텍스트 입력•버튼 클릭•로그인 등의 작업을 자동화
- requests, Beautiful Soup 은 동적 웹페이지에 대해 데이터 추출이 불가하므로 Selenium을 활용하여 크롤링 진행
② WebDriver 객체
- 웹 브라우저 제어에 사용되는 핵심 객체
- 웹 페이지 열기•요소 찾기•클릭 등의 상호작용을 수행
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
# Service 객체 생성
service = Service(ChromeDriverManager().install())
# WebDriver 객체 생성
driver = webdriver.Chrome(service=service)
# [웹 페이지 열기]
driver.get("https://naver.com")
# [웹 페이지에서 조건과 값에 해당하는 단일 요소 탐색]
element = driver.find_element(By.CLASS_NAME, "클래스이름")
# [웹 페이지에서 조건과 값에 해당하는 복수 요소 탐색]
elements = driver.find_elements(By.ID, "아이디")
# [해당 요소에 대해 텍스트 입력 상호작용 실행]
search_box = driver.find_element(By.NAME, "query")
# 입력 박스에 Python 문자열 입력
search_box.send_keys("Python")
# [해당 요소에 대해 클릭 상호작용 실행]
button = driver.find_element(By.CLASS_NAME, "btn_search")
# 버튼 요소 클릭
button.click()
# [현재 페이지의 HTML 문서 정보]
page = driver.page_source
print(page)
# 드라이버 닫기
driver.quit()
[TIP] By 객체 탐색 조건
- By.ID : 요소의 id 속성을 조건으로 탐색
- By.NAME : 요소의 name 속성을 조건으로 탐색
- By.CLASS_NAME : 요소의 class 속성을 조건으로 탐색
- By.TAG_NAME : 요소의 tag 이름을 조건으로 탐색
- By.LINK_TEXT : a 태그 요소의 전체 링크 텍스트를 조건으로 탐색
- By.PARTIAL_LINK_TEXT : a 태그 요소의 일부 링크 텍스트를 조건으로 탐색
- By.CSS_SELECTOR : CSS 선택자를 조건으로 탐색
- By.XPATH : XPATH 표현식을 조건으로 탐색
③ 대기 매커니즘
- Implicit Wait : 암시적 대기 - 요소를 탐색할 때, 최대 시간(초) 만큼 탐색할 때까지 대기 "시간이 기준"
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
# Implicit Waits(암시적 대기) 10초 설정
driver.implicitly_wait(10)
driver.get("https://www.naver.com")
try:
# 조건에 해당하는 요소를 탐색합니다.
element = driver.find_element(By.CLASS_NAME, "element_class")
print("조건에 만족하는 요소를 찾았습니다.")
except:
print("조건을 만족하는 요소를 찾지 못했습니다.")
driver.quit()
- Explicit Wait : 명시적 대기 - 요소를 탐색할 때, 조건을 만족할 때까지 최대 시간(초) 만큼 대기 "조건이 기준"
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions(탐색 조건) 객체 불러오기
from selenium.webdriver.support import expected_conditions as EC
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("https://www.naver.com")
try:
# WebDriverWait를 사용하여 명시적 대기 탐색
# 찾는 요소가 문서 내에 존재할 때까지 최대 10초 대기합니다.
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'element_class'))
)
print("조건에 만족하는 요소를 찾았습니다.")
except:
print("조건을 만족하는 요소를 찾지 못했습니다.")
driver.quit()
④ requests & Beautiful Soup 과 Selenium 비교
# requests & Beautiful Soup
import requests
from bs4 import BeautifulSoup
response = requests.get("http://naver.com.com")
soup = BeautifulSoup(response.text, "html.parser")
mail = soup.find(attrs={"class": "service_name"})
print(mail)
# Selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.implicitly_wait(10)
driver.get("https://www.naver.com")
mail = driver.find_element(By.CLASS_NAME, "service_name")
print(mail.text)
driver.quit()
5) 웹 페이지 상호작용
- Selenium 이 수행할 수 있는 상호작용
- 웹 페이지 열기
- 요소 탐색
- 텍스트 입력
- 버튼 클릭
- 마우스 동작
- 키보드 동작 등
# [조건을 만족하는 버튼 탐색 후 클릭]
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
# By 객체를 위한 모듈 불러오기
from selenium.webdriver.common.by import By
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.implicitly_wait(10)
url = "https://www.naver.com"
driver.get(url)
# id가 search-btn인 요소 탐색
search_button = driver.find_element(By.ID, "search-btn")
# 검색 버튼 클릭
search_button.click()
driver.quit()
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.implicitly_wait(10)
url = "https://www.naver.com"
driver.get(url)
# [입력(input) 박스 탐색 후 값 입력]
# id가 query인 요소 찾기
search_input = driver.find_element(By.ID, "query")
# 입력 박스에 텍스트 입력
search_input.send_keys("파이썬")
search_button = driver.find_element(By.ID, "search-btn")
search_button.click()
# [단일 요소 탐색 후 텍스트 출력]
# class에 text가 포함된 단일 요소 탐색
quote_text = driver.find_element(By.CLASS_NAME, "text")
# 탐색한 요소의 text 속성 출력
print(quote_text.text)
# [요소 내부의 자식 요소 탐색]
# class에 quote가 포함된 복수 요소 탐색
quote_list = driver.find_elements(By.CLASS_NAME, "quote")
# 개별 quote 내부에서 자식 요소 탐색
for quote in quote_list:
# quote 요소 내부에서 class에 text가 포함된 요소 탐색
text = quote.find_element(By.CLASS_NAME, "text")
# quote 요소 내부에서 class에 author가 포함된 요소 탐색
author = quote.find_element(By.CLASS_NAME, "author")
print(f"{text.text} - {author.text}")
# [버튼 클릭을 통한 페이지 이동]
# 링크의 텍스트가 Next → 인 요소 단일 탐색
next_button = driver.find_element(By.LINK_TEXT, "Next →")
next_button.click()
# 종료
driver.quit()
📙 내일 일정
- 파이썬 크롤링(복잡한 웹 페이지 상호작용) 학습
'TIL _Today I Learned > 2024.07' 카테고리의 다른 글
[DAY 7] Data Manipulation (0) | 2024.07.19 |
---|---|
[DAY 6] Python Crawling (0) | 2024.07.18 |
[DAY 4] Python Programming (0) | 2024.07.16 |
[DAY 3] Python Programming (0) | 2024.07.15 |
[DAY 2] Python Programming (0) | 2024.07.14 |