데이터 수집을 위한 웹 크롤링 방법
ML 모델링, 대시보드 제작 등 여러 이유로 웹 사이트를 크롤링해야 하는 상황이 생긴다. 물론 Python의 BeautifulSoup나 Selenium을 사용하면 크롤링이 가능하지만, 여기서는 "추출 방법"보다는 "추출 링크를 찾는 것"에 초점을 맞춰보려고 한다. 특정 페이지에서 원하는 정보를 가져오는 링크나 API를 찾을 수 있으면, 더 간단하고 빠르게 데이터를 추출할 수 있다.
정적/동적 페이지와 정적/동적 수집의 특징, API에 대해 먼저 살펴보고 싶다면, 아래 링크를 참고하면 된다.
[정적 페이지] GET Method를 활용한 HTML 요소 추출
가장 쉽고 일반적으로 사용할 수 있는 크롤링 방법이 정적 페이지에서 GET Method를 활용하는 방법이다. 그러나 동적 페이지에서 이 방식을 사용할 경우 원하는 데이터가 표시되지 않을 가능성이 존재하니 주의해야 한다!
가장 일반적인 방법
처음 크롤링을 접하는 사람들이 이 방법을 활용해 크롤링을 연습한다. 첫 연습에 사용될 방법인 만큼 간단하고 일반적으로 사용되는 방법이다. 네이버를 예시로 들자면, "https://www.naver.com"에 GET Request 및 HTML을 가져오고, 필요한 데이터를 추출하는 것이다.
GET Request URL 확인
이 방법을 활용한다면, 대체로 주소창에 있는 URL에 GET Request를 보내면 된다. 그러나 정확히 확인하기 위해서는 관리자 도구(F12)의 Network에서 확인이 가능하다. 아래의 사진에서 "https://m.naver.com/"에 GET Request를 통해 가져왔다는 것이 Header에 나타나 있고, Response에는 이에 대한 응답인 HTML 코드를 확인할 수 있다.
Python 예시
Python에서는 requests 라이브러리를 통해 HTTP 요청이 가능하다. response를 통해 얻은 결과를 BeautifulSoup를 활용해 원하는 형태로 데이터를 추출할 수 있는 것이다.
import requests
response= requests.get('https://www.naver.com')
print(response.text[:1000])
[정적, 동적 페이지] 해당 사용하는 API 및 Parameter 탐색
두 번째로 정적/동적 페이지 관계없이 사용 가능하지만, 어느 정도의 웹/프로그래밍 지식이 필요한 방법이다. 이 방법은 모든 페이지에 적용되는 것은 아니고, 관리자 도구나 웹 디버거(ex: Fiddler)를 활용해 페이지 내에서 API 호출이 이루어지는지 확인하고, 해당 API를 호출해 데이터를 수집하는 것이다. 만약 API를 호출하지 않는 페이지라면, 이 방법은 사용할 수 없다.
탐색 방법
사용하는 API를 탐색하기 위해서는 관리자 도구(F12)와 같은 웹 디버거가 필수적이다. 관리자 도구는 설치 없이 웹 상에서 가능하기 때문에 편리하지만, Fiddler는 관리자 도구보다 UI가 깔끔하고 데이터를 확인하기 편하다. 그래서 여기서 설명은 Fiddler를 기준으로 진행하려고 한다. 또한 Postman을 활용하면, API에 Request와 Response가 정상적으로 동작하는지 확인할 수 있다.
- 요약 : 웹 디버거(Fiddler)로 API를 탐색한 뒤, Postman으로 해당 API가 올바르게 동작하는지 확인
Fiddler와 Postman에 대해 자세히 알고 싶다면, 다음 링크를 참고하면 된다.
예시 페이지 : 다방
예시를 들어 설명하는 것이 이해가 빠를 것이라 생각하기 때문에 API 호출로 페이지를 구성하는 플랫폼 중 하나인 다방을 확인해보려고 한다. 다방은 아래 사진과 같이 지도를 줌 인/아웃하여 해당 위치의 매물을 확인할 수 있도록 구성되어 있다.
여기서 줌 인/아웃을 진행하면, 그때마다 api가 호출되는 것을 Fiddler에서 확인이 가능하다.
위의 Host URL(www.dabangapp.com)과 아래 Headers을 통해 "https://www.dabangapp.com/api/v5/markers/category/one-two" 링크로 GET Request를 보낸 것을 알 수 있다. 여기서 "?" 뒷부분은 API의 Parameter로 활용된다.
Fiddler의 WebForms에서 해당 Request에 사용된 Parameter를 확인 가능하다. 해당 API에 사용된 Parameter는 bbox, filters, useMap, zoom이다. 이를 형식에 맞춰 작성한 뒤 API에 Get Request를 보내면 이에 대한 응답을 받을 수 있는 것이다.
다방의 API에서는 Response를 JSON 형태로 제공하며, bbox 내에 존재하는 매물의 정보를 확인할 수 있다.
Python 예시
다방의 경우 headers를 설정해주지 않으면, 에러가 발생하는 이슈가 있어 추가해 주었다. 여기서 headers는 Fiddler의 Header 메뉴에서 확인이 가능하며, params와 headers를 json 형태로 작성해 준 뒤 requests.get의 매개변수로 넣어주면 된다. 사용한 GET 메서드의 파라미터는 다음과 같다.
- url : 요청을 보낼 주소
- headers : 요청에 포함할 헤더
- params : 요청에 포함할 파라미터
import requests
params = {
"bbox": '{"sw":{"lat":37.505739,"lng":126.9919803},"ne":{"lat":37.5539984,"lng":127.0562675}}',
"filters": '{"sellingTypeList":["MONTHLY_RENT","LEASE"],"depositRange":{"min":0,"max":999999},"priceRange":{"min":0,"max":999999},"isIncludeMaintenance":false,"pyeongRange":{"min":0,"max":999999},"useApprovalDateRange":{"min":0,"max":999999},"roomFloorList":["GROUND_FIRST","GROUND_SECOND_OVER","SEMI_BASEMENT","ROOFTOP"],"roomTypeList":["ONE_ROOM","TWO_ROOM"],"dealTypeList":["AGENT","DIRECT"],"canParking":false,"isShortLease":false,"hasElevator":false,"hasPano":false,"isDivision":false,"isDuplex":false}',
"page": 1,
"useMap": "naver",
"zoom": 14
}
headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
"Cookie": "_fwb=37od3E9MpyXVmFsL4IofFB.1720697470212; _fbp=fb.1.1720697470585.225224189142580448; _gcl_aw=GCL.1720697471.Cj0KCQjwhb60BhClARIsABGGtw-kc-hlUX7yjy6_4EHU8ub7a9PsTdTTN1p5i12H1O7P4uS3z-JEWoUaAjkGEALw_wcB; _gcl_gs=2.1.k1$i1720697470; _gid=GA1.2.363020388.1720697472; _gac_UA-59111157-1=1.1720697472.Cj0KCQjwhb60BhClARIsABGGtw-kc-hlUX7yjy6_4EHU8ub7a9PsTdTTN1p5i12H1O7P4uS3z-JEWoUaAjkGEALw_wcB; ring-session=1391973f-c2b6-42db-a949-9ce55784cd56; wcs_bt=s_3d10ff175f87:1720698474; _ga=GA1.1.844565415.1720697471; _ga_QMSMS2LS99=GS1.1.1720697470.1.1.1720698475.54.0.0",
"Csrf": "token",
"D-Api-Version": "5.0.0",
"D-App-Version": "1",
"D-Call-Type": "web",
"Expires": "-1",
"Pragma": "no-cache",
"Priority": "u=1, i",
"Referer": "https://www.dabangapp.com/map/onetwo?sellingTypeList=%5B%22MONTHLY_RENT%22%5D&m_lat=37.5822204&m_lng=126.9710212&m_zoom=13",
"Sec-Ch-Ua": '"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"macOS"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
}
response = requests.get(url='https://www.dabangapp.com/api/v5/markers/category/one-two', params=params, headers=headers)
print(response.json())
[동적 페이지] 동적 웹 페이지를 스크래핑할 수 있는 기술 활용
마지막 방법은 동적 웹 페이지에서 사용할 수 있는 방법이다. 바로 selenium이나 playwright와 같은 동적 웹 스크래핑 라이브러리를 활용하는 것이다. 물론 정적 웹 페이지에서도 활용이 가능하지만, 정적 웹 페이지 스크래핑 라이브러리(BeautifulSoup) 보다 속도가 훨씬 느린 것을 명심하자.
아래 링크는 Selenium을 활용하여 진행했던 것인데, 동적 웹 페이지 크롤링에 관심이 있다면 참고하면 좋을 것 같다.
동적 웹 페이지 vs 정적 웹 페이지
동적 웹 페이지는 웹 요소를 한 번에 가져오는 것이 아니라 요소를 부분적으로 적용함으로써 사용자에게 동작하고 있음을 알림과 동시에 실행이 빠른 부분은 바로 확인할 수 있다. 이러한 페이지에서 정적 수집을 하게 되면, 미완성된 HTML 코드를 받을 가능성이 높다. 따라서 정적 수집을 진행하다가 원하는 결과를 얻을 수 없다면, 동적 웹 페이지인지 확인해 보는 것도 좋은 방법이다.
동적 수집
동적 수집 라이브러리를 사용하면, 정적 수집과는 다르게 페이지를 직접 조작할 수 있다. selenium 같은 경우 코드를 실행하면, 웹 페이지를 직접 띄워 페이지에서 데이터를 수집하거나 페이지와 상호작용도 할 수 있다. 그만큼 동작 속도에서 정적 수집 라이브러리보다 미흡하다.
- 동적 수집 라이브러리 기능 중 일부
- 키보드 입력, 마우스 클릭
- 페이지 요소를 모두 가져올 때까지 대기
정리
크롤링을 진행할 수 있는 방법으로 총 세 가지를 정리해 보았다. 여기서 두 번째 방법인 페이지에서 사용하는 API를 활용할 수 있다면, 속도도 빠르고 어느 정도 정제된 데이터를 가져오기 때문에 가장 적합한 크롤링 방법이다. 그러나 대부분의 페이지는 첫 번째와 세 번째 방법으로 이루어져 있다. 그러니 속도 면에서 우월한 정적 수집을 먼저 시도해 본 후 동적 수집을 진행하는 것이 적합하다.
'Web' 카테고리의 다른 글
[Web] 웹 크롤링을 위한 Fiddler와 Postman 설치 및 사용법 (1) | 2024.09.25 |
---|---|
[Web] API(Application Programming Interface) 개념과 활용 (0) | 2024.04.13 |
[Web] Visual Studio Code에서 장고(Django) 사용 (0) | 2024.04.10 |
[Web] 장고(Django) 개발 환경 구축 (Windows) (0) | 2024.04.09 |
[Web/Python] 동적(Dynamic)/정적(Static) 수집 방법 비교 (2) | 2024.04.07 |