일단 제일 먼저 파이썬을 이용해서 데이터 크롤링을 해보기로 했다. 일단 데이터가 프로젝트의 생명이기도 하고 데이터를 추출해보면서 웹페이지를 어떻게 구상할지도 생각해보는게 좋을 것 같아서 말이다.
근데 사이트 하나를 혼자 힘으로 크롤링해보는건 처음이라 시행 착오가 꽤 될거라고 예상을 하긴 했지만..... 생각보다 너무 고생했다. 조금만 하면 나올 것 같아서 붙잡고 붙잡고 하느라 퀭한 눈으로 일주일을 보냈다. ㅎㅎㅎㅎ
이 고됐던 삽질의 과정을 눈에 보이는 곳에 기록해두고 나중에는 이런 실수들을 줄여가야겠다.
해외의 제로웨이스트 쇼핑몰 2~3곳을 파이썬 bs4 패키지를 이용해 크롤링하여 카테고리별로 DB화한다.
첫번째 대상 사이트: 'zero waste store'라는 미국사이트
보러가기
크롤링해야하는 데이터 : 카테고리명, 페이지수, 상품 타이틀, 가격, 이미지, 링크(상품 클릭 시 해당 쇼핑몰 상세페이지로 이동할 수 있도록)
주의 사항 : 기존에 해봤던 단순히 url과 keyword 따서 get 요청을 하는 식으로 크롤링을 돌리는게 아니라 여러개의 키워드가 있고, 이 키워드별로 여러개의 페이지수가 있다. 여느 쇼핑몰 페이지들이 그렇듯이...
그래서 이 로직을 연결하는게 이번 크롤링의 핵심.
4월 6일
4월 7일
전날 했던 크롤링을 페이지&카테고리를 url에 get request를 하려고 함수 만들기 시작했다. 하지만 인덴테이션 엉망으로 하고.. 함수도 요상하게 선언해서 만든게 망가졌다. 그러다 전날 추출한 카테고리를 다시 추출하려니 할 수 없어져서 여기에 몇시간을 쏟아부었다.
크롤링 할때 아직 find와 select_one의 차이 혹은 select / find_all을 써야하는때의 차이를 잘 구분하지 못해서 계속 에러가난다. 어제 2시간 넘게 걸리면서 안풀린 문제도 결국 이거때문이었다. 그것도 모르고 a태그 안에 있는 텍스트가 추출이 안되니까 pesudo 코드가 있는건지 같은걸 찾아헤맸고...그래도 이렇게 헤맨 덕분에 카테고리 텍스트를 메뉴바에서 크롤링하는것과 + 추가로 href 텍스트도 크롤링해야지만 페이지 url에 적용해서 페이지별 추출을 할 수 있다는걸 깨달았다.
내가 계속 해결 못했던 부분 박제
soup = BeautifulSoup(result.text, 'html.parser')
sidebar = soup.find("div", {"class": "sidebar-widget"})
a_tags = sidebar.find_all('a')
key = []
for a_tag in a_tags:
key.append(a_tag['href'])
print(key)
4월 8일
result = requests.get(url, headers=headers)
soup = BeautifulSoup(result.text, 'html.parser')
sidebar = soup.find("ul", attrs={'class': 'product-categories'})
atags = sidebar.find_all('a')
key_url = []
keys = []
for atag in atags:
key_url.append(atag.get('href'))
keys.append(atag.text)
return keys, key_url # request할때 필요한 url 뒷부분과 카테고리 리스트
response 200 뜨는거보고 이것도 사진 찍고ㅎㅎㅎ
4월 9일
for i in range(len(key_url)):
keyword = key_url[i]
result = requests.get(f"https://zerowastestore.com{keyword}")
soup = BeautifulSoup(result.text, 'html.parser')
links = soup.select(
'.products-footer > .shopify-pagination > ul > li > a')
if len(links) is 0:
pages.append(1)
else:
for link in links[:-1]:
pages.append(int(link.text))
if len(pages) < 2:
last_pages.append(pages[0])
else:
last_pages.append(pages[-1]) # 각 카테고리별 마지막 페이지 추출
위기2:
반복문을 너무 많이 엮어서 이제 로직이 너무 헷갈리는 식으로 함수가 길어졌다.
이런 코드는 전혀 좋은 코드가 아닌데... 무조건 함수를 여러개로 잘라서 붙여야지 가독성이 높아져 에러 고치는것도 쉽다고 배웠다. 근데 함수가 잘라져있을때 값이 연결이 안되어서 그냥 한 함수안에 쭉 넣어버릴 수 밖에 없었고 지금 그게 내 발목을 붙잡고 있다.
위기3:
키워드 url 추출 + 마지막 페이지 수 추출 = get request (url + 키워드 + 페이지수)로 아이템 정보 크롤링
이 구조가 간단하다고 생각했지만 사실 키워드별로 페이지수가 다르기 때문에 이걸 적절게 맞물린 결과의 url이 나오지 않는다... 아무래도 변수와 값들의 유효범위 같은 부분에 대한 이해가 아직 부족해서 그런것 같다. 3시간을 쏟았는데 아직 해결 못해서 머리 식힐겸 다른 부분 보고 또 도전하겠다. 크롤링하면서 제일 어려웠던 부분...
4월 10일
오피스아워때 멘토님께 질문을 해보니 문제의 원인이 밝혀졌다. ㅜㅜ
위에서 돌아가는 반복문과 아래 반복문이 중첩되어서 돌아가고 있었는데 그걸 멈추게 하는 코드를 넣어줬어야 했던 것.... 드디어 카테고리별 페이지가 한번씩 돌아가는 url 주소를 만들었다. (이부분에 대한 코드를 깃헙에 올려놓은줄 알았는데 없네. 아쉽다 )
근데 이걸 해결하기가 무섭게 또 에러발생.ㅎㅎㅎ 아이템들이 전체가 다 추출되지 않는다. 시벌탱ㅎㅎㅎㅎ
4월 11일 토요일
그리고 오피스아워때 멘토님이 내가 짠 코드 파악하시느라 중간 중간 프린트를 하시면서 보시는데 그게 꽤 좋은 방법 같아 보였다.
크롤링을 할때 정보를 알아보기 쉽게 구분해주는게 좋은 것 같아서 적용해서 해봤는데 확실히 도움이 됐다. 반복문이 많을때는 특히 이렇게 해야할 것 같다.
soup = BeautifulSoup(result.text, 'html.parser')
links = soup.select(
'.products-footer > .shopify-pagination > ul > li > a')
if len(links) is 0:
pages.append(1)
else:
pages.append(int(links[-2].text))
# print('카테고리: ', keys[i], '****************************')
# 각 카테고리별 페이지 수 만큼 반복되는 반복문 만들기
for j in range(1, pages[i]+1):
res = requests.get(
f"https://zerowastestore.com/{keyword}?page={j}")
data = BeautifulSoup(res.text, 'html.parser')
products = data.find('div', {'class': 'jas_contain'})
product = products.find_all(
'div', {'class': 'product-grid-item'})
for one in product:
title = one.select_one('.product-title').text
price = one.select_one('.price').text
img_h = one.select_one(
'.product-element-top > a').get('href')
img_url = f"https://zerowastestore.com{img_h}"
img_s = one.select_one(
'.product-element-top > a > img').get('src')
img_src = f"https:{img_s}"
추출한 소중한 데이터들은 도망갈새라 mongoDB에다가 호다닥 예쁘게 집어넣었다.
이렇게 첫번째 사이트 크롤링끝이다! (이제 겨우 첫....번째...? 허...)
이제 허버허버 html/css로 페이지 디자인 다듬어서 내 웹페이지에 예쁘게 데이터를 뿌려줘야겠다. 빨리 결과 보고싶다!!!