Skip to content

dss-16th/crawling-repo-3

Repository files navigation

crawling project

Screen Shot 2021-03-03 at 2 15 48 PM


프로젝트 소개

👏🏻 소유하고 있는 옷의 사이즈와 판매 중인 옷의 사이즈를 비교하여
  나에게 딱 맞는 핏의 옷을 찾는다.

목표

무신사 스토어 상품의 데이터를 크롤링하여 유저가 제공한 사이즈와 유사한 상품을 추천한다.


사이트 소개

무신사 스토어(MUSINSA STORE)

  • 메인 페이지 url

    https://store.musinsa.com/app/

  • 전체 url

    https://search.musinsa.com/category/{ 중분류 번호 }?device=&d_cat_cd=001001&brand=&rate=&page_kind=search&list_kind=small&sort=pop&sub_sort=&page={ 페이지 번호 }&display_cnt=90&sale_goods=&ex_soldout=&color=&price1=&price2=&exclusive_yn=&size=&tags=&sale_campaign_yn=&timesale_yn=&q=

  • 제품 상세 페이지 url

    https://store.musinsa.com/app/goods/{ 제품 번호 }


프로젝트 결과

step 1

카테고리에 해당하는 사이즈 정보를 입력받아 전달
⇒ javascript 활용

step 2

MySQL 검색 후 결과 리스트 제공


시스템 구조


프로젝트 진행 과정


01 Crawling

1. 목표 크롤링 페이지: 20만 개


  : 서버 1개로 크롤링하기엔 많은 양

  => Github <-> AWS instance



2. 복잡한 size 데이터 크롤링

size title, number가 다양함.


  : scrapy가 느려짐
  => scrapy 2개 사용: 'musinsa', 'size'



3. 서버 부하 => scrapy setting 조절

'CONCURRENT_REQUESTS': 12
# 'CONCURRENT_REQUESTS': 16
'AUTOTHROTTLE_ENABLED': True
# 'AUTOTHROTTLE_ENABLED': False

4. Crawling 수행시 나타난 특징적 에러

  1. Index out of range
    종종 'User-Agent'가 모바일로 설정되어 response가 m.store.musinsa.com으로 돌아와서 xpath가 틀리다고 나옴
    ⇒ settings.py 수정
RANDOMUSERAGENT_RANDOM_UA_TYPE = {
		'hardware_types': 'COMPUTER',
		'popularity': 'POPULAR'
}
  1. Took longer than 180.0 seconds
    서버에서 응답을 일부러 늦춤 (크롤링 대비)

5. scrapy response 속도 체험...

⋇⋇ gif 파일입니다..
속도체험


02 MySQL 저장

두 개의 테이블 (item, size)
: size 데이터가 복잡하여 item과 분리해 별도의 table을 만듦

from sqlalchemy import *
import pandas as pd


engine = create_engine("mysql://root:<pswd>@<ip>/mymusinsa?charset=utf8")

class MusinsaPipeline():
    def process_item(self, item, spider):
        df = pd.DataFrame([item])
        df.to_sql('item', con=engine, if_exists='append', index=False)
        engine.execute("SELECT * FROM item").fetchall()
        return item

1. size table

제품마다 S, M, L, ... 등의 사이즈 분류가 유동적

=> 일반적인 컬럼명으로 데이터 구조화
=> 했지만... 후에 문제 발생..


03 Web Service

Top / Outer / Pants / Onepiece / Skirt
: 다섯가지 카테고리로 구별

1. javascript

function Top() {
            var pic = "https://image.musinsa.com/images/size_type/detail_img/2019070114282500000014799.png"
            document.getElementById('GuideImg').src = pic;
            document.getElementById('GuideImg').style.display = 'block';
            maincode = '001'
        }
var url = "/getdatas?maincode=" + maincode + "&v1=" + vl1 + "&v2=" + vl2 + "&v3=" + vl3 + "&v4=" + vl4 + "&v5=" + vl5;

2. and, or 쿼리...

if maincode in ['001', '002', '020']:
        query_request = Size.query.filter(Size.main_code == maincode).filter(or_(Size.A_0 == size_values["v1"], Size.A_1 == size_values["v2"], Size.A_2 == size_values["v3"], Size.A_3 == size_values["v4"])).limit(10)
        rs = [result.item_id for result in query_request]
        query_request = Size.query.filter(Size.main_code == maincode).filter(or_(Size.B_0 == size_values["v1"], Size.B_1 == size_values["v2"], Size.B_2 == size_values["v3"], Size.B_3 == size_values["v4"])).limit(10)
        rs += [result.item_id for result in query_request]
        query_request = Size.query.filter(Size.main_code == maincode).filter(or_(Size.C_0 == size_values["v1"], Size.C_1 == size_values["v2"], Size.C_2 == size_values["v3"], Size.C_3 == size_values["v4"])).limit(10)
        rs += [result.item_id for result in query_request]
        query_request = Size.query.filter(Size.main_code == maincode).filter(or_(Size.D_0 == size_values["v1"], Size.D_1 == size_values["v2"], Size.D_2 == size_values["v3"], Size.D_3 == size_values["v4"])).limit(10)
        rs += [result.item_id for result in query_request]
        query_request = Size.query.filter(Size.main_code == maincode).filter(or_(Size.E_0 == size_values["v1"], Size.E_1 == size_values["v2"], Size.E_2 == size_values["v3"], Size.E_3 == size_values["v4"])).limit(10)
        rs += [result.item_id for result in query_request]
        query_request = Size.query.filter(Size.main_code == maincode).filter(or_(Size.F_0 == size_values["v1"], Size.F_1 == size_values["v2"], Size.D_2 == size_values["v3"], Size.D_3 == size_values["v4"])).limit(10)
        rs += [result.item_id for result in query_request]
        query_request = Size.query.filter(Size.main_code == maincode).filter(or_(Size.G_0 == size_values["v1"], Size.G_1 == size_values["v2"], Size.D_2 == size_values["v3"], Size.D_3 == size_values["v4"])).limit(10)
        rs += [result.item_id for result in query_request]
    elif maincode == '003':
        query_request = Size.query.filter(Size.main_code == maincode).filter(Size.A_0.in_(size_values["v1"])).filter(Size.A_1.in_(size_values["v2"])).filter(Size.A_2.in_(size_values["v3"])).filter(Size.A_3.in_(size_values["v4"])).filter(Size.A_4.in_(size_values["v5"])).limit(5)
        rs = [result.item_id for result in query_request]
    elif maincode == '022':
        query_request = Size.query.filter(Size.main_code == maincode).filter(Size.A_0.in_(size_values["v1"])).filter(Size.A_1.in_(size_values["v2"])).filter(Size.A_2.in_(size_values["v3"])).limit(5)
        rs = [result.item_id for result in query_request]

프로젝트 회고

  • 옷의 색상 데이터의 경우 selenium을 통한 수집이 필요 했으나 selenium을 동작시켜 확인해보니 필요한 컴퓨팅 자원이 컸기에 수집하지 않기로 결정.
  • 프로젝트 초기에 전체 데이터 크롤링 시간을 예측하여 전체 프로젝트 스케쥴을 세웠는데, 생각보다 크롤링이 오래걸려 후반부 웹서비스 작업을 상대적으로 못하였다.
    어떤 일이 생길지 모르니 스케쥴 계획은 빡빡하게 세우는 게 필요할 듯.
  • 크롤링 속도가 낮아진다면 크롤러(scrapy)를 좀 더 사람처럼 세팅하고 해야겠다.
  • 무신사 스토어는 고객이 편리하게 쇼핑을 할 수 있도록 다양한 정보를 제공하고 있지만
    크롤링하는 입장에서 html 구조의 일관성이 살짝 부족했다.
  • SQL이 서비스의 데이터 흐름을 잘 반영하는 것만으로 서비스의 속도가 달라질 수 있을것 같다
  • git은 어렵다.

Reference

무신사닷컴(www.musinsa.com)
Icons made by dDara, Freepik, iconixar from www.flaticon.com

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published