231025 데브코스 데이터 엔지니어링 TIL

아름다리·2023년 10월 25일

기본적인 웹 스크래핑의 실습을 하는 시간이었다.

bs4를 사용하여 스크래핑했는데, 기존에 해본 경험이 있어 낯설지 않았다.

다만 bs4가 이런거다, 기본적인 작동 방법 정도를 알려주는거라 혼자 더 연습하면서 사용법을 숙달해야겠다.

내일 강의에 selenium이 에정되어있는데, selenium 강의가 기대된다.


HTML을 분석해주는 BeautifulSoup

BeautifulSoup

  • requests 모듈을 사용하면 다 가져와 분석이 어려움
  • HTML Parser를 사용하면 편함
  • bs4는 가장 범용적인 파서중 하나
#bs4 설치

%pip install beautifulsoup4

BS4 객체 만들기 및 사용

# www.example.com 사이트를 요청한 후 응답 받아보기
#html 파서니 html 파일이 있어야한다
#모듈 불러오기

import requests

res = requests.get("http://www.example.com")

res.text
  • HTML 파서에 전달
# BeautifulSoup4 - bs4를 불러와봅시다.

from bs4 import BeautifulSoup as bs4 #보통 파이썬에서 대문자로 시작하면 클래스
  • bs 객체 생성
# BeautifulSoup객체를 만들어봅시다.
# 첫번째 인자로는 response의 body를 텍스트로 전달합니다.
# 두번째 인자로는 "html"로 분석한다는 것을 명시해줍니다.

soup = bs4(res.text, "html.parser") #res의 text를 먼저 전달, 어떤형식으로 분석할것인가 명시

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

print(soup.prettify())
  • 특정 요소 가져오기
# title 가져오기

soup.title

# head 가져오기

soup.head

# body 가져오기

soup.body

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

# <p> 태그로 감싸진 요소들 찾기
# find_all 사용

soup.find_all("p")

# 태그 이름 가져오기
#name 사용
h1.name

# 태그 내용 가져오기
#text사용

h1.text

원하는 요소 가져오기

책 이름 모으기

  • http://books.toscrape.com/catalogue/category/books/travel_2/index.html
  • 책의 제목을 가져올 것
  • 웹 페이지에서 챕 제목이 어느 요소에 들어있는지 먼저 사용해야함
  • 특정 태그를 타겟팅해서 가져오는건 가장 간단하면서 가장 좋지 않을 수 있음(구조가 변하기 때문)
  • 해당 페이지의 제목은 div 태그 ol 태그 li 태그 h3 태그 a 태그에 있음 저 태그를 가져오려면 어떤 정보가 필요한가 상대 적인 위치를 보면 h3 태그 안에 a 태그가 있음 h3는 11개가 있음 h3를 모두 가져와라. h3의 집합을 가져와라 하는 정책을 세울 수 있음 하지만 h3도 많은 태그에 감싸져 있음
  • 정리 h3 태그 안에 주어진 제목 정보들이 있음 그것을 가져오겠다는 아이디어, 목표 이것을 코드 구현, 스크래핑

스크래핑 진행

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

import requests
from bs4 import BeautifulSoup as bs

# 예시 사이트에 요청을 진행하고, 응답을 바탕으로 BeautifulSoup 객체를 만들어봅시다.

res = requests.get("http://books.toscrape.com/catalogue/category/books/travel_2/index.html")

soup = bs(res.text, "html.parser")

# <h3> 태그에 해당하는 요소를 하나 찾아봅시다

book = soup.find("h3")

# <h3> 태그에 해당하는 요소를 모두 찾아봅시다

h3_results = soup.find_all("h3")
len(h3_results)
h3_results[0]

# book_list에서 우리가 원하는 제목(title)만 추출해봅시다.
# 객체 - 메서드를 호출하거나 안에 있는 속성을 사용
# h3태그 안에 a태그를 속성처럼사용할수 있음
book.a.text
#title 속성에 전체 제목이 다 들어가 있음
#dic 처럼 사용
for book in h3_results:
    print(book.a.text)

for book in h3_results:
    print(book.a["title"])

#웹 사이트 확인
#찾고자 하는 요소가 어디에 있는가, 어떤 태그로 감싸져 있는가
#requests
#bs로 객체 만듬
#관련된 속성 사용

HTML의 Locator로 원하는 요소 찾기

ID와 CLASS

태그는 자신의 이름 뿐만 아니라 고유한 속성 또한 가질 수 있음

이 중에서 idclass는 Locator로서, 특정 태그를 지칭하는 데에 사용

  • tagname: 태그의 이름
  • id: 하나의 고유 태그를 가리키는 라벨
  • class: 여러 태그를 묶는 라벨
<p>This element has only tagname</p> #p태그로만 묶여짐
<p id="target">This element has tagname and id</p> #id와 target라는 키와 밸류, unique 해야함
<p class="targets">This element has tagname and class</p> #class, targets

idclass를 이용해서 HTML의 특정 태그를 지칭하고 가져오는 방법

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

import requests
from bs4 import BeautifulSoup as bs

## 또 다른 연습 사이트를 이용해봅시다.
# http://example.python-scraping.com/ (현재시점 접속안됨)

#국가정보가 많은 태그에 감싸져있음
#특정 로케이터 찾기
#span12
#id = result id가 results인것은 하나

res = requests.get("http://example.python-scraping.com/")

soup = bs(res.text, "html.parser")
  • ID를 이용해서 요소 가져오기
    • ID는 유니크함
    • 해당 태그 하나만 가져올 수 있음
## id 없이 div 태그를 찾아봅시다.

soup.find("div")

#태그,id, 클래스 이름으로 함께 검색

## id가 results인 div 태그를 찾아봅시다.

soup.find("div", id ="results")
  • CLASS를 이용해서 요소 가져오기
    • 유사한 요소들을 구분짓는 별명
    • 해당 하는 태그 하나를 가져올 수 있음
# class가 "page-header"인 div 태그를 찾아봅시다.
#파라미터 이름을 굳이 안 지정해도 됨

find_result = soup.find("div", "page-header")

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

find_result

finr_result.h1.text.strip() #특정 공백을 다 지움

원하는 요소 가져오기 II

HASHCODE 질문 모으기

https://hashcode.co.kr/

아래 두 가지 원칙을 지킵니다.

  1. 과도한 요청을 보내지 않습니다.
  2. 받아온 정보 활용에 유의합니다.

질문의 리스트를 가져오는게 목적

수많은 li태그와 question, top에 질문이 들어가있음
question-list-item 클래스
li태그 중에서 클래스가 question-list-item 인 것을 find all

# 다음 User-Agent를 추가해봅시다.

user_agent = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Whale/3.22.205.26 Safari/537.36"}
# 필요한 라이브러리를 불러온 후, 요청을 진행해봅시다.

import requests
from bs4 import BeautifulSoup as bs

res = requests.get("https://hashcode.co.kr/", user_agent) #user_agent는 헤더, 키와 밸류로 되어있음
# 응답을 바탕으로 BeautifulSoup 객체를 생성해봅시다.

soup = bs(res.text, "html.parser")
# 질문의 제목을 모아서 가져옴
#class = "question-list-item"을 다 가져옴
#그다음 안에 h4를 검색 -> 51개로 유일하지 않음

#question list item에 대해서 스크래핑
#연쇄적으로 사용가능
#soup.find("li", "question-list-item").find("div", "question").find("div","top").h4.text

#for문을 사용해서 반복해서 가져오기

questions = soup.find_all("li", "question-list-item")
for question in questions:
    print(question.find("div", "question").find("div","top").h4.text)

페이지네이션

페이지네이션은 많은 정보를 인덱스로 구분하는 기법

Query String을 통해서 이를 구분

https://hashcode.co.kr/?page={i}

# Pagination이 되어있는 질문 리스트의 제목을 모두 가져와봅시다.
# 과도한 요청을 방지하기 위해 1초마다 요청을 보내봅시다.
# 페이지네이션이 n번 된 페이지를 참조하려면 n번 요청해야함

import time

for i in range(1,6):
    res = requests.get("https://hashcode.co.kr/?page={}".format(i), user_agent) #중괄호의 변수를 i로 치환해줌
    soup = bs(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)

동적 웹 페이지

정적 웹 사이트와 동적 웹 사이트

  • 웹 페이지는 어떻게 생성되냐에 따라 2가지로 구문
  • HTML 내용이 고정된 정적(static) 웹 사이트
  • HTML 내용이 변하는 동적(dynamic) 웹 사이트
    • 내용들은 페이지가 온 다음에 실행됨
  • 차이점 - 핵심은 정보의 완성 타이밍
    • 정적 웹 사이트는 HTML 문서가 완전하게 응답된다
    • 동적 웹 사이트는 응답 후 HTML이 렌더링이 될 떄까지의 지연시간이 존재

동적 웹 사이트의 동작 방식

  • 웹 브라우저엔 JavaScript 프로그래밍 언어 동작
  • 비동기 처리를 통해서 필요한 데이터를 채움
    • 동기 와 비동기 - 여러 작업이 진행될때 한 작업이 끝날 때 그 작업의 결과가 돌아오는 것을 보장 하냐 마냐
    • 동기 처리 : 요청에 따른 응답을 기다림
- 비동기 처리 : 요청에 따른 응답을 기다리지 않음



- 동기 처리된 경우, HTML 로딩에 문제가 없음 (데이터 처리가 다 끝나기 때문)
- 비동기 처리된 경우 상황에 따라서 데이터가 완전하지 않은 경우가 발생 (데이터 처리가 진행중에 스크래핑을 하게 되는 경우 발생)

지금까지의 스크래퍼의 문제점

  • requests로 요청 시 발생하는 문제점
    • 동적 웹사이트에 적용이 어려움
    • 비동기일때 불완전한 응답을 받게 됨
    • ui 상호작용의 어려움
      • 키보드 입력, 마우스 클릭 등을, requests로는 진행하기 어려움
  • 해결
    • 임의로 시간을 지연한 후, 데이터 처리가 끝난 후 정보를 가져오기
- 키보드 입력, 마우스 클릭을 프로그래밍 하려면? → 응답이 온 후의 작업 → 응답이 온 후에 ui action을 할 수 있는 환경 구현
    - 웹 브라우저를 파이썬으로 조작하기
- 웹 브라우저를 자동화하는 라이브러리 Selenium
    - 응답 후 시간을 지연시킬  수 있음
    

    
    - UI와의 상호작용 가능
    
  • 문제점 요약
    • 동적 웹 사이트는 응답 후 바로 정보를 추출하기 어려움
    • 다양한 키보드 입력과 마우스 클릭 등의 상호작용을 하기 어려움
    • 웹 브라우저를 파이썬으로 조작하여 진행 (Selenium)
profile
주니어 개발자(인턴)

0개의 댓글