파이썬을 이용한 크롤링 연습 2


⛏크롤링 2


스타벅스 지역별 매장정보 가져오기

  • 각 지역의 스타벅스 지역별 매장들의 정보를 가져와 리스트화해서 json파일로 만들어보자.

  • starbucks 폴더 생성

  • starbucks01.py 생성

    • 인코딩

      • # -*- coding:utf-8 -*-
        
    • 모듈 호출

      • import requests
        import json
        

시도 선택

  • [스타벅스 홈페이지] - [스토어] - [매장 찾기] - [지역 검색]

  • 개발자 도구로 서울 선택해서 자바스크립트 위치 찾기

    • 지역 검색을 눌러 개발자 도구에 들어가보자 [F12]
      • image
    • 파이어폭스를 이용하면 해당 기능을 하는 자바스크립트의 위치를 알려준다. 기타 브라우저를 사용하면 노가다를 해야한다.(직접 찾아야함 하나하나….)
      • image
      • [개발자 도구] - [소스] - [common] - [js] - [store] - [store_core.js?v=~~~~]
  • 시도 선택창을 요청하는 코드 찾기(1246번째 줄)

    • image

    • __ajaxCall("/store/getSidoList.do", {}, true, "json", "post",
      					function (_response){...}
      
    • (url, 보내는 데이터, async, 받는 데이터 형식, 전송 방식(method), success function) 인걸로 추정

    • 따라서, 응답 받은 데이터가지고 만들었다고 추론 가능

    • _(언더바) 1개나 2개를 쓰면 이 내부에서만 사용하겠다는 의미다.

    • 비동기 통신을 직접 만들어 놓은 것 같음.
  • starbucks01.py에 내용 작성

    • def getSiDo():
          # End Point : starbucks.co.kr / service url : /store/getSidoList.do
          url = "https://www.starbucks.co.kr/store/getSidoList.do"
          resp = requests.post(url)
          # resp를 json형태로 바꿔 'list'객체 가져옴
          sido_list = resp.json()['list']
              
          sido_cd = list(map(lambda x : x['sido_cd'], sido_list))
          sido_nm = list(map(lambda x : x['sido_nm'], sido_list))
          
          sido_dict = dict(zip(sido_cd, sido_nm))
          
          return sido_dict
      
    • if __name__ == '__main__':
          print(getSiDo())
      

구군 선택

  • 시도 선택 후 구군 선택창을 요청하는 코드 찾기(1302번째 줄)

    • image

    • image

  • starbucks01.py에 내용 작성

    • 방식은 시도를 선택할 때와 같으나, 아까 받은 시도코드를 data로 같이 보내줘야 한다.

    • def getGuGun(sido_cd):
          # __ajaxCall("/store/getGugunList.do", {"sido_cd":sido}, true, "json", "post", function (_response){...}
          url = 'https://www.starbucks.co.kr/store/getGugunList.do'
          # data도 같이 보내줘야함("sido_cd")
          resp = requests.post(url, data={"sido_cd": sido_cd})
          gugun_list = resp.json()['list']
          
          gugun_cd = list(map(lambda x : x['gugun_cd'], gugun_list))
          gugun_nm = list(map(lambda x : x['gugun_nm'], gugun_list))
          
          gugun_dict = dict(zip(gugun_cd, gugun_nm))
          
          return gugun_dict
      
    • if __name__ == '__main__':
          print(getSiDo())
          sido = input('도시 코드를 입력해 주세요 : ')
          if sido == '17':
              pass
          else:
              print(getGuGun(sido))
      
    • 세종시는 구군이 없어 바로 검색하기 때문에 if문으로 store를 검색할 여지를 만들어 둔다.

매장 선택

  • 매장 정보 보내주는 코드 찾기(586번째 줄)

    • image

    • getStore.do 라고 요청할 때 같이 보내지는 데이터들을 확인

      • image
      • 군구 선택 전에 개발자도구를 켜 네트워크창을 띄워주고 선택해주면, getStore~ 가 뜰 것이다. 그걸 선택에 페이로드에 들어가면 FormData에 요청시에 들어가는 데이터들이 나온다.
    • 매장 정보를 요청할 때 보낼 데이터로, 필요한 값빼고 다 지우기

      • ins_lat: 37.3653504
        ins_lng: 126.9399552
        p_sido_cd: 01
        p_gugun_cd: 0101
        in_biz_cd: 
        set_date: 
        
  • starbucks01.py에 내용 작성

    • 메인 함수

      • if __name__ == '__main__':
            # 시도 정보 갖고오기
            print(getSiDo())
            # 시도 코드를 입력받고
            sido = input('도시 코드를 입력해 주세요 : ')
            # 세종시면 바로 매장정보 가져오기
            if sido == '17':
                print(getStore(sido_cd='17', gugun_cd=''))
            # 세종시가 아니라면 구군코드를 입력하고 매장정보 가져오기
            else:
                print(getGuGun(sido))
                gugun = input('구군 코드를 입력해 주세요 : ')
                print(getStore(gugun_cd=gugun))
        
    • 매장 정보를 요청해준다.(위에서 골라낸 보낼 데이터도 함께 보내준다)

      • def getStore(sido_cd='', gugun_cd=''):
            url = 'https://www.starbucks.co.kr/store/getStore.do'
            resp = requests.post(url, data={'ins_lat': '37.3653504',
                                            'ins_lng': '126.9399552',
                                            'p_sido_cd': sido_cd,
                                            'p_gugun_cd': gugun_cd,
                                            'in_biz_cd': '',
                                            'set_date': ''})
            store_list = resp.json()['list']
        
    • 여기서 매장 하나의 데이터(서울시, 강남구의 첫번째 매장)를 보면 이러하다.

      • {'seq': 0, 'sido_cd': None, 'sido_nm': None, 'gugun_cd': None, 'gugun_nm': None, 'code_order': None, 'view_yn': None, 'store_num': None, 'sido': None, 'gugun': None, 'address': None, 'new_img_nm': None, 'p_pro_seq': 0, 'p_view_yn': None, 'p_sido_cd': '', 'p_gugun_cd': '', 'p_store_nm': None, 'p_theme_cd': None, 'p_wireless_yn': None, 'p_smoking_yn': None, 'p_book_yn': None, 'p_music_yn': None, 'p_terrace_yn': None, 'p_table_yn': None, 'p_takeout_yn': None, 'p_parking_yn': None, 'p_dollar_assent': None, 'p_card_recharge': None, 'p_subway_yn': None, 'stb_store_file_renew': None, 'stb_store_theme_renew': None, 'stb_store_time_renew': None, 'stb_store_lsm': None, 's_code': '1727', 's_name': '역삼이마트', 'tel': '1522-3232', 'fax': '02-554-4044', 'sido_code': '01', 'sido_name': '서울', 'gugun_code': '0101', 'gugun_name': '강남구', 'addr': '서울특별시 강남구 역삼동 755 한솔필리아', 'park_info': None, 'new_state': None, 'theme_state': 'T16@T20@T21@T30@T32@T34@@T36@T43@P40@P90', 'new_bool': 0, 'search_text': '', 'ins_lat': '', 'ins_lng': '', 'in_distance': 0, 'out_distance': '17.71', 'all_search_cnt': -1, 'addr_search_cnt': -1, 'store_search_cnt': -1, 'rowCount': 30, 'store_nm': '', 'store_cd': 0, 's_biz_code': '4043', 'new_icon': 'N', 'set_user': '', 'favorites': 0, 'map_desc': None, 'notice': None, 'defaultimage': '/upload/store/2021/12/[4043]_20211201044027_sla8h.jpg', 'etcimage': None, 'in_biz_cd': None, 'in_store_cd': None, 'in_favorites': None, 'in_user_id': None, 'in_biz_cds': 0, 'in_biz_arr': None, 'in_biz_arrdata': None, 'in_scodes': 0, 'in_scode_arr': None, 'in_scode_arrdata': None, 'disp': None, 'set_date': None, 'hlytag': None, 'hlytag_msg': None, 'vSal': '', 'istart': 1, 'iend': 60, 'open_dt': '20201127', 'gold_card': 0, 'ip_lat': '', 'ip_long': '', 'espresso': '', 'new_store': '', 'premiere_food': '', 'doro_address': '서울특별시 강남구 역삼로 310 (역삼동)', 'cold_blew': '', 'my_siren_order_store_yn': 'N', 'whcroad_yn': 'WHCROAD', 'skuNo': '', 'skuName': '', 'skuImgUrl': '', 'stock_count': 0, 'store_area_name': None, 'store_area_code': 'A01', 'is_open': None, 'gift_stock_yn': None, 'lat': '37.499367', 'lot': '127.048425', 't20': 0, 't04': 0, 't03': 0, 't01': 0, 't12': 0, 't09': 0, 't06': 0, 't10': 0, 'p10': 0, 'p50': 0, 'p20': 0, 'p60': 0, 'p30': 0, 'p70': 0, 'p40': 0, 'p80': 0, 't22': 0, 't21': 0, 'p90': 0, 't05': 0, 't30': 0, 't36': 0, 't27': 0, 't29': 0, 't43': 0, 't48': 0}
        
    • 여러 개의 데이터가 있는데, 매장명(s_name), 전화번호(tel), 도로명주소(doro_address), 위도(lat), 경도(lot)을 가져올 것이다.

      • # 빈 리스트를 하나 만들어 주고
        result_list = list()
        	# store_list를 반복해준다.
            for store in store_list:
                store_dict = dict() # 딕셔너리를 하나 생성해서
                store_dict['s_name'] = store['s_name'] # 키값 's_name'에 각 매장명을
                store_dict['tel'] = store['tel'] # 키값 'tel'에 각 전화번호를
                store_dict['doro_address'] = store['doro_address'] # 키값 'doro_address'에 각 도로명주소를
                store_dict['lat'] = store['lat'] # 키값 'lat'에 각 위도를
                store_dict['lot'] = store['lot'] # 키값 'lot'에 각 경도를 저장해주고
                result_list.append(store_dict) # result_list에 append 해준다.
        
    • print(result_list)를 해보면 다음과 같이 출력될 것이다.

      • [{'s_name': '역삼이마트', 'tel': '1522-3232', 'doro_address': '서울특별시 강남구 역삼로 310 (역삼동)', 'lat': '37.499367', 'lot': '127.048425'}, {'s_name': '삼성동', 'tel': '1522-3232', 'doro_address': '서울특별시 강남구 영동대로96길 12 (삼성동)', 'lat': '37.510843366121534', 'lot': '127.06363342044263'}, {'s_name': '강남논현', 'tel': '1522-3232', 'doro_address': '서울특별시 강남구 강남대로 512 (논현동)', ...]
        
    • 이제 받아준 리스트를 json형태로 만들기 위해 딕셔너리를 사용해 만들어보자.({'store_list': [{},{},{}]})

      • # 빈 딕셔너리형을 만들고
        result_dict = dict()
        # 딕셔너리의 'store_list'라는 키값에 result_list를 value로 넣어준다.
        result_dict['store_list'] = result_list
        
    • print(result_dict)로 확인해보면 다음과 같이 출력될 것이다.

      • {'store_list': [{'s_name': '역삼이마트', 'tel': '1522-3232', 'doro_address': '서울특별시 강남구 역삼로 310 (역삼동)', 'lat': '37.499367', 'lot': '127.048425'},...}]}
        
    • json 형태로 만들어 줬으니 json 파일로 만들어 보자.

      • # .dumps()를 이용해 json 객체를 만들어준다. 이때, 한글이 잘 나오도록 아스키코드로 바뀌는 것을 방지해준다.
        result_json = json.dumps(result_dict, ensure_ascii=False)
              
        # starbucks01.json이라는 파일을 만들어 result_json 내용을 적어준다.
        with open('starbucks01.json', 'w', encoding='utf-8') as f:
            f.write(result_json)
              
        # 그리고 result_json 객체 반환
        return result_json
        
      • image

      • image

      • 실행하면 이런식으로 json 파일이 생성되고 result_json 값이 반환된다.
  • 결론적으로, 실행하면 메인함수에 따라서 시도코드입력하고 그 시도에 맞는 구군코드를 적어주면 그 지역에 해당하는 요청한 정보에 맞는 데이터들이 json형태로 출력되고, 같은 폴더에 json 파일이 만들어 질 것이다.

스타벅스 전국 매장 정보 가져오기

  • 위 실습 코드를 활용해 이번에는 전국 매장의 정보들을 가져와 starbucks_all.json이라는 파일을 생성해보자.

  • starbucks02.py를 생성

  • 위 실습의 코드를 그대로 가져와서 붙여넣되 getStore()함수 부분에서 마지막 반환값을 result_list로 정해준다.

    • 모듈 호출

      • # -*- coding:utf-8 -*-
              
        import requests
        import json
        
    • 함수 정의

      • def getSiDo():
            # End Point : starbucks.co.kr / service url : /store/getSidoList.do
            url = "https://www.starbucks.co.kr/store/getSidoList.do"
            resp = requests.post(url)
            # resp를 json형태로 바꿔 'list'객체 가져옴
            sido_list = resp.json()['list']
              
            sido_cd = list(map(lambda x: x['sido_cd'], sido_list))
            sido_nm = list(map(lambda x: x['sido_nm'], sido_list))
              
            sido_dict = dict(zip(sido_cd, sido_nm))
              
            return sido_dict
              
              
        def getGuGun(sido_cd):
            # __ajaxCall("/store/getGugunList.do", {"sido_cd":sido}, true, "json", "post", function (_response){...}
            url = 'https://www.starbucks.co.kr/store/getGugunList.do'
            # data도 같이 보내줘야함("sido_cd")
            resp = requests.post(url, data={"sido_cd": sido_cd})
            gugun_list = resp.json()['list']
              
            gugun_cd = list(map(lambda x: x['gugun_cd'], gugun_list))
            gugun_nm = list(map(lambda x: x['gugun_nm'], gugun_list))
              
            gugun_dict = dict(zip(gugun_cd, gugun_nm))
              
            return gugun_dict
              
              
        def getStore(sido_cd='', gugun_cd=''):
            url = 'https://www.starbucks.co.kr/store/getStore.do'
            resp = requests.post(url, data={'ins_lat': '37.3653504',
                                            'ins_lng': '126.9399552',
                                            'p_sido_cd': sido_cd,
                                            'p_gugun_cd': gugun_cd,
                                            'in_biz_cd': '',
                                            'set_date': ''})
            store_list = resp.json()['list']
            # s_name, tel, doro_address, lat, lot
            result_list = list()
            for store in store_list:
                store_dict = dict()
                store_dict['s_name'] = store['s_name']
                store_dict['tel'] = store['tel']
                store_dict['doro_address'] = store['doro_address']
                store_dict['lat'] = store['lat']
                store_dict['lot'] = store['lot']
                result_list.append(store_dict)
              
            return result_list
        
  • 이제 함수들이 작동할 메인함수를 만들어줘야한다.

    • 원하는 형태는 {'list' : [{s_name:'',..},{},...]} 이런 형태다.

    • if __name__ == '__main__':
          # 전국의 모든 스타벅스 매장을 저장
          # {'list' : [{s_name:'',..},{},...]}
          # 파일이름 : starbucks_all.json
              
          # 빈 리스트 생성
          list_all = list()
          	
          # getSiDo()는 key(sido_cd)와 value(sido_nm)이 담긴 딕셔너리(sido_dict)
          sido_all = getSiDo()
          for sido in sido_all:
              # sido_cd가 17이면(세종시)
              if sido == '17':
                  # 바로 세종시에 있는 스타벅스 매장의 정보들을 가져와 result에 list형태로 저장
                  result = getStore(sido_cd=sido)
                  print(result)
                  # []를 풀어서 list_all에 추가
                  list_all.extend(result)
              else:
                  # 세종시를 제외한 시, 도라면 각 시도에 맞는 gugun_dict를 가져온다.
                  gugun_all = getGuGun(sido)
                  for gugun in gugun_all:
                      # 각 구와 군에 존재하는 스타벅스 매장의 정보들을 result에 저장
                      result = getStore(gugun_cd=gugun)
                      print(result)
                      # []를 풀어서 list_all에 추가
                      list_all.extend(result)
          
              
      	# 빈 딕셔너리 생성
          result_dict = dict()
          # 빈 딕셔너리의 'list'라는 key에 list_all(모든 매장의 정보(형태[{:}]))를 넣어준다.
          result_dict['list'] = list_all
          	
          # result_dict를 json 형태로 변환해서 result에 저장
          result = json.dumps(result_dict, ensure_ascii=False)
          	
          # result를 내용으로 한 json파일 생성
          with open('starbucks_all.json', 'w', encoding='utf-8') as f:
              f.write(result)
          
      
  • print(result)를 해보자.

    • {"list": [{"s_name": "역삼이마트", "tel": "1522-3232", "doro_address": "서울특별시 강남구 역삼로 310 (역삼동)", "lat": "37.499367", "lot": "127.048425"}, {"s_name": "삼성동", "tel": "1522-3232", "doro_address": "서울특별시 강남구 영동대로96길 12 (삼성동)", "lat": "37.510843366121534", "lot": "127.06363342044263"}, {"s_name": "강남논현", "tel": "1522-3232", "doro_address": "서울특별시 강남구 강남대로 512 (논현동)", "lat": "37.5078978596254", "lot": "127.023338614644"}, ..]}
      
    • 원하던 것 처럼 잘 출력된다!
  • starbucks_all.json을 확인해보자.

    • image

스타벅스 매장 지도에 표시하기

  • 위에서 구한 지역별 매장정보가 담긴 json 파일에서 정보를 가져와 folium을 사용해 지도에 매장의 위치를 표시해보자.

  • 참고 : https://github.com/python-visualization/folium

  • folium은 Open Street Maps과 같은 지도데이터에 Leaflet.js를 이용해 위치 정보를 시각화하는 파이썬의 라이브러리다. 위도와 경도를 사용하기 때문에 구글맵, 네이버지도 등도 사용할 수 있다.

  • 설치 : 터미널을 열어 pip install folium을 입력한다.

  • 모듈 호출

    • import folium
      import json
      

1. json파일을 읽어들이기

  • 위에서 서울시(01), 강남구(0101)의 매장 정보들을 가지고 있는 starbucks01.json파일을 읽어오자.

    with open('starbucks01.json', 'r', encoding='utf-8') as f:
        seoul_gangnam = json.load(f)
    
    • json파일을 읽어들일 때는 json.load()를 사용하면 된다.
  • print(seoul_gangnam) 으로 데이터를 확인해보자

    • {'store_list': [{'s_name': '역삼이마트', 'tel': '1522-3232', 'doro_address': '서울특별시 강남구 역삼로 310 (역삼동)', 'lat': '37.499367', 'lot': '127.048425'}, ... ]}
      

2. folium 라이브러리를 사용해 지도 만들기

  • 기준으로 삼고 싶은 위치의 위도, 경도를 가져와서 folium.Map(location=[위도,경도], zoom_start=)을 사용해 지도를 만들어 줄 수 있다.

  • zoom_start는 처음 지도를 그릴 때 확대, 축소 정도를 잡아줄 수 있다. 숫자가 클수록 확대, 작을 수록 축소된다.(디폴트 값은 10)

  • 매장 정보는 서울시 강남구에 있는 스타벅스 매장에 대한 정보이기 때문에, 기준 위치를 강남구청으로 잡을 것이다.

  • 강남구청의 주소는 구글지도에서 가져왔다.

    • image
  • 위도와 경도도 가져왔으니 강남구청을 기준 위치로두는 지도를 만들 수 있다.

    • gangnamgu_loc = folium.Map(location=[37.51728440687407, 127.04747565811068], zoom_start=14)
      

3. json파일에서 읽어온 위도, 경도를 가지고 스타벅스 매장의 마커를 만들어 지도에 추가하자.

  • folium 라이브러리로 지도를 만들었으면, folium.Marker(위도, 경도, popup=, max_width=)를 사용해서 마커를 만들 수 있고, add_to()를 사용해 만들어놓은 지도로 마커를 보낼 수 있다.

  • json파일로부터 가져온 정보를 담은 seoul_gangnam을 키값을 이용해 매장정보 리스트(value)를 다른 변수에 저장해주고, 반복문을 사용해 각 매장정보를 마커에 추가해줄 것이다.

    • stores = seoul_gangnam['store_list']
      for store in stores:
          folium.Marker([store['lat'], store['lot']], popup=folium.Popup(f"스타벅스 {store['s_name']}점", max_width=100)).add_to(
              gangnamgu_loc)
      
    • 매장 정보를 확인해봤듯이, 매장명(s_name), 전화번호(tel), 도로명 주소(doro_address), 위도(lat), 경도(lot)을 가지고 있다.

    • popup속성을 사용해 마커를 클릭하면 위치에 대한 정보를 나타내는 팝업창이 나오게 만들 수 있다. 팝업을 눌렀을때 스타벅스 매장명이 나오게 만들었다.

    • max_width는 최대 크기

    • 만든 마커들을 아까 만들어놓은 gangnamgu_loc지도로 반복적으로 보내준다.

4. 지도를 저장하자.

  • 마지막으로 만들어준 지도들을 저장하자. .save()메소드를 사용하면된다.

    • gangnamgu_loc.save('startbucks_gangnam.html')
      
    • image-20220210222225433
  • 브라우저로 확인해보자.

    • image
  • 마커를 눌러 팝업도 확인해보자.

    • image
  • CodePen을 사용해 만든 html을 가져와봤다. 결과를 확인해보자.

See the Pen hello by goodjeon (@goodjeon) on CodePen.

2022

[web]jQuery 복습 3

1 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]jQuery 복습 2

13 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]jQuery 복습 1

14 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]JavaScript 정리4

5 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]JavaScript 정리3

10 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]JavaScript 정리2

7 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]JavaScript 정리1

8 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]CSS 기초 정리

11 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[web]HTML 기초 정리

8 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

[Pandas]pandas 연습

3 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

맨 위로 이동 ↑

2021

[Python기초]module

1 분 소요

[Noitce] 고쳐야하거나 틀린 것이 있으면 말씀해주세요!

맨 위로 이동 ↑