Comparison analysis (Starbucks vs Ediya)

J·2024년 8월 28일

스타벅스 데이터 수집

필요 모듈 호출

import time
import pandas as pd
import numpy as np
from selenium import webdriver
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
from tqdm import tqdm_notebook

1. 페이지 접근

from selenium import webdriver

#스타벅스 페이지 접근
url='https://www.starbucks.co.kr/store/store_map.do?disp=locale'
driver=webdriver.Chrome()
driver.get(url)

2.지역 선택

search_area = driver.find_element(By.CSS_SELECTOR, '#container > div > form > fieldset > div > section > article.find_store_cont > article > header.loca_search > h3 > a')
search_area.click()

3.서울시 선택

 choose_area = driver.find_element(By.CSS_SELECTOR, '#container > div > form > fieldset > div > section > article.find_store_cont > article > article:nth-child(4) > div.loca_step1 > div.loca_step1_cont > ul > li:nth-child(1) > a')

choose_area.click()

4.서울시의 구 전체 지역 선택

all_gu = driver.find_element(By.CSS_SELECTOR, '#mCSB_2_container > ul > li:nth-child(1) > a')
all_gu.click()

5.BeautifulSoup 이용해서 html 읽어오기

html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
  • 매장 정보 태그 확인 및 접근
store_list_raw = soup.select_one('ul.quickSearchResultBoxSidoGugun')
store_list = store_list_raw.select('li.quickResultLstCon')

확인

store_list[0].text

split 하기에 불편하니, 태그로 접근

  • 주소 Tag
store_list[123].select_one('p').text

store_list[123].select_one('p').text[:-9]

  • 매장명 Tag
store_list[123].select_one('strong').text

store_list[123].select_one('strong').text[:-2]

  • 구 이름 확인
store_list[123].select_one('p').text.split()[1]

6.DataFrame 만들기

정보 긁어오기

address_list = [] # 주소 
name_list = []    # 이름 
gu_list = []      # 구 
lat = []
lng = []

for i in range(len(store_list)):

    name_list.append(store_list[i].select_one('strong').text[:-2])
    address_list.append(store_list[i].select_one('p').text[:-9])
    gu_list.append(store_list[i].select_one('p').text.split()[1])
    lat.append(store_list[i]['data-lat'])
    lng.append(store_list[i]['data-long'])

데이터 프레임

starbucks = pd.DataFrame(
    {
        '매장명':name_list,
        '주소':address_list,
        '구':gu_list,
        '브랜드':'스타벅스',
        '위도':lat,
        '경도':lng
    }
)

켜져있는 셀레니움 종료

driver.quit()

이디야 데이터 수집

1. 페이지 접근

#이디야 페이지 접근
url='https://www.ediya.com/contents/find_store.html'
driver=webdriver.Chrome()
driver.get(url)

2. 매장 목록 접근

  • ediya의 경우 스타벅스와 다르게 직접 검색을 해야한다. 따라서 스타벅스에서 찾은 구를 가져온다.
#구 목록 만들기
gu_array = starbucks['구'].unique()
gu_array

주소 버튼 클릭

address_button = driver.find_element(By.CSS_SELECTOR, '#contentWrap > div.contents > div > div.store_search_pop > ul > li:nth-child(2) > a')
address_button.click()

검색 창, 검색 버튼 접근

search_bar = driver.find_element(By.CSS_SELECTOR, '#keyword')
search_button = driver.find_element(By.CSS_SELECTOR, '#keyword_div > form > button')

3.데이터 가져오기

  • 웹페이지 확인결과, 매장명은 'dt'태그 안에, 주소는 'dd'태그 안에 확인 가능
name_list = []
address_list = []
gu_list = []

for gu in tqdm_notebook(gu_array):
    #구 검색
    search_bar.send_keys(f'서울 {gu}')
    time.sleep(1)
    search_button.click()
    time.sleep(1)

    #BeautifulSoup사용 해 html 가져오기
    html = driver.page_source
    soup = BeautifulSoup(html, 'html.parser')
    #매장 정보에 접근
    place_list_raw = soup.select_one('ul#placesList')
    place_list = place_list_raw.select('.item')
    for place in place_list:
        #데이터 긁어오기
        name = place.select_one('dt').text
        address = place.select_one('dd').text
        name_list.append(name)
        address_list.append(address)
        gu_list.append(gu)
    #검색창 초기화
    search_bar.clear()

4.데이터 프레임 만들기

ediya = pd.DataFrame(
    {
        '매장명':name_list,
        '주소':address_list,
        '구':gu_list,
        '브랜드':'이디야',
        '위도':np.nan,
        '경도':np.nan
    }
)

5. Google Maps API사용하여 (위도,경도 얻기)

  • Google Maps API를 이용해서 위도와 경도정도 가져오기
  • 주소중 완벽하지 않은 주소 확인 및 네이버 지도에서 정확한 주소 확인 후 직접 입력
count=0
for idx, row in ediya.iterrows():

    a = row['주소'].split()[:4]
    if len(a) == 3:
        count += 1
        print(idx, row['매장명'], a)
print(count)

changeDict = { 
    0:'서울 강남구 봉은사로37길 29',
    13:'서울 강남구 언주로148길 14',
    25:'서울 강남구 논현로167길 16',
    146:'서울 광진구 강변역로4길 34',
    175:'서울 금천구 시흥대로 198',
    202:'서울 노원구 월계로45길 37',
    293:'서울 서대문구 통일로 203-1',
    297:'서울 서대문구 통일로 369',
    300:'서울 서대문구 통일로 141',
    310:'서울 서대문구 통일로 431',
    316:'서울 서초구 효령로60길 15',
    322:'서울 서초구 효령로40길 4',
    324:'서울 서초구 서초중앙로 89',
    326:'서울 서초구 반포대로21길 23',
    337:'서울 서초구 청계산로 189',
    506:'서울 종로구 삼일대로 436-1',
    515:'서울 종로구 홍지문2길 6',
    524:'서울 종로구 삼봉로 81',
    531:'서울 종로구 수표로 109-1'
}

키 값을호 해당 index로 잡고 바꿔줄 주소를 값으로 하는 공간 생성

for key in changeDict.keys():
    ediya['주소'][key] = changeDict[key]

다시 확인

count=0
for idx, row in ediya.iterrows():

    a = row['주소'].split()[:4]
    if len(a) == 3:
        count += 1
        print(idx, row['매장명'], a)
print(count)

진짜 위도 경도 추가

import googlemaps
import folium
import pandas as pd
import json
from tqdm import tqdm_notebook

gmaps_key = '할당받은 개인 키'
gmaps = googlemaps.Client(key=gmaps_key)
    # 위도, 경도 채우기
    for idx, row in tqdm_notebook(ediya.iterrows()):

        address = row['주소'].split()[:4]
        print(' '.join(address))
        tmp = gmaps.geocode(' '.join(address), language='ko')

        lat = tmp[0]['geometry']['location']['lat']
        lng = tmp[0]['geometry']['location']['lng']

        ediya['위도'][idx], ediya['경도'][idx] = lat, lng

확인

데이터 시각화

-folium 사용하여 지도에 표시

import json
import folium
import warnings
warnings.simplefilter(action='ignore', category='FutureWarning')

1.이디야 매장 지도 표시 (연한 파랑)

geo_path = './skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))

my_map = folium.Map(location=[37.5502, 126.982], zoom_start=12, tiles='CartoDB positron')

for idx, rows in ediyaAdded.iterrows():
    latitude = rows['위도']
    longitude = rows['경도']

    if latitude is not None and longitude is not None:
        folium.CircleMarker(
            location=[rows['위도'], rows['경도']],
            radius=1,
            color='lightblue'
        ).add_to(my_map)

my_map

2.스타벅스 매장 지도 표시 (진한 초록)

my_map_2 = folium.Map(location=[37.5502, 126.982], zoom_start=12, tiles='CartoDB positron')

for idx, rows in df_added.iterrows():
    latitude = rows['위도']
    longitude = rows['경도']

    if latitude is not None and longitude is not None:
        folium.CircleMarker(
            location=[rows['위도'], rows['경도']],
            radius=1,
            color='green'
        ).add_to(my_map_2)

my_map_2

3.매장 한번에 지도에 표시 (이디야(빨강), 스타벅스(초록))

my_map_3 = folium.Map(location=[37.5502, 126.982], zoom_start=12, tiles='CartoDB positron')

# 이디야
for idx, rows in ediyaAdded.iterrows():
    latitude = rows['위도']
    longitude = rows['경도']

    if latitude is not None and longitude is not None:
        folium.CircleMarker(
            location=[rows['위도'], rows['경도']],
            radius=1,
            color='red',
            legend_name='이디야'
        ).add_to(my_map_3)

# 스타벅스
for idx, rows in df_added.iterrows():
    latitude = rows['위도']
    longitude = rows['경도']

    if latitude is not None and longitude is not None:
        folium.CircleMarker(
            location=[rows['위도'], rows['경도']],
            radius=1,
            color='green',
            legend_name='스타벅스'
        ).add_to(my_map_3)

my_map_3

해석

  • 이디야는 특정이나 상권에 몰려있기보단 전 지역에 골고루 포진되어있다
  • 스타벅스는 3대 상업지구(종로,여의도,강남) 및 관광지(홍대,명동)에 밀집되어 있고 그 외 지역은 주요상권에만 매장이 있다.

문제 : 이디야는 스타벅스 옆에 매장을 만드는가?

  • 몇몇 지역에서는 그렇다고 말할수 있다,
    하지만 전반적으로 이디야는 스타벅스가 없는 곳에도 많은 매장이 분포되어있다.
    메인 상권이 있는 곳은 사람이 많이 몰리고 지출이 많은 곳이기에 스타벅스,이디야 뿐만 아니라 다른 체인들도 위치한다.
profile
Full of adventure

0개의 댓글