본문 바로가기
AI/자연어처리

[생활속의 IT] 자연어 처리#4 - 직방 아파트ID 얻기

by 생활속의 IT램프 2020. 3. 24.

[이전 글 보기]

2020/03/22 - [AI/자연어처리] - [생활속의 IT] 자연어 처리#1 - 아나콘다 설치하기

2020/03/22 - [AI/자연어처리] - [생활속의 IT] 자연어 처리 - 참고) Jupyter의 개념

2020/03/23 - [AI/자연어처리] - [생활속의 IT] 자연어 처리#2 - 크롤러 만들기

2020/03/23 - [AI/자연어처리] - [생활속의 IT] 자연어 처리#3 - 직방의 지리정보 Geohash 이해하기

 

 

이전 포스트에서 직방이 여러 정보를 전달할 때 인수로 Geohash를 이용한다는 것을 봤습니다.

우리는 텍스트마이닝을 위해 직방의 아파트 평가글을 수집할 겁니다.

 

전국 아파트를 대상으로 하겠습니다.

 

1. Geohash 정하기

 

2. 서울내 아파트 ID 가져오기

 

--------------------------------------------------------------------------------------------------------------------------

1. Geohash 정하기

이전 포스트에서 인접한 구(가령 서초구, 강남구)에 대한 geohash는 중복될 수 있다고 했습니다.

그래서 전국 아파트ID를 가져오기 위해 직접 geohash 값을 전달할 예정입니다.

 

http://geohash.gofreerange.com/사이트에 가보면 아래와 같이 geohash 값을 지도로 직접 클릭해서 정할 수 있습니다.

대략 서울을 담는 geohash 를 모아 List로 만들어보겠습니다.

 

 

geohash = ['wyd','wye','wy6','wy7']

그런데 3레벨의 geohash값을 전달하기에는 규모가 너무 크기 때문에

직방에는 5레벨의 geohash값을 전달하려고 합니다.

즉 wyd7e 같은 형태로 말이죠.

 

이전 포스트에 언급하였지만 상위 레벨은 하위 레벨을 32개로 분할한 크기입니다.

그리고 하위 레벨의 값을 공통적으로 가진다고 하였습니다.

 

따라서 geohash값을 string으로 전달하면

상위 레벨 geohash 값 32개를 리스트로 리턴하는 함수를 만들었습니다. 

1
2
3
4
5
6
7
8
9
10
11
def getHigherGeohash(strgh):        # string 형태의 geohash 입력시 상위 레벨의 geohash 32개를 리스트로 전달
    returnList=[]
    for i in range(10):
        returnList.append(strgh+str(i))
    startIdx = ord('b')
    endIdx = ord('z')
    for i in range(startIdx, endIdx + 1):
        if (chr(i) != 'i' and chr(i) != 'l' and chr(i) != 'o'):
            returnList.append(strgh + chr(i))
 
    return returnList
 

3레벨 geohash를 전달하면 4레벨 geohash 를 얻어올 수 있고 이를 한번 더 통과시키면 5레벨 geohash 값을 가져올 수 있습니다.

3레벨 geohash 개수는 4개이고 상위로 갈수록 32개씩 곱해지니 우리가 구할 5레벨 geohash 개수는

4*32*32 = 4096이 될 것이라 예상할 수 있습니다.

 

2. 전국 아파트 ID 가져오기

 

전국 ID를 얻기 전 일단 서울 은평구에 속하는 wydq0 geohash 값을 주어 아파트 리스트를 받는 과정을 

보도록 하겠습니다.

1
2
3
4
5
6
7
8
import requests
import json
 
def getDanjiId(geohash):
    req = requests.get(url)
    items = req.json()
    print(items)

 

그리고 메인에는 geohash 리스트를 만든 후 하나씩 던지도록 만들었습니다. (지금은 은평구 한개)

 

1
2
3
geohash = ['wydq0']
for i in geohash:  
    getDanjiId(i)

 

나타난 결과값은 json 사이트(http://json.parser.online.fr/)에서 정리해서 보도록 합니다.

 

wydq0 geohash의 item 목록 GET 결과

결과를 보니 vrItems가 7건, RecommendItems가 26건, items가 6건인데 자세히 열어보면 danjiID가 들어있습니다.

vrItems의 목록. vrItems에는 이런게 7건 들어있음

 

RecommendItems, Items 모두 areaDanjiId가 들어가 있는데

이 세 가지 종류의 item에서 danjiId 값을 모두 가져오도록 하겠습니다. 

데이터를 보니 danjiId가 중복되는 경우도 있어서 중복ID는 제외하고 구성하겠습니다.

 

아까 작성했던 함수를 좀 뜯어고쳐 보도록 하겠습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def getDanjiList(geohash):
    req = requests.get(url)
    items = req.json()
 
    danjiList=[]
    if items["vrItems"!=[]:       ## vrItems 대상이 있으면 진행
        for i in items["vrItems"]:
            danjiList.append(i["areaDanjiId"])
    if items["recommendItems"!=[]:       ## recommend 대상이 있으면 진행
        for i in items["recommendItems"]:
            danjiList.append(i["areaDanjiId"])
    if items["items"!=[]:       ## Items 대상이 있으면 진행
        for i in items["items"]:
            danjiList.append(i["areaDanjiId"])
 
    danjiList = list(set(danjiList))
 
 
    return danjiList
 

vrItems, Recommend, Items 에서 Danji리스트는 중복될 수 있으므로 중복제거를 위해 list(set()) 함수를 썼습니다.

이제 위 함수는 string으로 된 geohash값을 주면 단지 ID를 리스트로 반환해줍니다.

 

#######################################################################################

 

메인함수는 아래와 같이 작성해서 돌려보겠습니다.

 

1
2
3
geohash = ['wydq0']
for i in geohash:
    print(getDanjiList(i))

 

wydq0 geohash 영역의 아파트 리스트를 가져왔습니다. 30건을 리턴해 주는군요.

그런데 wydq0 영역은 5레벨로 아래 보시다시피 매우 큰 영역입니다.

 

은평구 위쪽의 wydq0 영역, 매우 넓은 지역이다.

이 영역의 직방을 봐도 아파트 개수는 30건은 넘을 것이라 볼 수 있습니다.

 

wydq0 의 일부 영역, 이미 아파트 개수가 15건은 넘는 듯 합니다.

 

한마디로 직방은 아파트 리스트를 전부 주지는 않는 걸로 보인다는 겁니다.

geohash 값을 5레벨로 준게 너무 큰가 해서 6레벨 32개를 전달해서 받아봤는데

제가 테스트해본 결과 직방이 준 아파트 리스트는 동일했습니다. 

 

 

결국 직방이 아파트 ID를 100% 주지는 않는듯 한데, 왜 그런지는 잘 모르겠습니다.

어쨌든 일부 아파트가 누락된다고 보고, 전국의 아파트 ID를 얻어오도록 하겠습니다.

 

getDanjiList함수는 그대로 두고 메인에서 5레벨 geohash를 만들어 인수로 주면 됩니다.

메인은 이렇게 만들었습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
geohash = ['wyd','wye','wy6','wy7']
tmp = []
for i in geohash:
    tmp4Lv=getHigherGeohash(i)
    for j in tmp4Lv:
        tmp5Lv=getHigherGeohash(j)
        tmp.append(tmp5Lv)
 
totalGeohash = []
for i in tmp:
    totalGeohash+=i
print(totalGeohash[:5], len(totalGeohash))

그러면 아래와 같이 4096개의 5레벨 geohash를 얻게 됩니다.

 

이제 4096개의 geohash 값을 던져 danjiList를 얻어보도록 하겠습니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import requests
 
def getHigherGeohash(strgh):        # string 형태의 geohash 입력시 상위 레벨의 geohash 32개를 리스트로 전달
    returnList=[]
    for i in range(10):
        returnList.append(strgh+str(i))
    startIdx = ord('b')
    endIdx = ord('z')
    for i in range(startIdx, endIdx + 1):
        if (chr(i) != 'i' and chr(i) != 'l' and chr(i) != 'o'):
            returnList.append(strgh + chr(i))
 
    return returnList
 
 
def getDanjiList(geohash):
    req = requests.get(url)
    items = req.json()
 
    danjiList=[]
    if items["vrItems"!=[]:       ## vrItems 대상이 있으면 진행
        for i in items["vrItems"]:
            danjiList.append(i["areaDanjiId"])
    if items["recommendItems"!=[]:       ## recommend 대상이 있으면 진행
        for i in items["recommendItems"]:
            danjiList.append(i["areaDanjiId"])
    if items["items"!=[]:       ## Items 대상이 있으면 진행
        for i in items["items"]:
            danjiList.append(i["areaDanjiId"])
 
    danjiList = list(set(danjiList))
 
 
    return danjiList
 
 
#################################################################################################
 
geohash = ['wyd','wye','wy6','wy7']     # 5레벨 geohash 얻기
tmp = []
for i in geohash:
    tmp4Lv=getHigherGeohash(i)
    for j in tmp4Lv:
        tmp5Lv=getHigherGeohash(j)
        tmp.append(tmp5Lv)
totalGeohash = []
for i in tmp:
    totalGeohash+=i
 
totalDanjiList=[]
for i in totalGeohash:
    DanjiListPerGeohash = getDanjiList(i)
    totalDanjiList+=DanjiListPerGeohash
print(totalDanjiList[:10], len(totalDanjiList))

 

참고로 돌리면 매우 오래 걸립니다.

 

댓글