아래 내용은 다음 notebook을 참고하여, 공부한 내용 입니다.

https://nbviewer.jupyter.org/gist/hyeshik/cf9f3d7686e07eedbfda?revision=6

 

Jupyter Notebook Viewer

시뮬레이션 결과, 어느 정도는 인구와 커버리지 차이로 설명이 되는 걸 확인할 수 있다. Pearson's correlation으로 시뮬레이션과 실제 지수가 0.25 정도 나오니까, 매장 수가 많고 적음만 가지고도 버거지수 차이가 어느 정도는 나타난다고 볼 수 있겠다. 한편, 브랜드 별로 매장이 살아남을 수 있는 위치 자체가 많거나 적을 수가 있고, 매장 운영 형태 (롯데리아는 주로 가맹점 운영, 버거킹은 주로 직영점 운영)에 따라 나타나는 것일 수도 있어

nbviewer.jupyter.org

import requests 		#python에서 http 요청을 보내는 모듈
import urllib.request 		#http 요청 기능을 담은 모듈
import pandas as pd 		#데이터 분석을 위한 라이브러리
import bs4			#웹크롤링을 위한 bs4 라이브러리
import time 			#time 관련 모듈
from itertools import count 	#반복을 통해 데이터를 조작할 때 사용
MCD_URL = 'http://www.mcdonalds.co.kr/www/kor/findus/district.do?sSearch_yn=Y&skey=2&pageIndex={page}&skeyword={location}'
  • 맥도날드 주소를 변수에 저장 합니다.

  • 지역별로 검색하여 모든 페이지의 정보를 가져올 것이므로 page와 location을 변수로 지정합니다.

def get_mcd_address_one_page(location, page): #한 페이지에 있는 맥도날드 주소 받아 오기
    response = urllib.request.urlopen(
MCD_URL.format(
location=urllib.parse.quote(location.encode('utf-8')), page = page)
) 
  • MCD_URL 변수에 {page}와 {location}을 넣기 위해 format 함수를 활용합니다.

  • urllib.request.urlopen는 웹 서버에 정보를 요청한 후, 돌려받은 응답을 저장하여 ‘응답 객체’(httpresepone)를 반환합니다.

  • urllib.parse,quote는 한글 텍스트를 퍼센트 인코딩으로 변환합니다.

  • location.encode('utf-8')는 location에 입력된 한글 텍스트를 'utf-8'의 형태로 인코딩 합니다. 

    (한글 텍스트를 바로 '퍼센트인코딩'을 해도 문제 없을거 같다는 생각에 이부분을 location으로만 해서

    해본 결과 오류가 없었습니다.)

 

*퍼센트 인코딩(percent encoding):

- URL에 사용할 수 있는 문자는 영문자, 숫자, 몇몇 기호뿐이다. 그래서 우리는 아스키코드가 아닌 문자들을 퍼센트 인코딩이라는 형식으로 바꾸어야 한다.

 

mcd_data = response.read().decode('utf-8')
  • urllib.request.urlopen('URL').read().decode('utf-8')을 실행하면 웹 요청을 보냅니다.

  • 쉽게 말해, 웹 문서 html 소스를 요청합니다.

 

*웹 요청과정:

- urlopen()으로 반환한 응답객체를 read()메소드를 실행해 웹서버가 응답한 데이터 바이트 배열로 읽습니다.

- 읽어들인 바이트 배열을 decode('utf-8') 메소드를 실행해 문자열로 변환합니다.(utf-8은 decode의 기본인자 이므로 생략 가능합니다.)

soup = bs4.BeautifulSoup(mcd_data)
#mcd_data에 불러온 html소스를 BeautifulSoup을 사용할 수 있게 soup에 저장
ret = []
#반환할 빈 배열 생성
for storetag in soup.findAll('dl', attrs={'class': 'clearFix'}):
    storename = storetag.findAll('a')[0].contents[-1].strip()
    storeaddr = storetag.findAll('dd', attrs={'class': 'road'})[0].contents[0].split(']')[1]
    storeaddr_district = storeaddr.split()[:2]
    ret.append([storename] + storeaddr_district)
  • bs4를 통해 soup에서 dl태그 중 클래스가 'clearFix'인 것들을 storetag에 넣습니다. 

  • storetag 중 모든 a태그의 내용을 앞뒤 공백을 지우고 storename에 저장합니다.

  • storetag 중 모든 dd태그의 클래스가 'road'인 부분의 내용을 ']' 로 나누어 stareaddr에 저장합니다. 

  • storeaddr의 ‘시’부분 까지만 storeaddr_district에 저장합니다.

  • ret배열에 [storename] [storeaddr_district]를 추가합니다.

return pd.DataFrame(ret, columns=('store', 'd1', 'd2')) if ret else None
  • 행이 store/d1/d2인 배열을 ret을 이용해 만듭니다.(ret이 비어있으면 none을 반환합니다.)

def search_mcdonalds_stores(location):
    found = []
  • 입력된 location에 있는 맥도날드의 수를 찾는 함수입니다.

  • 찾은 값을 넣을 found 배열을 생성합니다.

for pg in count():
    foundinpage = get_mcd_address_one_page(location, pg+1)
    if foundinpage is None:
        break
    found.append(foundinpage)
  • count()를 통해 수를 0부터 1씩 증가 시키면서 pg에 넣는 반복문입니다.

  • get_mcd_address_one_page 함수에 location과 page를 입력하여 찾은 값들을 foundinpage 변수에 저장합니다. 

  • 만약에 foundinpage가 none이면(페이지가 없거나 검색결과가 없으면) for문 종료합니다.

  • found 배열에 위에서 찾은 해당 페이지의 정보 저장 후 for문을 통해 다음페이지로 이동합니다.

return pd.concat(found)
#for문이 종료되면 found 배열을 연결 한 값을 반환한다
found = []
for distr in nameOfDo:
    print("진행중",distr)
    found.append(search_mcdonalds_stores(distr))
  • 모든 도와 광역시를 하나씩 distr에 입력합니다.

  • 어느부분이 진행중인지 확인합니다.

  • search_mcdonalds_stores에 팔도와 광역시를 넣어서 찾은 값들을 found에 넣습니다.

전체적인 코드

import requests
import urllib.request
import pandas as pd
import numpy as np
import bs4
import json
import time

from itertools import count

MCD_URL = 'http://www.mcdonalds.co.kr/www/kor/findus/district.do?sSearch_yn=Y&skey=2&pageIndex={page}&skeyword={location}'
name_of_distr = ['경기도','서울특별시','인천광역시','경상남도','강원도','충청남도','대전광역시','충청북도','부산광역시','울산광역시','대구광역시','경상북도','전라남도','광주광역시','전라북도','제주특별자치도']

def get_mcd_address_one_page(location, page):
    response = urllib.request.urlopen(MCD_URL.format(location=urllib.parse.quote(location), page = page))
    mcd_data = response.read().decode('utf-8')
    soup = bs4.BeautifulSoup(mcd_data)
    ret = []
    for storetag in soup.findAll('dl', attrs={'class': 'clearFix'}):
        storename = storetag.findAll('a')[0].contents[-1].strip()
        storeaddr = storetag.findAll('dd', attrs={'class': 'road'})[0].contents[0].split(']')[1]
        storeaddr_district = storeaddr.split()[:2]
        ret.append([storename] + storeaddr_district)

    return pd.DataFrame(ret, columns=('store', 'd1', 'd2')) if ret else None

def search_mcdonalds_stores(location):
    found = []
        
    for pg in count():
        foundinpage = get_mcd_address_one_page(location, pg+1)
        if foundinpage is None:
            break
        found.append(foundinpage)
    
    return pd.concat(found)

found = []
for distr in name_of_distr:
    print("진행중",distr)
    found.append(search_mcdonalds_stores(distr))
mcd_tbl = pd.concat(found)
mcd_tbl['store'].value_counts().head()

+ Recent posts