파이썬으로 웹 다루기 (3)

PH_Lee·2024년 4월 3일

HTML을 분석해주는 BeautifulSoup

원하는 요소만을 가져오도록 HTML코드를 분석해주는 HTML Parser를 사용할 수 있다.
그 중 가장 유명한 것이 BeautifulSoup4입니다.

BeautifulSoup 객체 만들기

#pip로 라이브러리 다운로드
%pip install beautifulsoup4

#모듈 불러오기
import requests

# www.example.com 사이트를 요청한 후 응답 받아보기
res = requests.get("http://www.example.com")
res.text

# BeautifulSoup4 - bs4를 불러와봅시다.
from bs4 import BeautifulSoup

# BeautifulSoup객체를 만들어봅시다.
# 첫번째 인자로는 response의 body를 텍스트로 전달합니다.
# 두번째 인자로는 "html"로 분석한다는 것을 명시해줍니다.
soup = BeautifulSoup(res.text, "html.parser")

# 객체 soup의 .prettify()를 활용하면 분석된 HTML을 보기 편하게 반환해줍니다.
print(soup.prettify())

# title 가져오기
soup.title

# head 가져오기
soup.head

# body 가져오기
soup.body

# <h1> 태그로 감싸진 요소 하나 찾기
soup.find("h1")

# <p> 태그로 감싸진 요소들 찾기
soup.find_all("p")

# 태그 이름 가져오기
h1 = soup.find("h1")
h1.name

# 태그 내용 가져오기
h1.text

원하는 요소 가져오기 - 책 이름 모으기

# 스크래핑에 필요한 라이브러리를 불러와봅시다.
import requests
from bs4 import BeautifulSoup

# 예시 사이트에 요청을 진행하고, 응답을 바탕으로 BeautifulSoup 객체를 만들어봅시다.
res = requests.get("https://books.toscrape.com/catalogue/category/books/travel_2/index.html")
soup = BeautifulSoup(res.text, "html.parser")

# <h3> 태그에 해당하는 요소를 하나 찾아봅시다
book= soup.find("h3")

# <h3> 태그에 해당하는 요소를 모두 찾아봅시다
h3_results = soup.find_all("h3")

# book_list에서 우리가 원하는 제목(title)만 추출해봅시다.
for book in h3_results:
    print(book.a["title"])
# 이 데이터들을 리스트와 같은 컨테이너에 넣어 추후에 활용할 수 있겠죠!

HTML의 Locator로 원하는 요소 찾기

id, class

  • tagname : 태그의 이름
  • id : 하나의 고유 태그를 가리키는 레벨
  • class : 여러 태그를 묶는 라벨
# 스크래핑에 필요한 라이브러리를 불러와봅시다.
import requests
from bs4 import BeautifulSoup

## 또 다른 연습 사이트를 이용해봅시다.
res = requests.get("http://programmers.co.kr/pages/data_engineering")
soup = BeautifulSoup(res.text, "html.parser")

## id 없이 div 태그를 찾아봅시다.
soup.find("div")

## id가 results인 div 태그를 찾아봅시다.
soup.find("div", id="results")

# class가 "page-header"인 div 태그를 찾아봅시다.
find_result = soup.find("div", "page-header")

# 위 결과에서 text 값을 깔끔하게 가져와봅시다.
find_result.h1.text.strip()

원하는 요소 가져오기 - Hashcode 질문 가져오기

원칙

  1. 과도한 요청을 보내지 않습니다.
  2. 받아온 정보 활용에 유의합니다.
# 다음 User-Agent를 추가해봅시다.
user_agent = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}

# 필요한 라이브러리를 불러온 후, 요청을 진행해봅시다.
import requests
from bs4 import BeautifulSoup
res = requests.get("https://hashcode.co.kr/", user_agent)

# 응답을 바탕으로 BeautifulSoup 객체를 생성해봅시다.
soup = BeautifulSoup(res.text,"html.parser")

# 질문의 빈도를 체크하는 dict를 만든 후, 빈도를 체크해봅시다.
questions = soup.find_all("li", "question-list-item")
for question in questions:
    print(question.find("div", "question").find("div", "top").h4.text)

페이지네이션(Pagination)

많은 정보를 인덱스로 구분하는 기법

Query String을 통해 구분하는 사이트에서 가져오기

# Pagination이 되어있는 질문 리스트의 제목을 모두 가져와봅시다.
# 과도한 요청을 방지하기 위해 1초마다 요청을 보내봅시다.
import time

for i in range(1, 6):
    res = requests.get("https://hashcode.co.kr/?page={}".format(i), user_agent)
    soup = BeautifulSoup(res.text, "html.parser")
    questions = soup.find_all("li", "question-list-item")
    for question in questions:
        print(question.find("div", "question").find("div", "top").h4.text)
    time.sleep(0.5)

동적 웹 페이지와의 만남

HTML 내용이 고정된 정적(static) 웹 사이트

  • 정적 웹 사이트는 HTML문서가 완전하게 응답된다.

HTML 내용이 변하는 동적(dynamic) 웹 사이트

  • 동적 웹 사이트는 응답 후 HTML이 렌더링이 될 때까지의 지연시간이 존재

동적 웹 사이트의 동작 방식

웹 브라우저에선 JavaScript라는 프로그래밍 언어가 동작한다.
비동기 처리를 통해서 필요한 데이터를 채운다.

동기 처리 : 요청에 따른 응답을 기다린다.
비동기 처리 : 요청에 따른 응답을 기다리지 않는다.

동기 처리된 경우, HTML 로딩에 문제가 없다.

문제점

비동기 처리된 경우, 상황에 따라서 데이터가 완전하지 않은 경우가 발생한다
키보드 입력, 마우스 클릭 등을 requests로는 진행하기 어렵다.

  • 임의로 시간을 지연한 후, 데이터가 처리가 끝난 후 정보를 가져오면 된다.
  • 웹 브라저우저를 파이썬으로 조작하자
  • 웹 브라우저를 자동화하는 라이브러리 Selenium
    -> 응답 후 시간을 지연시킬 수 있고 UI와 상호작용이 가능하다.

요약

동적 웹사이트는 응답 후 바로 정보를 추출하기 어렵다. 또한, 다양한 키보드 입력과 마우스 클릭 등의 상호작용이 존재한다. 이런 상황을 해결하기 위해, 웹 브라우저를 파이썬으로 조작하는 전략을 취하자

profile
새싹 개발자

0개의 댓글