웹 스크래핑이 머리로 잘 정리되지 않아 다시 천천히 정리한다는 마음으로 쓴 포스팅이다.
웹 스크래핑의 기본 프로세스는 대개 정해진 패턴이 있다.
따지고 보면 웹 스크래핑이라는 것은 웹페이지에서 자신이 원하는 데이터를 긁어오는 것이므로 비교적 정형화된 작업이다. 정형화된 작업은 정형화된 프로세스가 있으므로 이것을 정리해서 머리에 넣어 두는 것이 중요하다.
웹 스크래핑 코딩의 기본 프로세스
1. 대상 웹페이지를 파싱(Parsing by BeautifulSoup)
(* 파싱이란 문자열데이터를 분석하고 분해하여 목적한 패턴에 맞게 문자열의 구조를 결정하는 것)
2. 파싱(Parsing)된 데이터 중에서 스크래핑하고자 하는 "전체 데이터"를 선택함
: 이때 find_all 또는 select 명령어를 사용하며 얻어지는 데이터는 리스트 형태이다.
: 이 리스트는 대부분 "대 리스트"안에 "소 리스트"들이 들어있는 구조이다.
3. 이 리스트형 데이터 안에서 직접 구하고자 하는 "단위 데이터"를 선택함
: 이때 find 또는 select_one 명령어를 사용하며
: for 순환문을 이용하여 "2"에서 만들어진 "대 리스트"안의 "소 리스트"를 대상으로 "단위 데이터"를 스크래핑
: 대 리스트 = [[소 리스트 = 내부에 "단위 데이터"], [소 리스트], [소 리스트], ...]
4. 이렇게 얻어진 "단위 데이터"를 출력함
: 출력은 단순하게 print문을 활용하거나 혹은 csv형태의 파일로 만들어서 출력해줌
1단계: 대상 웹페이지를 파싱(Parsing by BeautifulSoup)
BeautifulSoup이 무엇인지 찾아보다가 누가 아름다운스프라고 기억하면 된다고 해서 피씩 웃어버렸다.
BeautifulSoup은 복잡한 구조로 되어 있는 웹페이지를 스크래핑 (혹은 크롤링이라고도 표현)이 용이하도록 단순한 구조의 데이터로 만들어 주는 파이썬의 라이브러리이다.
이것을 활용하여 웹페이지를 데이터로 만드는 과정을 파싱(Parsing)이라고 한다.
이 파싱은 복잡한 과정이지만 파이썬 프로그램 안에서 라이브러리가 다 해줌 ㅋ
프로그래머 입장에서는 필요한 기본 라이브러리들을 install 해주고, 코딩의 상단에 정형화된 형태로 기입 해주면 된다.
(남들이 만들어 둔 코딩의 앞부분을 그대로 복사해서 사용하면 됨)
2, 3단계: 데이터 선택 과정
초보자 입장에서 어려움에 부딪히는 곳은 이 단계이다. 물론 나도 여기서부터 뭔소린가 하여 정리해보는 것이다.
HTML 문서가 구조적인 형태로 되어 있으므로 원하는 웹페이지에서 스크래핑할 부분만 정확히 선택할 줄 알면 되는데 이게 참 경험이 많이 필요한 일...이라고 한다.
데이터를 선택하기 위해서 사용하는 명령어인 find와 select에 대해서 나만의 기준을 정리해둬야 한다.
<기준>
- 기본적으로 find와 select 명령 중에서 어떤 것을 사용하더라도 같은 결과를 얻을 수 있다.
- 2번의 "전체 데이터"를 얻기 위해서는 "find_all"을 사용하거나 "select"를 사용해야 한다.
- 3번의 "단위 데이터"를 얻기 위해서는 "find"을 사용하거나 "select_one"을 사용해야 한다.
- find와 select 모두 사용법이 매우 다양하기에 어느 한쪽을 숙지해두는 것이 좋다.
- 크롬 개발자 도구에 "Copy selector" 기능이 있어서 선택자를 쉽게 가져올 수 있어 select를 많이 쓰게 될 수도 있다.
- 그리고, "find_all" 혹은 "select"로 얻어진 전체 데이터 중에서 "find" or "select_one"으로 단위 데이터를 빼내기 위해서는 for 순환문을 사용한다.
4단계: 출력 부분
출력부분도 첫 단계인 파싱처럼 비교적 단순하다.
print문을 사용할 경우는 그냥 하면 되고, csv 포맷의 문서로 출력하려면 csv 라이브러리를 코딩 상단에 import 시켜 주고 간단한 명령어만 몇 줄 추가하면 된다.
예제
따라서 해볼려고 했는데 페이지 자체가 완전히 사라져버렸다.... 그래서 진짜 따라서 하는 수 밖에..
=> 전체 프로세스 가운데서 2번째/3번째 단계인 데이터 선택 부분에 대해서 한가지 사례를 가지고 이해를 해보자!!
- 스크래핑 대상: 네이버 쇼핑의 휴대폰용 보조배터리의 Best 100 페이지
- 가져올 데이터: 1위 ~ 100위 제품 각각의 "제품명", "링크", "가격", "상품평 숫자" 데이터
- 전체 데이터와 단위 데이터
전체 데이터(대 리스트)는 아래 표시된 영역(빨간색 사각형)의 단위 데이터(소 리스트) 100개로 구성된 것이다.
빨간색 사각형 부분은 크롬 관리자 도구(F12)로 Element를 확인해 보면 class 명이 "_itemSection"인 <li> 태그들인 것을 알 수 있다.
이 <li> 태그를 열어보면 그 아래에는 <div>, <p>, <div> <div> 등의 다양한 태그들이 내재되어 있고 이 가운데에 우리가 가져오고 싶은 "품명", "링크", "가격", "상품평 숫자" 등이 들어 있다.
전체 데이터(대 리스트)를 확보하기 위하여 "find_all" 명령어를 사용하거나 "select"를 사용해본다.
- select를 사용하여 코딩을 한 경우
find_all 명령을 사용하거나 select 명령어를 사용해도 동일한 결과값을 얻게 된다.
select의 경우에는 크롬 관리자 도구가 제공하는 기능을 사용할 수 있기 때문에 실수할 염려가 없고 좀 더 편하다.
items은 전체 데이터가 들어가는 변수이다.
items = soup.select("#productListArea > ul > li")
위 코드에서 "#productListArea > ul > li" 부분이 Sector인데, 이 부분을 직접 입력하지 않고 아래와 같이 크롬 관리자 도구에서 <li> 태그 영역에 선택한 다음에 마우스 오른쪽 버튼을 눌러서 "Copy selector"를 선택하면 된다.
그러면, selector 값으로 "productListArea > ul > li:nth-child(1)"이 복사된다.
여기서 nth-child(1) 부분은 첫 번째 li 값을 가리키므로 전체 데이터를 얻기 위해서 이 부분만 삭제해서 코딩에 붙여넣기를 해주면 된다..
한결 간단..!(하다고 하지만 아직 안 간단한 느낌이다.)
이렇게 해서 개별 <li> 태그 값이 들어있는 "단위 데이터" 100개가 포함된 "전체 데이터"가 리스트 형태로 items 변수에 할당된다.
전체 데이터(리스트 형태의 데이터)를 확보한 다음에,
for문을 사용하여 단위 리스트를 한 개씩 열어서 namve, price, link, review_number라는 변수에 넣는다.
예를 들어서 리뷰수인 "review_number"의 경우에도 위에서 같은 방법으로 Copy selector를 가져오면 된다.
이렇게 얻어진 값이 "#productListArea > ul > li > div.info > span > a.txt > em"이고 여기서 텍스트 값(.txt) 추출하면 된다.
아래 코드는 select 방법을 사용한 코드로 얻어진 결과를 csv 파일로 저장하는 것이다.
import requests
import re
from bs4 import BeautifulSoup
import csv
url = "https://search.shopping.naver.com/~~~"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
res = requests.get(url, headers=headers)
res.raise_for_status()
soup = BeautifulSoup(res.text, 'html.parser')
items = soup.select("#productListArea > ul > li")
powerbanklist = [] # 리스트 생성
# print(items)
for item in items:
temp=[]
name = item.select_one("#productListArea > ul > li > p > a")["title"]
price = item.select_one("#productListArea > ul > li > div.price > strong > span.num").text
link = itme.select_one("#productListArea > ul > li > p > a")["href"]
review_number = item.select_one("#productListArea > ul > li > div.info > span > a.txt > em").text
review_number = review_number[1:-1]
# print(review_number)
temp.append(name)
temp.append(price)
temp.append(link)
temp.append(review_number)
powerbanklist.append(temp)
with open('powerbanklist_select.csv', "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(['품명', '링크', '가격', '리뷰수'])
writer.writerows(powerbanklist)
f.close
(find말고 select만 일단 하였다.)
아래 블로그를 공부하며 작성하였음!
https://smorning.tistory.com/331
'알아두면쓸데있는신기한잡학사전 > 고군분투흔적들' 카테고리의 다른 글
[Web] DB - MongoDB, pymongo (0) | 2022.08.22 |
---|---|
[Web] Python - 웹스크래핑 (0) | 2022.08.22 |
[Web] Python - python package (0) | 2022.08.22 |
[Web] Python - 기초 문법 (0) | 2022.08.22 |
[Web] 서버 - 클라이언트 통신 (0) | 2022.08.22 |