지도 시각화를 해본 적이 없어 라이브러리도 익힐겸, API도 사용해볼겸 진행해보았다.
준비물은 다음과 같다.
- Jupyter Notebook
- 네이버 API 사용자 인증
1. 먼저 서브웨이 체인점들의 주소를 크롤링 해온다. 주소는 네이버에 검색해서 크롤링해오는 방법도 있지만, 서브웨이 홈페이지에서 직접 가져왔다.
보면 2019년 6월 현재 350개의 매장이 존재하며 매장명과 매장주소를 같이 제공하고 있다. 페이지가 넘어가며 url이 바뀌는 편한 구조이기 때문에 크롤링은 쉽다. 머리를 잘 써서 page_number를 지정해주지 않아도 알아서 크롤링 해오게 할 수 있지만 무난하게 페이지를 지정해주었다.
def make_subway_list():
url = 'http://subway.co.kr/storeSearch?page='
page_num = 1
subway_list = []
for j in range(1,36):
sourcecode = urllib.request.urlopen(url+str(j)).read()
soup = BeautifulSoup(sourcecode, 'html.parser')
for i in soup.find_all('div','title'):
temp_text = i.get_text()
temp_text = temp_text.replace('\xa0','')
subway_list.append(temp_text)
return subway_list
또한 가져오는 도중 '\xa0'라는 값이 가져와 주소가 제대로 저장되지 않는 경우가 있어 이를 중간에 제거할 수 있도록 해주었다.
2. 가져온 주소를 네이버 API를 이용해 위경도로 바꾼다. AI-Application Service로 다량의 호출을 무료로 이용할 수 있다.
사용한 서비스는 places - Geocoding로 주소의 텍스트를 입력받으면 좌표를 포함한 상세정보를 제공해주는 API이다. JSON으로 돌아오기 때문에 아래와 같은 형식으로 돌아온다.
{
"status": "OK",
"meta": {
"totalCount": 1,
"page": 1,
"count": 1
},
"addresses": [
{
"roadAddress": "경상남도 거제시 연초면 효촌1길 10-1",
"jibunAddress": "경상남도 거제시 연초면 연사리 93",
"englishAddress": "10-1, Hyochon 1-gil, Yeoncho-myeon, Geoje-si, Gyeongsangnam-do, Republic of Korea",
"addressElements": [
{
"types": ["SIDO"],
"longName": "경상남도",
"shortName": "경상남도",
"code": ""
},
{
"types": ["SIGUGUN"],
"longName": "거제시",
"shortName": "거제시",
"code": ""
},
{
"types": ["DONGMYUN"],
"longName": "연초면",
"shortName": "연초면",
"code": ""
},
{
"types": ["RI"],
"longName": "연사리",
"shortName": "연사리",
"code": ""
},
{
"types": ["ROAD_NAME"],
"longName": "효촌1길",
"shortName": "효촌1길",
"code": ""
},
{
"types": ["BUILDING_NUMBER"],
"longName": "10-1",
"shortName": "10-1",
"code": ""
},
{
"types": ["BUILDING_NAME"],
"longName": "",
"shortName": "",
"code": ""
},
{
"types": ["LAND_NUMBER"],
"longName": "93",
"shortName": "93",
"code": ""
},
{
"types": ["POSTAL_CODE"],
"longName": "53209",
"shortName": "53209",
"code": ""
}
],
"x": "128.6521583",
"y": "34.9070498",
"distance": 0
}
],
"errorMessage": ""
}
몇 번의 수정을 거치면 원하는 x, y 좌표값만을 저장할 수 있다.
def search_map(search_text):
client_id = 'id'
client_secret = 'secret'
encText = urllib.parse.quote(search_text)
url = 'https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?query='+encText
request = urllib.request.Request(url)
request.add_header('X-NCP-APIGW-API-KEY-ID',client_id)
request.add_header('X-NCP-APIGW-API-KEY',client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if(rescode==200):
response_body = response.read()
# print(response_body.decode('utf-8'))
return response_body.decode('utf-8')
else:
print("Error Code:" + rescode)
header에 client_id, client_secret를 넣어 요청하기 때문에 꼭 인증키를 받아야 한다.
3. 받은 x,y 좌표를 주소별로 저장하여 리스트로 만든다.
def make_location(subway_list):
x = []
y = []
for subway_location in subway_list:
temp_map = search_map(subway_location)
temp_map = json.loads(temp_map)
try:
temp_map = temp_map['addresses'][0]
x.append(float(temp_map['x']))
y.append(float(temp_map['y']))
except IndexError:
pass
return x, y
x, y를 따로 저장하여 넣어주었다. 또한 서브웨이 홈페이지에서 주소가 잘못된 매장이 몇 개 있는데 이를 배제하기 위하여 try/except를 처리해주었다. 실제로 한 건을 처리해보면 다음과 같이 나타난다.
4. 이제 지도를 띄우고 마커를 추가해준다. 지도와 마커는 folium 라이브러리를 사용하여 다음과 같은 방식으로 띄운다.
map_osm = folium.Map(location=[37.4729081, 127.039306])
folium.Marker([37.4729081, 127.039306]).add_to(map_osm)
map_osm
여러개의 마커는 여러번 추가해주면 된다.
def make_marker(map_osm, x, y):
for i in range(len(x)):
folium.Marker([y[i], x[i]]).add_to(map_osm)
5. 강원도에는 서브웨이가 하나도 없는걸로 나타나는데 정말 없을까? 확인해본다.
서브웨이 미용실이 있다.
make_marker(map_osm, x, y)
map_osm
map_osm.save('save.html')
저장하여 나중에도 써먹도록 하자.
'Python > Crawler' 카테고리의 다른 글
네이버 실시간 검색어 크롤링 코드 (0) | 2019.08.27 |
---|---|
Beautiful Soup Documentation (0) | 2019.06.19 |
우리 지역의 성범죄자는 몇 명이나 될까? (1) - python을 이용한 크롤링, 시각화 (0) | 2019.04.29 |
네이버 블로그를 크롤링하여 단어 빈도 분석하기 (0) | 2019.04.03 |
Python과 Google API를 이용하여 인스타그램 크롤링 이후 이미지를 분석해보기 (0) | 2019.03.19 |