본문 바로가기
Back-end/Python

[크롤링] 직방에서 방찾기 (2) - Crawler

by 허도치 2020. 1. 21.

2020/01/21 - [Back-end/Python] - [크롤링] 직방에서 방찾기 (1) - 데이터 분석

 

 

  지난 포스트에서 직방에서 방정보를 수집하기위한 API서버의 URL정보들을 수집했다. API서버에서 바로 데이터를 받아오는 방식으로 크롤러를 만들것이기 때문에 BS4와 같은 별도의 Parser는 사용하지 않을 것이며 Reuqests 라이브러리 하나로 간단하게 만들어 볼 것이다.

 

 

1. 라이브러리 설치.

   1-1. requests 라이브러리 설치.

         > pip install requests

 

 

2. 매물목록 데이터 확인.

   2-1. 데이터 확인용 크롤러 생성.

         - crawl_zigbang.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# crawl_zigbang.py
import requests
import json
from pprint import pprint
 
ROOM_LIST_URL="https://apis.zigbang.com/v3/items/ad/96?subway_id=96&radius=1&sales_type=&deposit_s=0&rent_s=0&floor=1~%7Crooftop%7Csemibase&domain=zigbang&detail=false"
ROOM_INFO_URL="https://apis.zigbang.com/v2/items/19854111"
SUBWAY_LIST_URL="https://apis.zigbang.com/property/biglab/subway/all?"
 
req = requests.get( ROOM_LIST_URL )
 
if req.status_code == 200:
    data = json.loads( req.text )
 
    print( data.keys() )
    print( data['total_count'], len(data['list_items']) )
    pprint( data['list_items'][:5] )
 
cs

         - 3 ln: 파이썬에서 Json 데이터를 조작하기 위한 내장 라이브러리.

         - 4 ln: Dict, List 등의 데이터를 출력할 때, 보기좋게 만들어주는 내장 라이브러리.

         - 6~8 ln: 지난 포스트에서 수집한 RequestURL.

         - 10 ln: GET 방식으로 매물목록을 요청.

         - 12 ln: 요청이 성공했을 경우.

         - 13 ln: 문자열로된 Json을 Dictionary로 파싱.

 

   2-2. 실행결과.

         - list_items에 매물목록 정보와 공인중개사의 정보가 있음.

         - 매물의 상세 정보를 요청하기위해서 item_id를 추출.

           * data["list_items"]["simple_item"]["item_id"]

         - 공인중개사 정보는 필요없으므로 버림.

 

   2-3. 매물목록에서 매물의 ID만 추출.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# crawl_zigbang.py
import requests
import json
from pprint import pprint
 
ROOM_LIST_URL="https://apis.zigbang.com/v3/items/ad/96?subway_id=96&radius=1&sales_type=&deposit_s=0&rent_s=0&floor=1~%7Crooftop%7Csemibase&domain=zigbang&detail=false"
ROOM_INFO_URL="https://apis.zigbang.com/v2/items/19854111"
SUBWAY_LIST_URL="https://apis.zigbang.com/property/biglab/subway/all?"
 
req = requests.get( ROOM_LIST_URL )
 
if req.status_code == 200:
    data = json.loads( req.text )
 
    item_ids = [ item["simple_item"]["item_id"for item in data["list_items"if 'ad_agent' not in item ]
 
    pprint( item_ids[:5] )
 
cs

         - 15 ln: 공인중개사 정보를 제외하고 item_id만 추출.

 

   2-4. 실행결과.

         - 매물의 ID 정보만 추출성공.

 

   2-5. 지하철 정보와 매물의 상세정보도 위와 같이 분석하면서 필요한 데이터를 어떻게 수집할지 분석해야함.

 

 

4. 최종 소스.

   4-1. 지하철역을 중심으로 매물의 상세정보 수집하는 크롤러.

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# crawl_zigbang.py
import requests
import json
from pprint import pprint
 
SUBWAY_LIST_URL="https://apis.zigbang.com/property/biglab/subway/all?"
ROOM_LIST_URL="https://apis.zigbang.com/v3/items/ad/{subway_id}?subway_id={subway_id}&radius=1&sales_type=&deposit_s=0&rent_s=0&floor=1~%7Crooftop%7Csemibase&domain=zigbang&detail=false"
ROOM_INFO_URL="https://apis.zigbang.com/v2/items/{room_id}"
 
# 지하철 정보 수집
def getSubwayId( subway_name ):
    REQUEST_URL = SUBWAY_LIST_URL
 
    req = requests.get( SUBWAY_LIST_URL )
    if req.status_code == 200:
        data = json.loads( req.text )
 
        subway_info = [ item['id'for item in data if item['name'== subway_name ]
 
        if len(subway_info) > 0:
            return subway_info[0]
 
    return None
 
# 매물 목록 수집
def getRoomList( subway_id ):
    REQUEST_URL = ROOM_LIST_URL.format( subway_id=subway_id )
 
    req = requests.get( REQUEST_URL )
    if req.status_code == 200:
        data = json.loads( req.text )
 
        return [ item["simple_item"]["item_id"for item in data["list_items"if 'ad_agent' not in item ]
 
    return list()
 
# 매물 상세정보 수집
def getRoomInfo( room_id ):
    REQUEST_URL = ROOM_INFO_URL.format( room_id=room_id )
 
    req = requests.get( REQUEST_URL )
    if req.status_code == 200:
        data = json.loads( req.text )
 
        return data
    
    return None
 
# 매물 상세정보를 입맞대로 파싱
def parseRoomInfo( room_info, find_text=None ):
    parsed_data = {
        "url"'https://www.zigbang.com/home/oneroom/items/{}'.format( room_info["item"].get("item_id") )
        , "item_id": room_info["item"].get("item_id")
        , "제목": room_info["item"].get("title")
        , "주소": ( room_info["item"].get("local1"), room_info["item"].get("local2"), room_info["item"].get("local3"), room_info["item"].get("local4") )
        , "설명": {
            "요약": room_info["item"].get("agent_comment")
            , "상세내용": room_info["item"].get("description")
        }
        , "정보": {
            "사진": room_info["item"].get("images")
            , "전세/월세": room_info["item"].get("sales_type")
            , "방": room_info["item"].get("service_type")
            , "층수""{}/{}".format( room_info["item"].get("floor"),  room_info["item"].get("floor_all") )
        }
        , "비용": {
            "관리비": room_info["item"].get("manage_cost")
            , "보증금액": room_info["item"].get("보증금액")
            , "월세금액": room_info["item"].get("월세금액")
        }
        , "면적": {
            "공급면적_m2": room_info["item"].get("공급면적_m2")
            , "대지권면적_m2": room_info["item"].get("대지권면적_m2")
            , "전용면적_m2": room_info["item"].get("전용면적_m2")
        }
        , "중개사": room_info["agent"].get("owner")
    }
    if find_text is not None:
        if  parsed_data["설명"]["상세내용"].find( find_text ) > 0:
            return parsed_data
        return None
    return parsed_data
 
# 지하철 정보 수집
subway_name = '수유역'
subway_id = getSubwayId( subway_name )
 
if subway_id is not None:
    
    # 매물 목록 수집 요청
    room_list = getRoomList( subway_id ) # 수유역=96
 
    for room_id in room_list:
        # 매물 상세 정보 수집 요청
        room_info = getRoomInfo( room_id )
 
        # 매물 상세정보를 입맞대로 파싱
        parend_room_info = parseRoomInfo( room_info, '대출' )
 
       if parend_room_info is not None:
pprint( parend_room_info )
 
else:
    print"{}을 찾을 수 없습니다. {}".format( subway_name, subway_id ) )
 
cs

         - 최대한 이해하기 쉽게 변수명과 함수명으로 만들었으니 천천히 보면서 이해해보는걸 추천함.

 

   4-2. 실행.

         > python crawl_zigbang.py

 

   4-3. 실행결과.

       

         - 위와같이 데이터가 잘 수집되는 것을 확인할 수 있음.

         - 조회하는 데이터의 갯수를 제한하지 않으면 조회할 때마다 100개가 넘은 데이터를 요청함.

         - 따라서, 주기적으로 수집하고자 하는 경우에는 Database나 File에 결과와 수집이력을 저장하여 중복수집되지 않도록 로직을 변경해야함.

 

 

 

5. 마치며.

   - 지금까지 직방에서 지하철역을 기준으로 매물을 수집하는 크롤러를 작성해보았다. 예제는 단순히 이런식으로 데이터를 수집할 수 있다는 것을 보여주는 것이기 때문에 저장소는 따로 설정하지 않았다. 수집된 데이터는 취향에 따라 가공해서 쓰는 것을 추천한다.

댓글