쿠팡 크롤링을 해보려고 한다. 쿠팡에 있는 크림 제품 중 로켓배송만 선택하였고, 기말 프로젝트 때 사용할 상품명과 가격, 리뷰수를 크롤링해보겠다. 모든 크롤링 프로젝트는 다음 기말 때 사용할 데이터를 수집하는 과정이라고 보면 될 것 같다.
1. 라이브러리 불러오기
# 라이브러리 불러오기
from selenium import webdriver # 브라우저 자동화를 위한 모듈
import requests # HTTP 요청을 보내기 위한 모듈
from bs4 import BeautifulSoup as bs # HTML 내용 파싱을 위한 모듈
import pandas as pd # 데이터 조작 및 분석을 모듈
import time # 코드 실행 속도 조절을 위한 모듈
import re # 정규 표현식 사용을 위한 모듈
import pickle # 파이썬 객체 직렬화를 위한 모듈
from selenium.webdriver.common.by import By # 다양한 방법으로 엘리먼트를 찾기 위한 모듈
import datetime # 날짜와 시간 연산을 위한 모듈
2. 동적 크롤링 시작
from selenium import webdriver
from bs4 import BeautifulSoup as bs
import pandas as pd
import time
# 크롬 드라이버 로드
driver = webdriver.Chrome()
# 각 리스트 초기화
title = [] # 상품 제목 리스트
price = [] # 가격 리스트
review_cnt = [] # 리뷰 개수 리스트
driver.get('https://www.coupang.com/np/categories/486253?listSize=120&brand=&offerCondition=&filterType=rocket_luxury%2Crocket%2Ccoupang_global&isPriceRange=false&minPrice=&maxPrice=&page=10&channel=user&fromComponent=N&selectedPlpKeepFilter=&sorter=bestAsc&filter=&component=486153&rating=0&rocketAll=true')
time.sleep(3) # 페이지가 완전히 로드될 때까지 대기
# 스크롤하여 모든 데이터를 로드
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) # 스크롤 후 로딩 대기
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
# 페이지 소스를 가져와서 BeautifulSoup으로 파싱
soup = bs(driver.page_source, 'html.parser')
# 상품 정보 크롤링
items = soup.find_all('dl', class_='baby-product-wrap adjust-spacing')
for item in items:
# 제목 (제품 이름)
try:
a = item.find('div', class_='name').get_text(strip=True)
except:
a = 'null'
title.append(a)
# 가격
try:
b = item.find('strong', class_='price-value').get_text(strip=True)
except:
b = 'null'
price.append(b)
# 리뷰 개수
try:
c = item.find('span', class_='rating-total-count').get_text(strip=True)
except:
c = 'null'
review_cnt.append(c)
# 드라이버 종료
driver.quit()
# 크롤링한 데이터를 데이터프레임으로 변환
raw_data = pd.DataFrame({
'title': title,
'price': price,
'review_cnt': review_cnt
})
# 결과 출력
print(raw_data)
# CSV파일로 저장
raw_data.to_csv("d10.csv", index = False, encoding="utf-8-sig")
하지만 문제가 발생하였다. 왜냐하면 쿠팡에서 크롤링을 막은 거 같아 다음 url로 넘어가는 for문 크롤링이 불가능했다. 그래서 결국 글로우픽처럼 d1~d9까지 concat을 시켜주었다.
d1 = pd.read_csv("d1.csv")
d2 = pd.read_csv("d2.csv")
d3 = pd.read_csv("d3.csv")
d4 = pd.read_csv("d4.csv")
d5 = pd.read_csv("d5.csv")
d6 = pd.read_csv("d6.csv")
d7 = pd.read_csv("d7.csv")
d8 = pd.read_csv("d8.csv")
d9 = pd.read_csv("d9.csv")
coopang = pd.concat([d1,d2,d3,d4,d5,d6,d7,d8,d9], ignore_index=True)
쨘 이렇게 coopang 크롤링을 해보았다.
하지만 이것도 전처리가 필요하다. 숫자 데이터만 필요한데 콤마와 괄호가 너무 많다.
3. 전처리
#숫자화
for i in range(len(coopang)):
# price에서 숫자를 제외한 모든 문자를 삭제
coopang['price'][i] = re.sub("[^0-9]", "", str(coopang['price'][i]))
# review_cnt에서 숫자를 제외한 모든 문자를 삭제
coopang['review_cnt'][i] = re.sub("[^0-9]", "", str(coopang['review_cnt'][i]))
coopang
숫자화로 변경해주고, 데이터 중 2개를 기준으로 판매하는 상품 또한 많아서 1개인 상품만 남기고 나머지는 삭제해보겠다.
import csv
def filter_rows(csv_file, keyword):
filtered_rows = []
with open(csv_file, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
if keyword in row["title"]:
filtered_rows.append(row)
return filtered_rows
# CSV 파일 경로
csv_file = 'test_coopang.csv'
# 원하는 단어
keyword = '1개'
# 선택한 단어가 포함된 행들 추출
filtered_rows = filter_rows(csv_file, keyword)
# 결과 출력
for row in filtered_rows:
print(row)
print(len(filtered_rows))
print(len(coopang))
coopang.csv 안에 찾을 단어를 설정해주고 선택 단어의 행이 몇 개인지 확인한다.
import csv
import os
def filter_and_delete_rows(csv_file, keyword):
temp_file = csv_file.replace('.csv', '_temp.csv')
with open(csv_file, 'r', newline='', encoding='utf-8') as read_file, \
open(temp_file, 'w', newline='', encoding='utf-8') as write_file:
reader = csv.DictReader(read_file)
if 'title' not in reader.fieldnames:
raise ValueError("CSV 파일에 'title' 열이 없습니다.")
writer = csv.DictWriter(write_file, fieldnames=reader.fieldnames)
writer.writeheader()
seen_titles = set()
for row in reader:
title = row['title']
if keyword not in title and title not in seen_titles:
writer.writerow(row)
seen_titles.add(title)
os.replace(temp_file, csv_file)
# CSV 파일 경로
csv_file = 'test_coopang.csv'
# 삭제할 키워드
keyword = '3개'
# 키워드가 포함된 행 삭제
filter_and_delete_rows(csv_file, keyword)
그리고 삭제할 키워드가 들어가면 포함된 행을 삭제하는 함수를 제작하여 행을 정리해주었다.
하지만 여기서 문제가 발생한다. title이 있음에도 없다고 판단시켜 실행이 안되었다.
이것을 해결하기 위해 csv 파일 열 이름 확인시킨다.
# 잘 변경되었는 지 확인 작업
import csv
def print_csv_headers(csv_file):
with open(csv_file, 'r', newline='', encoding='utf-8') as file:
reader = csv.reader(file)
headers = next(reader)
print("CSV 파일의 열 이름:", headers)
# CSV 파일 경로
csv_file = 'coopang.csv'
# CSV 파일의 열 이름 출력
print_csv_headers(csv_file)
출력을 시켜보니 title이 아닌 \ufefftitle로 설정이 되어있었다. 그래서 이걸 다시 변경해주었다.
## csv title의 이름이 \ufefftitle의 오류가 있어 변경시켜줌
import csv
import os
# CSV 파일의 헤더를 변경하는 함수
def change_csv_header(csv_file, old_header, new_header):
temp_file = csv_file.replace('.csv', '_temp.csv')
with open(csv_file, 'r', newline='', encoding='utf-8-sig') as read_file, \
open(temp_file, 'w', newline='', encoding='utf-8') as write_file:
reader = csv.reader(read_file)
writer = csv.writer(write_file)
headers = next(reader)
headers = [new_header if header == old_header else header for header in headers]
writer.writerow(headers)
for row in reader:
writer.writerow(row)
os.replace(temp_file, csv_file)
# CSV 파일 경로
csv_file = 'coopang.csv'
# 변경할 열 이름
old_header = '\ufefftitle'
new_header = 'title'
# 열 이름 변경
change_csv_header(csv_file, old_header, new_header)
이렇게 변경한 csv파일에서 다시 키워드 들어가면 삭제하게 한다.
import pandas as pd
# CSV 파일 경로
csv_file = 'coopang.csv'
# CSV 파일을 읽어서 데이터프레임으로 변환
df = pd.read_csv(csv_file, encoding='utf-8-sig')
# 열 이름의 공백 제거
df.columns = df.columns.str.strip()
# price 열이 문자열 형식인 경우에만 공백 제거 및 숫자로 변환
if df['price'].dtype == 'object':
df['price'] = df['price'].str.strip().replace('[\$,]', '', regex=True).astype(float)
# review_cnt 열이 문자열 형식인 경우에만 공백 제거 및 숫자로 변환
if df['review_cnt'].dtype == 'object':
df['review_cnt'] = df['review_cnt'].str.strip().astype(int)
# 삭제할 키워드 목록
keywords = ['2개', '3개', '4개', '5개']
# 키워드가 포함된 행 삭제
pattern = '|'.join(keywords)
df = df[~df['title'].str.contains(pattern)]
# 중복된 'title' 행 제거
df.drop_duplicates(subset=['title'], keep='first', inplace=True)
# 변경된 데이터프레임을 다시 CSV 파일로 저장
df.to_csv("clean_coopang.csv", index=False, encoding='utf-8')
# 데이터프레임 출력 (선택사항)
print(df)
원하는 키워드 삭제 목록을 작성하고 삭제를 하니 1000개의 데이터가 480개로 줄어든 것을 알 수 있었다.
다음에는 쿠팡 csv를 가지고 시각화를 진행해 볼 것이다.
'Python > 파이썬 크롤링' 카테고리의 다른 글
쿠팡 리뷰 크롤링 뚫는 법 (0) | 2024.06.07 |
---|---|
올리브영 크롤링 하기 (1) | 2024.06.02 |
글로우픽 크롤링 (0) | 2024.05.29 |
[네이버 뉴스] 크롤링 하는 방법 (0) | 2024.05.08 |