개인 프로젝트 - 의류 검색기
프로젝트 기간 :
23.04.06 ~ 23.04.12
사용 언어 : python
사용 라이브러리 : pandas, numpy, sklearn, flask, selenium, tqdm, BeatifulSoup
프로젝트 멤버 :
원명재(본인)
GITHUB LINK : https://github.com/Thingjae9/PROJECT4
GitHub - Thingjae9/PROJECT4
Contribute to Thingjae9/PROJECT4 development by creating an account on GitHub.
github.com
진행한 업무 :
데이터 크롤링, 데이터 EDA, 모델 구현, 모델 WEB 서빙
사용한 데이터 :
무신사 스토어
온라인 패션 스토어. 우리가 사랑한 패션의 모든 것, 다 무신사랑 해.
www.musinsa.com
def musinsa_rank(category_num,page_num):
url = f"https://www.musinsa.com/ranking/best?period=now&age=ALL&mainCategory=00{category_num}&subCategory=&leafCategory=&price=&golf=false&kids=false&newProduct=false&exclusive=false&discount=false&soldOut=false&page={page_num}&viewType=small&priceMin=&priceMax="
response = requests.get(url)
html = bs(response.text, 'lxml')
musinsa_rank_df = rbnl(html)
return musinsa_rank_df
def rbnl(html):
musinsa_rank_df = pd.DataFrame()
#순위 뽑기
rank_html = html.select('#goodsRankList > li > p')
rank_no_list = []
for i in rank_html:
rank_no_list.append(i.string.strip())
musinsa_rank_df['순위'] = rank_no_list
#브랜드 이름 뽑기
brand_html = html.select('#goodsRankList > li > div.li_inner > div.article_info > p.item_title > a')
brand_list = []
for i in brand_html:
brand_list.append(i.string)
musinsa_rank_df['브랜드명']=brand_list
#링크와 의류명 뽑기
link_name_html = html.select('#goodsRankList > li > div.li_inner > div.article_info > p.list_info > a')
link_list = []
name_list = []
for i in link_name_html:
link_list.append(i['href'])
name_list.append(i['title'])
musinsa_rank_df['의류명']=name_list
musinsa_rank_df['링크']=link_list
#상세 페이지 크롤링
musinsa_rank_df2 = specific_info(link_list)
#데이터 프레임 옆으로 합치기
musinsa_rank_df = pd.concat([musinsa_rank_df, musinsa_rank_df2], axis=1)
return musinsa_rank_df
def specific_info(link_list):
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36'}
musinsa_rank_df = pd.DataFrame()
part_num_list=[]
sex_list=[]
view_list=[]
sales_list=[]
like_list=[]
for link in tqdm(link_list):
# print(link)
response_1=requests.get(link,headers=headers)
html_1=bs(response_1.text, 'lxml')
#품번 리스트 생성
part_num_html=html_1.select('#product_order_info > div.explan_product.product_info_section > ul > li:nth-child(1) > p.product_article_contents > strong')
part_num=part_num_html[0].get_text().split('/')[-1].strip()
part_num_list.append(part_num)
#성별 리스트 생성
sex_html=html_1.select("#product_order_info > div.explan_product.product_info_section > ul > li > p.product_article_contents > span.txt_gender")
sex=sex_html[0].get_text().replace('\n',' ').strip()
sex_list.append(sex)
#셀레니움으로 원하는 데이터 가져오기
driver = webdriver.Chrome('chromedriver.exe')
driver.get(link)
sel_html=driver.page_source
html_2=bs(sel_html)
#조회수 가져오기
view_html=html_2.find_all("strong", {"id":"pageview_1m"})
view=view_html[0].get_text()
view_list.append(view)
#누적 판매 가져오기
sales_html=html_2.find_all("strong", {"id":"sales_1y_qty"})
sales=sales_html[0].get_text()
sales_list.append(sales)
#좋아요 수 가져오기
like_html=html_2.find_all("span", {"class": "prd_like_cnt"})
like=like_html[0].get_text()
like_list.append(like)
#드라이버 닫아주기
driver.close()
#시간 추가
time.sleep(0.01)
musinsa_rank_df['품번']=part_num_list
musinsa_rank_df['성별']=sex_list
musinsa_rank_df['조회수']=view_list
musinsa_rank_df['누적판매량(1년)']=sales_list
musinsa_rank_df['좋아요']=like_list
return musinsa_rank_df
for a in [1, 2, 3, 4, 5]:
for b in [2, 3, 4, 5]:
category_num=a
page_num=b
final_df=musinsa_rank(category_num,page_num)
file_name = f"musinsa_ranking_category{category_num}_page{page_num}.csv"
final_df.to_csv(file_name, index=False)
pd.read_csv(file_name)
데이터 크롤링 : 각 카테고리(상의, 하의, 아우터, 신발, 가방) 종류마다 탑 5 페이지(450등까지)의 정보 크롤링
프로젝트 배경 :
코로나 이후 많은 사람들이 온라인 매장에 관심을 갖기 시작했고, 사이트들은 옷의 종류는 많지만 원하는 것을 검색했을 때 원하는 제품을 바로 얻어내지 못하고, 이는 구매에 어려움으로 이어질 수 있음.
프로젝트 목표 :
1. 검색어를 통한 의류 추천 웹 사이트 구현
프로젝트 결과 :
파이프라인.
추천 알고리즘 웹 구현(Flask)
@app.route('/')
def home():
global df
df = pd.read_csv('clean.csv')
return render_template('index.html')
@app.route('/', methods=['POST'])
def get_recommendation():
global df
gender = request.form['gender']
category = request.form['category']
keyword = request.form['keyword']
# 이제 추천 로직을 수행합니다.
# 결과는 HTML 문자열로 생성합니다.
# 카테고리에 따른 필터링
if category == '상의':
filtered_df = df[df['category'].isin(['상의'])]
df = filtered_df.drop(['category'], axis=1)
elif category == '하의':
filtered_df = df[df['category'].isin(['하의'])]
df = filtered_df.drop(['category'], axis=1)
elif category == '아우터':
filtered_df = df[df['category'].isin(['아우터'])]
df = filtered_df.drop(['category'], axis=1)
elif category == '가방':
filtered_df = df[df['category'].isin(['가방'])]
df = filtered_df.drop(['category'], axis=1)
elif category == '신발':
filtered_df = df[df['category'].isin(['신발'])]
df = filtered_df.drop(['category'], axis=1)
else: df = df
if gender == '남':
filtered_df = df[df['gender'].isin(['남', '남 여'])]
elif gender == '여':
filtered_df = df[df['gender'].isin(['여', '남 여'])]
else:
filtered_df = df
model = TfidfVectorizer()
tfidf_vectors = model.fit_transform(filtered_df['name'])
keyword_vector = model.transform([keyword])
cosine_similarities = cosine_similarity(keyword_vector, tfidf_vectors)
results = cosine_similarities[0].argsort()[:-4:-1]
recommended_products = filtered_df.iloc[results]
reco_brand = recommended_products['brand']
recommended_products = recommended_products['name']
result = '<h1>당신을 위한 추천 아이템</h1>'
result += '<p>Gender : {}</p>'.format(gender)
result += '<p>Category : {}</p>'.format(category)
result += '<p>Keyword : {}</p>'.format(keyword)
result += '<h1>1위 브랜드 : {}</h1>'.format(reco_brand.iloc[0])
result += '<p>추천 아이템 1위 : {}</p>'.format(recommended_products.iloc[0])
result += '<p>추천 아이템 2위 : {}</p>'.format(recommended_products.iloc[1])
result += '<p>추천 아이템 3위 : {}</p>'.format(recommended_products.iloc[2])
# 추천 결과를 반환합니다.
return result
코사인유사도 :
검색 키워드를 코사인 유사도를 통해 데이터에 있는 가장 가까운 데이터에서 순위가 높은 3개 출력
DashBoard 구현(Flask)
@app.route('/dashboard')
def dashboard():
# 데이터 로드
df1 = pd.read_csv('final.csv')
group_brand = df1.groupby('브랜드명')['누적판매량(1년)']
brand_list = []
for row in df1['브랜드명']:
brand_list.append(row)
sales_list = []
for amount in df1['누적판매량(1년)']:
sales_list.append(amount)
# 대시보드 출력
return render_template('brand_for_sales.html')
@app.route('/dashboard2')
def dashboard2():
return render_template('brand_for_gender.html')
@app.route('/dashboard3')
def dashboard3():
return render_template('brand_for_total.html')
모델 서빙 결과 및 대시보드 설명 영상 :
한계점 및 개선 가능 사항 :
한계점.
1.검색어를 통해 브랜드 및 상품을 추천하기 때문에 검색기의 경우만 다르고 실제 출력 결과는 비슷할 수 있음.
개선 가능 사항.
1. dashboard 구현 방식 변경
2. 웹사이트 배포, 디자인 변경