본문 바로가기
TIL _Today I Learned/2024.07

[DAY 5] Python Crawling

by gamdong2 2024. 7. 17.
[천재교육] 프로젝트 기반 빅데이터 서비스 개발자 양성 과정 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