scrapy 대규모 데이터 수집을 위한 패키지 라이브러리

0. scrapy - 대규모 데이터 수집을 위한 패키지 라이브러리

: scrapy는 데이터 수집에 최적화된 라이브러리로 페이지를 크롤링하고, url 다운로드 및 파싱하고, 데이터를 저장하는 과정 일련이 모든 과정이 한꺼번에 처리가 올인원 라이브러리이다. scrapy의 기본적인 사용 방법부터 알아보고 그 안에 있는 기능들을 다루는 세부 내용을 차례로 정리해보자.

1. scrapy 설치 및 기본 사용법

1) scrapy 라이브러리 설치 

: 터미널 혹은 cmd 개발 환경에서 아래 명령으로 scrapy 라이브러리 설치 

  • pip install scrapy

2) scrapy 프로젝트 구성 

: scrapy 프로젝트를 진행하고자 하는 경로로 이동한 후 신규 폴더를 생성한 뒤 프로젝트를 시작하기 위한 명령어를 기입한다. (예시로 scrapyproject2 활용)

  • 입력 내용 : scrapy startproject <프로젝트명>
  • 실제 입력 : scrapy startproject scrapyproject2

:  위와 같이 입력하면 폴더가 생성된다. 터미널에서 폴더 경로를 따라 폴더명(위에서 지정한)으로 2회 이동한다. 해당 위치에서  pwd 명령어 (현재 위치) ls 명령어 (현재 경로에 위치한 파일/폴더 리스트 확인)를 확인하면 아래와 같이 세팅되어 있음을 확인 가능하다.  

: 해당 위치에서 크롤링 페이지를 지정하기 위해 아래의 명령어를 입력해야 한다. (예시로 gmarket 페이지를 진행)

# 크롤러 이름 : 크롤링 프로젝트 내에 여러 가지 크롤러 (scrapy에서는 spider) 있을 수 있으므로, 각 크롤러의 이름을 지정

# 크롤링페이지 주소: 각 크롤러가 크롤링을 시작할 페이지를 주소로 지정

# 주소 입력 간에 'https://' 부분은 빼고 입력하는 것이 좋음 (중복 발생)

 

: 위의 작업이 완료될 시에 spiders 폴더 내에 ls 명령 시 해당 크롤러가 설치되었음을 확인 가능하다.

 

3) 해당 프로젝트 컴파일러에서 확인 

: 해당 폴더를 컴파일러(sublime text3 / atom/ vs code)에서 키면 아래와 같이 기본 세팅되어 있음을 알 수 있다.

 

 

4) 데이터 추출 및 추출 양식에 대한 작업 진행 

: gmarket best 페이지 내 상품명을 추출하는 상황을 가정하여 CSS selector를 활용해 추출하는 구문을 작성했다. 기본 구문 외의 추가적인 기능 (itme/ pipilines/ setting 등 타 페이지 활용법)은 다른 페이지에서 정리하고자 한다.

 

 

5) 터미널에서 명령어 실행 

: pwd 명령어(현재 경로 확인) 통해 프로젝트명으로 2번 이동한 경로에서 genspider을 통해 생성한 크롤러 이름을 입력하면 해당 VS코드에 작업한 명령어가 실행됨을 확인할 수 있다.

  • pwd

  • 입력 내용 : scrapy crawl <크롤러명>
  • 실제 입력 : scrapy crawl gmarket_best

selenium 동적 조작 기능 정리

0. selenium 동적 조작 기능의 필요성 

: 구글 드라이브를 통해 웹페이지에 들어가는 것만으로는 selenium의 기능을 충분히 활용할 수 없다. 동적페이지는 드라이브의 스크롤 위치, 클릭 여부 등에 따라 작동하는 HTML 정보가 다르기 때문에 웹페이지 내에서의 이동, 웹페이지 간의 이동을 자유롭게 조작할 수 있어야만 웹페이지에 위치한 필요한 정보를 수집 가능하다. 

✓조작하고자 하는 대상을 지정하는 방법

#대상으로 선언하고자 하는 코드 예시
<input type="text" name="name 값" id="id 값" />
#대상을 선정하는 코드 작성 예시
element = driver.find_element(By.ID, "id 값")
element = driver.find_element(By.NAME, "name 값")
element = driver.find_element(By.XPATH, "//input[@id='id 값']")
element = driver.find_element(By.CSS_SELECTOR, "input#id 값")

 

1. 드라이브 동적 조작 기능 정리

1. input 입력란 내용 기입  

elem = driver.find_element(BY.NAME, "NAME 값")

#기존에 채워진 정보 삭제 (비워있을 경우 쓰지 않아도 무관)
elem.clear()
#입력란에 내용 기입
elem.send_keys("입력하고자 하는 내용")
#엔터 키 입력 (elem.click()으로 대체 가능)
elem.send_keys(Keys.RETURN)

2. 버튼 클릭  

#클릭 대상 선언
elem = driver.find_element(BY.CSS_SELECTOR, 'CSS_SELECTOR 값'
#대상 클릭
elem.click()

 

3. 스크롤 이동  

# 웹페이지 제일 하단으로 이동
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 특정 높이까지 이동하고자 할 때는 아래와 같이 입력 (해당 위치 먼저 찾고 1000 대신 기입)
driver.execute_script("window.scrollTo(0, 1000)")

4. Drag & Drop  

# 드래그 대상 선언
element = driver.find_element(By.NAME, "source")
# 드롭할 대상 선언
target = driver.find_element(By.NAME, "target")

from selenium.webdriver import ActionChains

# 드래그&드롭 작업 진행
action_chains = ActionChains(driver)
action_chains.drag_and_drop(element, target).perform()

5. 이전 페이지, 이후 페이지로 이동  

# 이전 페이지로 이동
driver.back()
# 이후 페이지로 이동
driver.forward()

 

selenium - 동적페이지(javascript)에 특화된 라이브러리 

0. selenium - 동적페이지(javascript)에 특화된 라이브러리

:  크롤링에 이용되는 많은 라이브러리 중 selenium은 웹페이지와 상호작용 할 수 있다는 점에서 차이가 존재한다. 이러한 차이에 기반해 동적페이지 (javascript) 상의 정보를 추출할 수 있다는 장점이 있어 활용도가 높기에 selenium 라이브러리의 기본적인 구조를 먼저 정리하고 이후 장에서 관련 기능들을 추가적으로 정리해보고자 한다. 

✓ selenium 라이브러리 사용 코드 정리

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

chromedriver = '크롬 드라이버 저장 위치'
driver = webdriver.Chrome(service=Service(chromedriver))

driver.get("크롤링할 사이트 주소")

elems = driver.find_elements(By.CSS_SELECTOR,'CSS selector 값')

for i in elems:
    print(i.text)

driver.quit()

✓ selenium 선언 방법 정리

    - driver.find_element(By.XPATH, '//태그명[속성명="속성 값"]')

    - driver.find_element(By.CSS_SELECTOR, 'CSS selector 값')

    - driver.find_element(By.TAG_NAME, 'tag명')
    - driver.find_element(By.CLASS_NAME, 'class 값')

    - driver.find_element(By.ID, 'id 값')
    - driver.find_element(By.LINK_TEXT, '텍스트 전체')
    - driver.find_element(By.PARTIAL_LINK_TEXT, '포함 테스트 일부')
    - driver.find_element(By.NAME, 'name 값')

1. selenium 설치 및 기본 사용법

1. 라이브러리 설치 및 드라이버 설치

- selenium 실행 간 필요 라이브러리 설치

  • selenium 설치 : pip install selenium
  • 웹드라이버 설치 : pip install webdriver_manager

- 드라이버 설치 (현재 브라우져의 버전에 맞는 드라이버를 설치할 것)

Chrome https://sites.google.com/chromium.org/driver/
Edge https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Firefox https://github.com/mozilla/geckodriver/releases
Safari https://webkit.org/blog/6900/webdriver-support-in-safari-10/

2. selenium 실행 간 필요 라이브러리 임포트

 

3. chrome driver 경로 지정 및 드라이버 선언

- chromedriver의 저장 경로를 입력한 후, 드라이버 선언 예시

 

- chromedriver가 설치된 경로를 확인하는 방법

: chromedriver가 설치된 폴더 들어가 우클릭 후 'Get info' 클릭 시 chromedriver가 어디에 설치되어 있는지 확인이 가능하다. 본인의 chromedriver위치를 찾아 입력해야 한다.

4. url 주소 입력 및 크롤링 할 정보 선언

- url주소 입력 및 크롤링 할 정보 선언 예시

: 추출할 대상이 하나이거나 첫 번째 대상만 추출하고자 할 때에는 driver.find_elements 대신 driver.find_elmenet 사용 

 

- selenium 내 대상을 지정하는 방법 정리

    ※ 참고 사이트 : https://selenium-python.readthedocs.io/locating-elements.html#locating-elements

 

4. Locating Elements — Selenium Python Bindings 2 documentation

There are various strategies to locate elements in a page. You can use the most appropriate one for your case. Selenium provides the following method to locate elements in a page: The attributes available for the By class are used to locate elements on a p

selenium-python.readthedocs.io

    - driver.find_element(By.XPATH, '//태그명[속성명="속성 값"]')

    - driver.find_element(By.CSS_SELECTOR, 'CSS selector 값')

    - driver.find_element(By.TAG_NAME, 'tag명')
    - driver.find_element(By.CLASS_NAME, 'class 값')

    - driver.find_element(By.ID, 'id 값')
    - driver.find_element(By.LINK_TEXT, '텍스트 전체')
    - driver.find_element(By.PARTIAL_LINK_TEXT, '포함 테스트 일부')
    - driver.find_element(By.NAME, 'name 값')

BeautifulSoup - 초보 사용자를 위한 가장 간편한 라이브러리

0. BeautifulSoup find와 select 함수 이해

: BeautifulSoup 라이브러리를 통해 HTML 형태로 가공한 웹페이지 데이터 상에 필요한 정보를 특정하기 위해 추가적으로 함수 사용이 필요한데, 이때 사용되는 대표적인 함수 두 가지가 find와 select 함수이다. 기본적인 HTML, CSS 구조를 이해하고 find와 select 함수가 각각 어떻게 쓰이는지 정리해보고자 한다. 

✓ find 함수와 select 함수 사용법 및 결론 요약

: find 함수와 select 함수 중 select 함수 사용에 익숙해지는 것이 더 좋다. find와 select는 모두 태그명, 속성, 속성값을 활용하는 방식이지만, CSS는 보통 여러개의 선택자 (Selector)를 갖고 있기 때문에 태그를 특정하기 위해선 일반적으로 여러 요소(element)를 함께 조합해야 한다. 이때 경로를 지정하는 방식과 관련하여 find는 함수를 여러번 반복하여 코드를 작성해야 하는 반면 select는 하나의 함수 내에 직접 하위 경로를 지정할 수 있는 기능이 존재하기 때문이다. 

 

1) find 함수 사용법 - 아래 기본 구조 중 선택해 사용

  • data = soup.find('태그명')
  • data = soup.find('태그', class_ = 'class 값')
  • data = soup.find('태그', 'class 값')
  • data = soup.find(id = 'id값')
  • data = soup.find('태그', attrs = {'속성 이름' : '속성 값'})

1) select 함수 사용법 - 아래 기본 구조를 조합해 사용

  • data = soup.select('태그명')
  • data = soup.select('.클래스값')
  • data = soup.select('#id값')
  • data = soup.select('상위태그'  '자식태그')
  • data = soup.select('상위태그' > '자식태그')
  • data = soup.select_one('id값')[속성]
 

 

1. HTML과 CSS의 기본 구조 이해

: BeautifulSoup는 물론 앞으로 Selenium이나 Scrapy 같은 정보 추출을 위한 라이브러리를 활용하기 위해 우선적으로 HTML과 CSS 구조에 대해 이해해야 한다. 특히 하나의 요소 안에 담긴 속성명과 속성값의 개념을 이해하는 것과 태그 간의 관계성에 기반한 상위태그 자식태그의 개념 두 가지만 우선적으로 알아보자.

1. HTML 요소의 기본 구조

: HTML의 요소는 <시작태그>로 시작해 </종료태그>로 끝나는 하나의 구문을 말하며, 여러개의 속성을 가질 수 있다는 특징이 있다. (속성은 해당 태그에 추가적인 정보들을 담고 있다.) 우리가 일반적으로 추출하고자 하는 정보는 태그 사이에 있는 내용(아래 이미지 참고)에 위치해 있는 경우가 많아 태그명은 물론 속성명과 속성값에 대해 활용할 수 있어야 한다. 대표적으로 많이 사용되는 두 가지 속성 'Class'와 'Id'의 경우 별도의 표현 방식을 통해 해당 요소를 특정할 수 있어 데이터 추출 간 좋은 힌트가 될 수 있다.

2. 부모 태그와 자식 태그의 관계

: HTML은 요소들은 기본적으로 부모 자식 관계 혹은 형제 관계로 구분된다. 원하는 정보가 위치한 태그안에 해당 태그를 특정할 만한 속성 정보가 부족할 때, 해당 태그의 부모 태그까지 함께 이용하는 것이 가능하기 때문에 크롤링 과정에서 부모태그의 개념을 이해하는 것이 매우 중요하다. 부모 자식 관계는 들여쓰기 형태로 구분되어 있어 HTML 구문을 직접 보면서 바로 확인이 가능하다. 아래를 예시로 부모 자식 관계를 부등호 표시로, 형제 관계를 등호 표시로 표현해보자면 html > body > h1 = div > span = img 와 같이 정리 가능하다.

2. select 함수와 find 함수 사용법

✓ 활용 예제 : span 태그 내의 '상품명' 정보 추출하기

from bs4 import BeautifulSoup
html = """
<html>
    <body>
        <h1 id='head'>구좌명</h1>
        <div class='item'>
            <span class='title' id='first'> 상품명1 </span>
            <img class='main' id='first_img' src='이미지주소' width='50px'>
        </div>
        <div class='item'>
            <span class='title' id='first'> 상품명2 </span>
            <img class='main' id='first_img' src='이미지주소' width='50px'>            
        </div>
    </body>
</html>
"""
soup = BeautifulSoup(html,"html.parser")

1. find 함수를 활용한 정보 추출

: find 함수는 조건에 부합하는 태그 중에 가장 먼저 발견되는 하나의 값을 가져다 준다. (print로 출력) 또한 조건 간의 중복적으로 사용할 수 없기 때문에 하나의 함수에 조건만 추가할 수 있다. 만약 부모태그 정보를 넣고 싶다면 find 함수 자체를 여러번 사용해야 하는 불편함이 있을 수 있다.

 

1) find 함수를 사용해 정보 추출하기

 

- 태그명을 이용해 정보 추출하는 방법

- 태그명 + 클래스 값을 이용해 정보 추출하는 방법

- 아이디 값을 이용해 정보 추출하는 방법

- data = soup.find('태그', attrs = {'속성 이름' :'속성 값'})

2) find_all 함수를 사용해 조건에 부합하는 모든 값 추출하기 (for반복문 통해 출력)

3) find 함수 중복 사용을 이용한 부모 태그 정보 기입하기

2. select 함수를 활용한 정보 추출

: select 함수는 조건에 부합하는 모든 태그의 값을 리스트 형태로 반환한다. (for 반복문으로 출력) 또한 조건 간의 중복사용이 가능하기에 하나의 함수에 여러 조건을 함께 쓸 수 있다. 부모태그 정보도 함께 기입할 수 있는 기능이 있어 활용성이 find 함수에 비해 상대적으로 높다.

 

1) select 함수를 사용해 정보 추출하기

 

: 하나의 요소(element) 안에 놓인 태그명/ 클래스 값/ id 값을 띄어쓰기 없이 연속으로 적어 데이터 특정이 가능하다. 다만 작성간 아래 조건에 따라 각 속성들을 추가해야 한다.

  • data = soup.select('태그명')
  • data = soup.select('.클래스값')
  • data = soup.select('#id값')

2) select_one 함수를 사용해 정보 추출하기

 

: select_one 함수는 find 함수와 맞찬가지로 조건에 부합되는 값들 중 가장 먼저 발견되는 값을 가져와 print로 출력 가능하다

: select_one 함수를 활용하면 요소 안에 들어있는 내용뿐만 아니라 속성값 출력도 가능하다.

  • data = soup.select_one('id값')[속성]

3) select 함수 이용한 부모 태그 정보 기입하기

 

: select 함수는 단일 태그의 정보를 조합적으로 이용할 수 있으며 동시에 부모 태그 혹은 부모의 부모 태그 (그 이상까지도..) 하나의 함수로 직접 활용이 가능하다. 부모태그에 대해 띄어쓰기를 통해 표시하면 되지만 바로 앞에 위치한 부모태그의 경우 부등호 ('>') 표시를 통해 보다 정확하게 정보 표시가 가능하다.

  • data = soup.select('상위태그'  '자식태그')
  • data = soup.select('상위태그' > '자식태그')

BeautifulSoup - 초보 사용자를 위한 가장 간편한 라이브러리

0. BeautifulSoup - 초보 사용자를 위한 간편한 라이브러리

:  웹페이지 정보를 긁어오는 많은 라이브러리 중 BeautifulSoup는 사용법이 가장 간단해 단발적으로 소규모의 데이터를 수집할 때 많이 이용된다. BeautifulSoup의 기본적인 구조를 먼저 정리하고 다음장에서 활용도를 높이기 위한 기능들을 추가적으로 정리해보고자 한다. 

✓ BeautifulSoup 라이브러리 사용 코드 정리

import requests
from bs4 import BeautifulSoup

res = requests.get('url 주소 입력')
soup = BeautifulSoup(res.content,'html.parser')
data = soup.find_all('HTML 정보 입력')

for index in data:
    print(index.get_text())

 

1. BeautifulSoup 설치 및 기본 사용법

1) BeautifulSoup와 Requests 라이브러리 설치

: BeautifulSoup의 본래 기능은 크롤링을 위한 것이 아니기 때문에 페이지 url 정보를 담는 기능이 없다. 그렇기에 requests 라이브러리를 함께 설치해 url을 담을 수 있는 기능을 별도로 추가해야 한다. 

# 쥬피터 노트북에 pip istall 앞에 '!'를 추가해 직접 설치가 가능하다. 터미널에서는 '!' 없이 입력해야 한다.

 

 

2) 설치한 라이브러리 임포트 

 

3) url 주소 가져오기 (requests 라이브러리 사용)

 

4) url 주소 불러와 파싱하기 (문자열의 의미를 분석해 HTML 구조로 정리)

   

- 파서 이전 데이터 형태

   

- 파서 이후 데이터 형태 (html 형태로 변환됨을 확인 가능하다.)

5) 필요한 데이터 찾아 변수에 담고 결과값 추출하기

: 웹사이트에서 필요한 데이터를 찾아 특정하기 위해서는 HTML과 CSS에 대한 지식이 조금은 필요하다. 이에 대한 기본적인 지식과 데이터를 특정하는데 가장 많이 사용되는 find와 select 함수에 대해서는 하단에 추가로 정리해두었다.

 

 

2022.12.28 - [python/python_crawling] - [파이썬] BeautifulSoup find와 select 함수 사용법 정리

 

[파이썬] BeautifulSoup find와 select 함수 사용법 정리

BeautifulSoup - 초보 사용자를 위한 가장 간편한 라이브러리 0. BeautifulSoup find와 select 함수 이해 : BeautifulSoup 라이브러리를 통해 HTML 형태로 가공한 웹페이지 데이터 상에 필요한 정보를 특정하기 위

ghdehdwp.tistory.com

 

Scrapy, Selenium, BeautifulSoup 장단점 비교

0. 데이터 수집 간 여러 라이브러리를 이해할 필요성

 : python을 사용한 웹 크롤링 방식 중 개발자들이 실제로 가장 많이 사용하는 라이브러리로는 Scrapy, Selenium 그리고 BeautifulSoup가 대표적이다. 세 개의 라이브러리의 구동 원리와 그에 따른 장단점도 각각 다르기에 하나의 라이브러리만 선택 사용하기 보단 웹 환경에 맞는 라이브러리를 선택할 수 있어야 한다. 이를 위해 각 라이브러리의 특성에 대해 우선 정리하고 각 라이브러리에 대한 구체적인 사용법은 추후에 다시 정리해보고자 한다.

✓ 크롤링 라이브러리별 특징 요약

  • Scrapy : 연속적이고 방대한 양의 작업 시 적합한 라이브러리
  • Selenium : JavaScript 기반 동적 페이지 크롤링 작업에 적합한 라이브러리
  • BeaurifulSoup : 초보자 & 작은 규모의 간편한 작업에 적합한 리이브러리
  Scrapy Selenium BeautifulSoup
작업 속도 빠름 느림 중간
확장 가능성 높음 낮음 낮음
학습 난이도 어려움 중간 낮음
동적 페이지 작업 추가 라이브러리 필요 가능 가능
비동기 작업
(Asynchronous)
가능 불가 불가

 

1. Scrapy - 대규모 데이터 수집을 위한 패키지 라이브러리

: Scrapy는 웹사이트에서 필요한 데이터를 추출하기 위한 오픈 소스 프레임워크이다. Scrapy는 웹페이지 내 정보를 수집하는 전 과정에 있어 필요한 모든 것들이 갖춰져 있어 페이지를 크롤링하고, url 다운로드 및 파싱하고, 데이터를 저장하는 과정까지 Scrapy로 일괄 처리가 가능하다. (다만 javascript는 지원하지 않는다)

 

  Scrapy는 또한 스파이더라고 불리는 Scrapy 스크립트를 통해 사용자 정의 기능을 사용할 수 있도록 하여 미들웨어 및 확장을 지원하고 있다. 이는 개인의 상황에 맞춰 Scrapy 기능을 최적화 하는 등 확장성 있게 사용할 수 있음을 뜻한다. 또한 Scrapy 프레임워크는 프록시 추가, 크롤링 깊이 제어, 쿠키 및 세션 처리 등을 허용하고 있으며 Xpath, CSS 표현식을 사용하여 HTML 소스로부터 데이터를 추출하기 위한 기본 기능까지 지원하고 있다.

 

  Scrapy가 다른 라이브러리와 구분되는 가장 큰 이점으로는 비동기 네트워킹 방식의 라이브러리 (asynchronous networking library) Twisted를 기반으로 구축된다는 것이다. 즉  Scrapy는 비차단 메커니즘을 기반으로 사용자 요청을 비동기적으로 처리할 수 있어 많은 페이지에서 데이터를 동시적으로 추출할 수 있으므로 프레임워크가 매우 빠르고 대규모 스크래핑에 적합하다.    

1) Scrapy의 장점 정리

  • 데이터 수집, 가공 저장과 관련된 모든 기능을 일괄 제공하는 올인원 패키지이다.
  • 파이썬 기반의 미들웨어(스파이더 - Scrapy 스크립트)를 지원하여 쉽게 확장이 가능하다.
  • 비동기 네트워킹 방식의 라이브러리를 사용해 기존의 다른 스크래핑 라이브러리보다 매우 빠르다.
  • 훨씨 적은 메모리와 CPU 사용량을 소비하며 다양한 안정 장치로 안정적인 데이터 수집이 가능하다.
  • Xpath, CSS 표현식을 사용하여 HTML 소스에서 데이트를 추출하기 위한 기본 기능을 지원하고 있다.
  • python 기반의 오픈 소스, 다른 개발자와 커뮤니테이션을 통해 더 많은 정보 확보가 가능하다.

2) Scrapy의 단점 정리

  • 초보자가 숙달하기에 상대적으로 많은 시간과 노력이 필요하다.
  • JavaScript를 지원하지 않아 ajax/ pjax로 데이터가 갱신되는 웹페이지라면 데이터 추출이 쉽지 않음

 

2. Selenium - 동적 페이지(JavaScript)에 특화된 라이브러리

: Selenium은 프로그래밍 방식으로 헤드리스 브라우저를 제어할 수 있는 API이다. 본래 웹 자동화 테스트 (버튼 클릭, 스크롤 조작 등등)을 위해 사용되었지만 자바스크립트를 통해 렌더링 되는 데이터들을 다룰 수 있다는 특징으로 인해 웹스크래핑 작업에도 사용되기 시작했다.

 

  Selenium이 다른 라이브러리와 구분되는 가장 큰 특징으로는 웹사이트와 상호작용이 가능하다는 점이다. 많은 웹사이트가 JavaScript에 기반한 기능이 더해지면서 전체 페이지가 로드되어야만 페이지 내 모든 데이터를 다룰 수 있는 동적 페이지 형태로 구성되고 있는데, Selenium은 웹페이지를 실제로 실행시키고 이를 통제하는 웹사이트와의 상호작용 기능을 통해 동적 페이지 상의 모든 정보를 가져올 수 있는 것이다.

 

  또한 Selenium은 범용성이 좋다. python, java, Ruby 및 node.js를 포함한 여러 프로그래밍 언어에서 실행 가능하며 Chrome, Firefox는 물론 Internet Explorer까지 주요 부라우저를 모두 제어할 수 있다. 그외에도 Selenium은 오랜 시간동안 많은 사람들이 사용해 와 Selenium 사용과 관련한 거대한 커뮤니티를 가지고 있는데 이러한 특징 역시  Selenium의 활용 범주를 넓게 한다.

1) Selenium의 장점 정리

  • JavaScript를 이용한 동적 데이터(ajax/ pjax로 데이터가 갱신되는 웹페이지) 상의 정보 추출이 가능하다.
  • 여러 프로그래밍 언어를 지원하며 주요 브라우저를 대부분 제어할 수 있는 등 사용 범주가 넓다.
  • 디버깅 과정에서 브라우저를 직접 눈으로 확인할 수 있는 직관적이다.

2) Selenium의 단점 정리

  • 브라우저 전체를 제어하기 때문에 상대적으로 많은 메모리와 CPU 사용량을 차지한다
  • 브라우저를 실제로 실행시키는 과정에서 작업하기 때문에 속도가 많이 느리다. (대규모 작업에 부적합) 

 

3. BeautifulSoup - 초보 사용자를 위한 가장 간편한 라이브러리

: BeautifulSoup는 본래 HTML 또는 XML 페이지를 구조화하고 필요한 데이터를 선택하여 적절한 방식으로 추출 하는데 사용되는 라이브러리이다. 그렇기에 타 라이브러리와 다르게 웹페이지를 가져오는 등의 크롤링 과정에 필요한 기능들을 직접적으로 제공하진 않고 있어 Requests와 같은 다른 라이브러리와 함께 사용되는 것이 일반적이다. 

 

  BeautifulSoup의 가장 큰 특징은 사용 방법이 매우 간단하다는 점이다. 단 몇 줄의 코드만으로 기본적인 크롤링 작업이 가능하기에 많은 개발자들은 BeautifulSoup을 자주 사용하게 되었고, 결과적으로 관련 커뮤니티에서 이와 관련해 많은 사람들의 자료를 공유받을 수 있다.  전반적으로 BeautifulSoup는 일회성 또는 소규모 웹스크래핑 작업에 적합하며, 대규모의 양을 지속적으로 추출하는 경우에는 Scrapy를 사용하는 것이 적절하다.

1) BeautifulSoup의 장점 정리

  • 사용 방법이 코드 단 몇 줄로 매우 간단해 초보자도 사용하기에 용이하다.
  • 많은 사용자들이 있어 라이브러리 관련 정보를 쉽게 얻을 수 있다.

2) BeautifulSoup의 단점 정리

  • 데이터를 수집하고 처리하는 과정에서 일부 기능이 누락되어 추가 라이브러리 설치해야 한다.
  • 병렬적인 작업이 가능하긴 하지만 Scrapy와 비교할 시 속도면에서 뒤쳐진다.

openpyxl 라이브러리 사용해 엑셀 파일 추출하기

0. 코드정리 

- 엑셀 파일로 파이썬 데이터 내보내는 코드

# 출력하고자 하는 데이터 리스트로 정리한 후 
# def 함수 인자만 필요에 맞게 변경 시 파일 출력 가능
import openpyxl

def write_excel_template(filename, sheetname, listdata):
    excel_file = openpyxl.Workbook()
    excel_sheet = excel_file.active
    
    if sheetname != '':
        excel_sheet.title = sheetname
    
    for item in listdata:
        excel_sheet.append(item)
    excel_file.save(filename)
    excel_file.close()

- 파이썬으로 엑셀 파일 데이터 입력하는 코드

# 출력하고자 하는 파일명/ 시트명 확인 후
# 출력하고자 하는 데이터의 열 변경 후 사용할 것

import openpyxl

excel_file = openpyxl.load_workbook('파일명.xlsx')

# 별도의 시트 지정이 필요한 상황인지 확인 후 아래 두개 중 선택할 것
excel_sheet = excel_file.active
excel_sheet = excel_file.get_sheet_by_name('시트명')

for row in excel_sheet.rows:
    print(row[0].value, row[1].value, row[2].value)

excel_file.close()

1. 엑셀 파일로 파이썬 데이터 내보내기

: 파이썬을 통해 수집한 데이터를 엑셀 자료로 추출하는 여러 방법 중 가장 대표적인 것이 openpyxl 라이브러리를 활용하는 것이다. openpyxl 라이브러리를 통해 엑셀 파일로 출력하는 단계는 아래와 같이 진행된다. 데이터 입력 단계에서 리스트 형태로 입력해야 한다는 점에만 주의한다면 문제 없이 엑셀 파일로 출력이 가능할 것이다.

  • openpyxl 라이브러리 입력 (오류 시 pip install openpyxl 통해 라이브러리 등록)

  • Workbook() 함수 통해 신규 엑셀 파일 열기

  • 엑셀 파일 내 시트 지정 및 시트 이름 바꾸기

  • 엑셀 시트 내 파이썬의 리스트 데이터 입력하기

  • 엑셀 파일 저장 및 닫기

  • 위의 예시에 따라 출력된 엑셀 파일

 

2. 파이썬으로 엑셀 데이터 가져오기

: 파이썬 to 엑셀 파일로 출력하는 경우와 반대로 엑셀 파일 내 데이터를 파이썬으로 가져오려는 상황에서도 openpyxl 라이브러리를 사용하여 해결 가능하다. 엑셀 자료를 파이썬으로 출력하는 방법은 아래와 같이 이뤄진다.

  • openpyxl 라이브러리 입력 (오류 시 pip install openpyxl 통해 라이브러리 등록)

  • load 함수를 사용해 저장되어 있는 엑셀 파일 열기

  • 데이터 추출이 필요한 시트 지정

  • 시트 내 출력하고자 하는 데이터 설정 (아래의 예시는 열을 기준으로 출력 요청)

  • 엑셀 닫기

여러 페이지 동시 크롤링 위한 url 구조 활용

1. url 주소를 통한 웹페이지 구조 파악

: 유의미한 수준의 설득력 있는 인사이트를 도출하기 위해서는 충분한 양의 로우 데이터를 확보하는 것이 중요하다. 하지만 일반적으로 방대한 양의 데이터는 여러 페이지에 걸쳐 나열되어 있는 경우가 많기에 페이지마다 따로 크롤링 작업을 진행할 경우 모을 수 있는 데이터는 극히 제한적이다. 결국 여러 페이지에 걸친 크롤링 작업을 자동화하는 기술이 중요한데 이를 위해 우선적으로 확인해야 하는 것이 url 주소이다. 

 

초기 페이지 유입 시 url (상품리스트 1페이지)

 온라인 쇼핑몰 내 상품리스트를 들어가면 일반적으로 url 주소는 위와 같이 나타난다. 복잡하기만 하고 특별한 구조가 보이지 않아 일반적으로 쓰이는 반복문을 적용하는게 쉽지 않아 보이는데 이때 쇼핑몰 페이지를 앞뒤로 한두번 이동하다보면 숨겨져 있던 웹페이지 url 구조를 확인할 수 있다.

 

페이지 이동 시 나타난 url (상품리스트 2페이지)

 실제로 상품리스트 상의 2번 페이지로 이동하니 위와 같이 url의 숨은 부분이었던 '&page=2' 부분이 나타남을 확인할 수 있었다. 다른 페이지도 추가적으로 확인해보기도 하고 url 주소 내 숫자를 임의적으로 바꿔가면서 'page=N' 부분만 수정한다면 페이지별 반복작업을 자동화 할 수 있는 url 구조라는 사실을 확인할 수 있었다.

 

2. for 반복문을 통한 여러 페이지 동시 크롤링

: url 구조를 통해 확인한 구조를 바탕으로 for 반복문을 사용한다면 여러페이지에 걸친 크롤링 작업을 자동화할 수 있다. url 구조 상에서 변화가 필요한 부분을 정의한 뒤에 해당 부분을 range 함수 등 범위를 지정하는 방법을 통해 원하는 범위 만큼 작업 가능하다.

import requests
from bs4 import BeautifulSoup

url : 'https://www.ssg.com/disp/category.ssg?dispCtgId=6000184784&sort=sale&page='

for i in range(1,10):
    res = requests.get(url+str(i))  #페이지 표시 부분 for 반복문으로 대체
    soup = BeautifulSoup(res.content,'html.parser')
    items = soup.select('a > em.tx_ko')
    
    for item in items:
        print(item.get_text())

 

3. 페이지 오류 방지하기 위한 대처 방안

: 여러 페이지를 동시에 작업하다보면 일부 페이지의 수신 오류에 따라 진행중인 크롤링 작업이 전체 취소되는 경우가 자주 발생한다. 이러한 상황을 사전에 방지하기 위한 한가지 방법으로 응답 코드(response code)를 통해 서버 정상 수신 여부를 확인하는 status_code를 사용할 수 있다.

 

 웹페이지 상의 데이터를 요청할 경우 서버로부터 응답코드(response code)를 받게 되는데 해당 코드는 HTTP 규격에 따라 200인 경우 정상을 나타내며 그렇지 않은 경우 수신에 문제가 있다는 의미이다. 따라서 status_code 함수를 통해 특정 페이지 요청 후의 응답 코드가 200인지 그렇지 않은지에 대한 조건문을 더함으로써 중도 오류 없이 데이터 추출이 가능하다.  

url = 'https://www.ssg.com/disp/category.ssg?dispCtgId=6000184784&sort=sale&page='

for i in range(1,10):    
    res = requests.get(url+str(i))
    
    if res.status_code != 200:
        print('페이지 없음')      # 페이지 수신을 못한 경우 오류 발생 방지
    else:
        soup = BeautifulSoup(res.content,'html.parser')
        items = soup.select('a > em.tx_ko')
    
        for item in items:
            print(item.get_text())

select 함수를 사용한 추출 데이터 지정

0. 코드 정리

# 정보 추출할 사이트 주소와 데이터 특정할 인자 수정해 사용할 것 

import requests
from bs4 import BeautifulSoup
res = requests.get('정보 추출할 사이트 주소')
soup = BeautifulSoup(res.content,'html.parser')

# 데이터 특정 위한 인자 예시, 하단 설명 참고 
section = soup.select('p.item_title > a > span.prName_PrName')

for item in section:
    print(item.get_text())    #select() 함수는 리스트값을 결과로 입력하여 for 반복문을 통해 추출

1. 데이터 지정 간 select 함수를 사용하는 이유

: 정제되지 않은 웹사이트를 대상으로 상황에 맞는 크롤링 구문을 작성하다보니 크롤링 문법이 다른 문법에 비해 직관적이지 않게 보이는 특성이 있다. 그에 따라 보다 다양한 방법을 사전에 알고 있어야 다른 사람의 코드를 참조할 수 있는데 find()를 이용한 함수만큼 혹은 그 이상 사용되는 것이 select() 함수이다. find() 함수가 상대적으로 이해하기 쉬운 특징이 있는 반면 select() 함수는 보다 더 구체적인 구문을 특정하는데 용이하다는 특징이 있어 실제적으로 더 많이 이용되고 있다.

 

2. select 함수의 기본 사용 형태와 인자 작성법

1) 기본적인 사용 형태

: find() 함수와 기본적으로 사용 형태가 비슷해 보이지만 select() 함수의 경우 결과값을 받는 형태와 안에 들어가는 인자가 달라진다는 점에 유의해 사용해야 한다. find() 함수의 경우 결과값을 객체(object)로 받아 여러개의 값을 가져올 경우 find_all() 함수로 대체 사용해야 했다. 하지만 select() 함수의 경우 결과값을 기본적으로 리스트 형태로 받기 때문에 오히려 하나의 값에 대한 객체(object)로 받고자 할 때 select_one()이라는 함수로 대체 사용해야 하는 특징이 있다. 

# find()와 select() 함수는 호환이 가능한데, 정보 타입에 따라 select() 함수는 find_all() 함수와 select_one()함수는 find()함수와 교차사용이 가능하다. 

import requests
from bs4 import BeautifulSoup
res = requests.get('https://www.okmall.com/products/list?cate=20008603&gi_num=2')
soup = BeautifulSoup(res.content,'html.parser')

section = soup.select('p.item_title > a > span.prName_PrName') # find() 대신 select() 사용

for item in section:
    print(item.get_text())    #select() 함수는 리스트값을 결과로 입력하여 for 반복문을 통해 추출

 

2) select() 함수 인자 작성법

: select() 함수 내 인자를 작성할 때에는 CSS 언어의 style 태그가 HTML 태그를 취할 때의 문법 구조와 동일하게 작성된다. tag 값은 별도의 표시 없이 값만 가져오며 class 값은 앞에 "."과 함께 그리고 id 값은 앞에 "#"과 함께 쓰인다. 동일한 태그 내의 정보를 중복으로 사용 가능하며 이런 구문을 작성할 때에는 띄어쓰기 없이 붙여 사용해야 한다.

#tag 값 : tag 값 입력
#class 값 : .class 값 입력
#id 값 : #id 값 입력

import requests
from bs4 import BeautifulSoup
res = requests.get('https://www.okmall.com/products/list?cate=20008603&gi_num=2')
soup = BeautifulSoup(res.content,'html.parser')

section = soup.select('태그값.class값#id값') #단일 태그 안에 있는 정보를 기입할 떄에는 붙여서 사용 

for item in section:
    print(item.get_text())

또한 selcet()함수는 보다 구체적으로 특정 데이터를 특정하기 위해 상위 태그 정보를 함께 기입하는 방법도 존재한다. 기본적으로 띄어쓰기를 통해 상위태그와 하위태그 정보를 연속적으로 나열 가능하며 바로 앞에 있는 상위 태그임을 나태내고 싶다면 띄어쓰기 대신 ">" 기호를 추가할 수 있다. 다만 ">" 기호를 사용할 경우 바로 앞에 위치한 상위태그가 정보가 아닐 시에는 정보 추출이 제한된다는 점에 유의해야 한다.

#상위 태그 포함 예시
section = soup.select('태그명.class명 태그명#id명 > 태그명.class명' )

 

3) select() 함수 인자 추출 방법

: 웹페이지 내 '검사' 기능을 사용한다면 크롤링을 통해 추출하고자 하는 정보의 CSS selector 정보를 즉시적으로 복사할 수 있다. 웹페이지 검사 기능 내 원하는 정보가 담긴 구문을 우클릭한 후 'Copy' 안에 'Copy Selector'를 클릭한 뒤 해당 정보를 select() 함수 인자로 사용 가능한 정보를 추출 가능하다.

 

# 검사 기능 내 CSS selector 정보 카피하는 방법 이미지 

크롤링 기본 방법 및 필요 지식 정리

1. 크롤링 위한 기본 코드 정리

: 웹페이지 내 필요 정보를 크롤링하기 위해  BeautifulSoup, requests 두 개의 라이브러리를 사용하는 방법이 대표적이다. 해당 방법에 이용되는 코드의 의미를 알아야 이에 기반해 응용할 수 있는 폭이 넓어지니 우선적으로 코드에 대해 의미를 이해한 뒤 전체 코드를 사용해 작업에 사용하는 것이 이상적일 것이다.

#라이브러리 내 함수를 사용하기 위해선 사용자 컴퓨터 내에 라이브러리가 이미 설치가 되어 있어야 한다. (No module 에러 주의)

#Mac 환경 터미널, 윈도우 환경 cmd 내 'pip install 라이브러리명' 명령을 내림으로써 라이브러리 설치 가능하다.

 

1) 크롤링 위한 기본 코드

import requests
from bs4 import BeautifulSoup

변수1 = requests.get('사이트 주소')
변수2 = BeautifulSoup(변수1.content,'html.parser')

data = 변수2.find('h3')
print(data.get_text())

 

2) 크롤링 기본 코드 해석

: 위의 기본 코드에 대해 줄마다의 의미를 정리하면 아래와 같다. 결국 크롤링을 잘하기 위해선 4단계의 방법을 아는 것이 중요한데 페이지 검사 기능을 사용하는 것도 좋지만, 기본적인 HTML과 CSS에 대한 지식이 더해졌을 때 보다 응용할 수 있는 범위가 넓어질 것이다.

# 1단계 : 크롤링 관련 라이브러리 임포트
import requests  # 웹페이지 가져오기 라이브러리
from bs4 import BeautifulSoup # 웹페이지 분석(크롤링) 라이브러리

# 2단계 : 원하는 웹페이지 가져오기
href = requests.get('https://www.nocutnews.co.kr/news/5862355')

# 3단계 : 파싱 - 문자열의 의미를 분서해주는 것 (html 구조로 정리)
soup = BeautifulSoup(href.content,'html.parser')

# 4단계 : 필요한 데이터 찾아 변수에 담기
data = soup.find('h3')

# 5단계 : 결과값만 추출하기
print(data.get_text())

 

2. 크롤링 작업 간 필요한 HTML/ CSS 지식 정리

: 크롤링 기본 5단계 중 4단계 '필요한 데이터 찾아 변수에 담기'를 잘 수행하기 위해선 기본적인 HTML과 CSS 언어에 대한 지식이 필요하다. 태그만으로는 정보를 특정하는데 어려운 부분이 있어 class 값 혹은 속성 값 혹은 id 값을 상황에 맞게 적절히 사용해야 하며 이를 위해 HTML/ CSS의 기본 구성에 대해 알 필요가 있다.

 

1) HTML 코드의 기본 구성과 이에 기반한 필요 데이터 특정

: HTML 코드는 'tag' 를 기본 구성으로 'class 값', 'id 값', '속성 값'으로 구별된다. 필요한 정보 이상의 방대한 자료를 크롤링하거나 원하는 정보를 다 담지 못하는 경우를 방지하기 위해서는 크롤링하고자 하는 대상의 코드 구성을 확인하고 원하는 정보만을 정확히 특정할 수 있어야 한다. 

# HTML 코드 예  
<img class = "클래스명" id = "아이디명" src = "저장된 이미지 주소" width = "50px">

# class 값은 일반적으로 동일한 구조 안에서 내용만 달라지는 경우에 이를 군집하기 위해 사용되는 특징을 지님 

→ 웹 페이지 내 나열되어 있는 정보를 한꺼번에 크롤링하는 목적으로 사용하기에 적합하다.

# id 값은 주로 태그 간의 구분을 위해 사용됨으로 다른 태그와 중복 없이 단일로 사용되는 특징을 지님

→ 특정 태그 안에 정보를 단일로 가져오는 목적으로 사용하기에 적합하다.

 

2) HTML 구조 내 원하는 데이터를 변수에 담는 방법 

: tag/ class 값/ id 값/ 속성 값 네 가지 정보에 대해 원하는 정보를 특정하였을 때 각 경우에 따라 데이터 추출하는 방법 정리

# 1번째 방법 : HTML 태그를 통한 정보 특정
data = soup.find('태그')

# 2번째 방법 : HTML 태그와 class 값을 통한 정보 특정
data = soup.find('p', class_ = 'class 값')
data = soup.find('p', 'cssstyle')

# 3번째 방법 : HTML 태그와 속성 값을 통한 정보 특정 
data = soup.find('p', attrs = {'속성 이름'} = '속성 값')

# 4번째 방법 : id 값을 통한 정보 특정
data = soup.find(id = 'id값')

+ Recent posts