[TIL] 파이썬으로 웹 데이터를 크롤하고 분석하기 (4)

이원진·2023년 4월 20일
0

데브코스

목록 보기
9/54
post-thumbnail

학습 내용


  1. [특강] 좋은 코드를 작성하려면?

  2. 브라우저 자동화하기, Selenium

  3. Wait and Call

  4. 마우스 이벤트 처리하기

  5. 키보드 이벤트 처리하기

1. [특강] 좋은 코드를 작성하려면?


Chapter 1. 기본 닦기


  • 행동

    • 긍정적인 자세

    • 남과 비교하지 않기

    • 커리어 길게 보기

    • 질문 잘하기

    • 의사소통 잘하기

    • 문제 정의 잘하기

    • 결과 내기

  • 기술

    • 프로그래밍 언어 선택하기

      • 파이썬, 자바/스칼라 ...

    • 구문 및 데이터 유형 이해하기

      • 기본 문법 이해 -> 고급 문법 이해

      • 상황에 맞는 구문과 데이터 유형 사용

      • 많이 고민하고 많이 코딩하기

      • 남의 코드 보고 배우고 코드리뷰 받기

    • 깔끔하고 읽기 쉬운 코드 작성

    • 생산성 툴 익히기

      • Git/Github

      • IDE
        - 단축키, 플러그인 많이 사용해보기


Chapter 2. 좋은 코드란?


  • 좋은 코드를 작성하는 것은 훌륭한 개발자의 필수 요소

    • 읽기 쉽고, 이해하기 쉽고, 수정하기 쉬운 코드

    • 명확한 이름, 일관된 형식, 의미 있는 주석으로 체계적으로 구성된 코드

    • 테스트가 가능한 코드

    • 클래스와 함수가 하나의 일만 하는 코드

    • 모듈화되고, 중복이 적은 코드

    • 오류 처리가 코드베이스 전체에서 철저하고 일관성 있게 이루어지는 코드

    • 작성자가 아닌 사용자를 염두에 두고 작성한 코드

    • 중요한 기능일수록 더 완벽을 기한 코드

  • 코드 작성 원칙

    • DRY(Don't Repeat Yourself)

      • 작성한 코드를 필요한 곳에 재사용할 수 있는 방법 찾기

      • 반복문, 함수, 클래스 활용

    • KISS(Keep It Simple, Stupid)

      • 불필요한 복잡성을 피하고 코드를 가능한 한 단순하게 유지
        - 코드를 반드시 짧게 작성해야 하는 것은 아님
        - 내장함수 활용

      • 너무 많은 기능을 하나의 함수로 구현하지 말 것

      • 한 함수가 너무 길어지면 여러 개로 나눌 것

      • 읽기 쉽고 이해하기 쉬운 코드를 작성하려고 노력할 것


Chapter 3. 코딩 규칙과 모범 사례 따르기


  • 일반적인 원칙

    • 일관된 포맷 및 이름 지정 규칙

      • 함수, 변수, 파일 이름은 이해하기 쉽도록, 약어를 피해 작성

    • 의미 있고 설명적인 변수 이름 사용

    • 적절한 주석 및 문서화

    • 제어 구조와 알고리즘의 효율적인 사용


Chapter 4. 코드 리뷰하기


  • 주니어 개발자나 새로 온 개발자들을 트레이닝시키는 최선의 방법

  • 단점은 리뷰를 해야하는 사람들이 이미 바쁜 사람이라는 점

  • 좋은 코드리뷰 방법

    • 코드리뷰 요청자

      • 요청 시 되도록이면 조금씩 자주 요청

      • Unit Test와 같이 요청하면 가장 좋음

      • 주석을 최대한 추가하고 무슨 이유에서 뭘 하려고 한 것인지를 설명

      • 리뷰에 대한 피드백을 너무 감정적으로 받아들이지 않기

    • 코드리뷰 진행자

      • 코딩 스타일에 대한 것보다는 코드 자체에 대해 이야기

      • 객관적으로 쓰고, 비판하는 어조는 피하기

      • 충분한 시간을 들여 도움이 되는 리뷰 제공

    • 코드 리뷰에 편리한 툴 사용


Chapter 5. 코드 테스트


  • 어떤 테스트들이 존재하는가?

    • Unit Test: 모듈의 특정 기능(함수) 테스트

    • Integration Test: 여러 모듈을 통합하여 하는 한 차원 위의 테스트

    • Acceptance Test: 트래픽 등을 생성하여 시스템이 부하를 견디는지 확인하는 테스트

    • UI Test: 최근에는 Selenium 등의 툴을 이용해 웹페이지 자체의 기능을 테스트

  • 테스트의 중요성

    • 많은 회사들이 코드 변경의 일부로 Unit Test를 의무적으로 요구

      • 테스트가 없으면 코드 체크인 실패

    • 테스트가 많을수록 이점이 존재

      • 시스템의 안정성 증대

      • 나중에 리팩토링할 경우 혹은 신입 엔지니어들이 코드 수정할 때 편리

  • Unit Test

    • 자신이 만든 소프트웨어의 특정 기능을 테스트하는 것

      • 특정 입력에 대해 예상되는 출력이 나오면 성공, 아니면 실패와 같은 형식으로 작성

    • 다른 테스트에 비해 가장 낮은 레벨의 기본 테스트

    • python의 unittest 라이브러리 사용

  • Test Coverage

    • 실행 가능 경로 중 몇 퍼센트나 테스트가 되었는지를 나타내는 비율

    • 높을수록 시스템이 안정되고, 리팩토링, 신입 직원 작업 시 용이


Chapter 6. 소스 버전 관리 툴 익히기


  • 소프트웨어 소스코드의 변경사항을 관리할 수 있도록 도와주는 프로그램

  • Git/Github으로 대표됨

  • 사용하는 이유

    • 코드 변경사항을 쉽게 추적 가능

    • 여러 명이 개발 시 코드의 공유와 변경 용이

    • 코드리뷰 기능 지원

    • 코드 백업의 역할


Chapter 7. CI/CD 프로세스 만들기


  • 소프트웨어의 새로운 기능을 빠르게 출시하기 위해서는 정기적인 배포가 아닌 기능이 구현되는대로 배포

    • 이를 가능케 하는 것이 CI/CD

  • 자동화된 프로세스

    • 관련 코드 커밋

    • 테스트 수행

    • 패키지 생성(빌드)

      • 소프트웨어를 최종적으로 배포하기 위한 형태로 만드는 것

      • 이를 위해서는 충분한 테스트가 필요

    • 패키지 배포

    • 모니터링

  • 보통 DevOps 팀이 담당

  • 구현 방법

    • 코드 repository를 하나로 유지

    • 코드 변경사항을 지속적으로 해당 repository에 반영(CI: Continuous Integration)

    • Unit Test 작성

      • Test Coverage를 70% 이상으로 유지

    • 안정적인 테스트 환경 구축

    • 빌드 생성 자동화(테스트 포함)

    • 빌드 배포 자동화(CD: Continuous Deployment)


2. 브라우저 자동화하기, Selenium


  • Selenium 프레임워크

    • Python으로 웹 브라우저를 조작할 수 있는 자동화 프레임워크

    • pip3 install selenium

  • Web Driver 프레임워크

    • 웹 브라우저를 제어할 수 있는 프레임워크

    • pip3 install webdriver-manager

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

# 주어진 명령이 끝나면 드라이버를 종료하도록 with-as 구문 사용
# 크롬 드라이버 객체 생성
with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:

    # 요청 전송
    driver.get("http://example.com")

    # <p> 요소 하나 찾기
    print(driver.find_element(By.TAG_NAME, "p").text)

    # <p> 요소 여러 개 찾기
    for element in driver.find_elements(By.TAG_NAME, "p"):
        print("Text:", element.text)

    # Response의 HTML 문서 확인
    print(driver.page_source)

3. Wait and Call


  • Selenium은 동적 웹사이트에 대한 지원으로 암묵적 기다림(Implicit Wait)명시적 기다림(Explicit Wait)을 지원

    • Implicit Wait: 로딩이 끝날 때까지 지정한 시간 동안 기자림

    • Explicit Wait: 특정 요소에 대한 제약을 통해 기다림

  • 사용할 사이트: https://indistreet.com/live?sortOption=startDate%3AASC

  • 최근 웹사이트는 스크래핑을 방지하기 위해 랜덤한 class 이름을 사용하는 경우가 많음
    -> 여러 가지 해결방안 중 위치를 활용하는 XPath 활용

  • XPath

    • XML, HTML 문서 등의 요소의 위치를 경로로 표현하는 것
      데스크탑/폴더1/폴더2/...

    • 개발자 도구에서 가져오고 싶은 요소를 클릭해 Copy > Copy XPath

    • //*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]

      • 인덱스는 1부터 시작

  • Implicit Wait

    • .implicitly_wait(second)
      • 반드시 주어진 시간을 모두 기다리는 것이 아니라, 로딩을 마칠 때까지의 한계 시간을 정하는 것

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import WebDriverWait
    from webdriver_manager.chrome import ChromeDriverManager
    
    with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
        driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
    
        # 암묵적 기다림(최대 10초)
        driver.implicitly_wait(10)
    
        # 1초 ~ 10초
        for i in range(1, 11):
            element = driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[{}]/div/a/div[2]/p[1]'.format(i))
            print(element.text)

  • Explicit Wait

    • until(arg): 인자의 조건이 만족될 때까지
    • until_not(arg): 인자의 조건이 만족되지 않을 때까지

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import WebDriverWait
    from webdriver_manager.chrome import ChromeDriverManager
    
    with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
        driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
    
        # 명시적 기다림
        # 타겟으로 명시한 요소를 반환
        # Xpath가 다음과 같은 요소가 존재할 때까지 최대 10초 간 기다림
        element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]')))
        print(element.text)

4. 마우스 이벤트 처리하기


  • 마우스로 일어날 수 있는 대표적인 이벤트
    • 마우스 움직이기(move)
    • 마우스 누르기(press down)
    • 마우스 떼기(press up)

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(service = Service(ChromeDriverManager().install()))
driver.get("https://hashcode.co.kr/")

driver.implicitly_wait(0.5)

# class가 2개 있는 태그 가져오기
button = driver.find_element(By.CLASS_NAME, "nav-link.nav-signin")
ActionChains(driver).click(button).perform()
  • perform() 메서드로 ActionChains에 쌓인 이벤트 실행

5. 키보드 이벤트 처리하기


  • 키보드로 일어날 수 있는 대표적인 이벤트
    • 키보드 누르기(press down)
    • 키보드 떼기(press up)

from selenium import webdriver
from selenium.webdriver import Keys, ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

import time

driver = webdriver.Chrome(service = Service(ChromeDriverManager.install()))
driver.get("https://hashcode.co.kr/")
time.sleep(1)

# 로그인 버튼 찾아서 클릭
button = driver.find_element(By.CLASS_NAME, "nav-link.nav-signin")
ActionChains(driver).click(button).perform()
time.sleep(1)

# 이메일 입력
id_input = driver.find_element(By.ID, "user_email")
ActionChains(driver).send_keys_to_element(id_input, "입력할 email").perform()
time.sleep(1)

# 비밀번호 입력
pw_input = driver.find_element(By.ID, "user_password")
ActionChains(driver).send_keys_to_element(pw_input, "입력할 비밀번호").perform()
time.sleep(1)

# 로그인 버튼 찾아서 클릭
login_button = driver.find_element(By.ID, "btn-sign-in")
ActionChains(driver).click(login_button).perform()
time.sleep(1)
  • send_keys_to_element() 메서드로 입력할 내용 전달

메모



0개의 댓글