크롤링은 웹 상에 존재하는 자료들을 특정한 방식을 사용하여 수집하는 것을 의미한다. 여기서 중요한 점은 웹 상의 정보에는 여러가지 종류가 있다라는 점이다.
정적인 문서가 대상이 될 수도 있고, API와 같은 서비스가 될 수도 있다. 정적인 자료를 대상으로 하는 것은 크롤링을 한번만 해서 정리하면 되는 것이기 때문에 비교적 수월하지만 동적으로 계속해서 변화하는 자료들은 주기적으로 update를 필요로 하는 경우가 많기 때문에 특정한 방식들이 사용된다.
이제 정적 크롤링과 동적 크롤링에 대해서 알아보자.
“정적 크롤링”
한 페이지 내에서 원하는 정보가 전부 드러나는 정적인 데이터를 크롤링하여 가져오는 것
동적크롤링은 다음과 같다.
“동적 크롤링”
여러 페이지를 이동하며 마우스로 클릭하거나 타이핑을 통한 입력으로 확인할 수 있는 데이터를 가져오는 것
대표적으로 다음과 같은 특징이 있다.
정적 크롤링 | 동적 크롤링 | |
---|---|---|
라이브러리 | jsoup / beautifulsoup | chromedriver / Selenium |
속도 | 직관적으로 빠름 | 느림 |
비고 | 수집한 데이터를 직관적으로 빠르게 확인 가능 | 실제로 동작하는 과정(클릭, 입력 등) 확인을 통해 디버깅하기 좋음 |
이제 OMD 프로젝트에서 개발했던 내용을 예시로 정적 크롤링 구현을 더 자세히 알아보자.
나는 네이버 상품 정보를 크롤링하는 것이 목적이었기 때문에 상품 상세 페이지에 들어가 크롤링을 하였다. 먼저 개발자 도구를 이용해 내가 가져오고 싶은 정보가 들어있는 클래스를 찾는다.
예를 들어 상품의 링크를 크롤링 하고 싶다면
productList_mall_link__TrYxC linkAnchor
(띄어쓰기 되어 있으면 다른 클래스임)<a>
요소 선택하여 안에 있는 요소들 가져오기Elements linkElements = doc.select("a.productList_mall_link__TrYxC.linkAnchor")
String link = linkElement.attr("href");
이와 같은 방법으로 상품의 다른 정보도 가져올 수 있다.
추출한 데이터로 JSON 객체를 생성하여 결과를 출력하도록 하였다.
public static void main(String[] args) {
try {
String URL = "https://search.shopping.naver.com/catalog/26101847522";
Document doc = Jsoup.connect(URL).get();
Elements priceElements = doc.select("a.productList_value__B_IxM.linkAnchor");
Elements linkElements = doc.select("a.productList_mall_link__TrYxC.linkAnchor");
Elements storeNameElements = doc.select("a.productList_mall_link__TrYxC.linkAnchor");
// 데이터를 저장할 리스트 생성
List<JsonObject> pages = new ArrayList<>();
for (int i = 0; i < linkElements.size(); i++) {
Element priceElement = priceElements.get(i);
Element linkElement = linkElements.get(i);
Element storeNameElement = storeNameElements.get(i);
// 각 요소로부터 데이터 추출
Elements priceTag = priceElement.select("em");
String priceText = priceTag.first().text();
int price = Integer.parseInt(priceText.replaceAll(",", ""));
String link = linkElement.attr("href");
Elements imgTag = storeNameElement.select("img");
String storeName = imgTag.attr("alt").isEmpty() ? storeNameElement.select("span").first().text() : imgTag.attr("alt");
// 추출한 데이터로 JSON 객체 생성
JsonObject page = new JsonObject();
page.addProperty("price", price);
page.addProperty("link", link);
page.addProperty("storeName", storeName);
// 리스트에 JSON 객체 추가
pages.add(page);
}
// Gson 인스턴스 생성 및 포맷팅 설정
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// 리스트를 JSON 형식으로 변환
String jsonOutput = gson.toJson(pages);
// 결과 출력
System.out.println(jsonOutput);
}
catch (Exception e) {
System.out.println("크롤링 실패 : " + e);
}
}
[
{
"price": 999000,
"link": "https://cr.shopping.naver.com/adcr.nhn?x\u003dk%2BzHLrjL4YXL8qDWiCmeT%2F%2F%2F%2Fw%3D%3DsYSO5S17xTdKFroTOyKK%2F8zu3qYkv6M99T52J5kP3%2Fll%2BowoAioOiY18LO0jYfDaZRqWjhDaoi6GqQa54Kob2J7DOR%2FLUjiefYuuPC23vP0EhhS9KWdbDew7L8h4moZBY0Sd0WzzbtHCCsXhw4SRIOHt%2Bn73F6F3JcLTBHczAxorQ1YZ3e2ivlUvLb3Xn9UN9gUsT12Bu8xqjL6SaemOd6iAey3v4wktBHdn6qRW7hkACFtWopB3rbp%2FPE7s8EJoBcikgMj90vcTwSpxO97bxXG9byOBGOfjXaFZo1KsHgeekCg4JeanhsEnZNo09%2BpY4Wv0MYkUn5C5w5sv8tH3%2B74zJPW%2FfGQnsXEGGy93Hpd654J8UO7LDGXdPU9Do8oyM%2ButNgbXZ3dsXpLc8YhINXNOEhemO5P9mLSQNZHUcpgINzKcybEmPJ9P6hlytdV%2FhA8vpR3VOt0APnKewTXr7mVylINQo7ElbqUbLjfRXqZ%2FCLfowEHUrDR9sAPaYWsG%2B13cDGb%2FrI2jqv2iJSp%2Bj9vtecQFyE2azzkNtPPJxVUBxcv7xPv1IUIA0oI%2FsyPanQpNz%2F5J39zgYSoJnoMFP7hCN%2Bk2BrhjdW1E5%2FiscKNm25nlgMyvZ%2BtcUupeeTdM7RQalJDjj8N2WnE9xXcPDQVLpCy%2BgP77opXdRQAW9vXlOiRhp6rL1Vmp6LQUc2QK8cg3Nd5g38NkedCyxjzy%2BOJ%2FyawiXHdfoit1OkZnYa6ck0tNx2sfNEdlwSQS7ZmndvnSe5oN739mtxlHRYC3cuA%3D%3D\u0026nvMid\u003d33760868983\u0026catId\u003d50000151",
"storeName": "쿠팡"
},
{
"price": 1064000,
"link": "https://cr.shopping.naver.com/adcr.nhn?x\u003dH4nkNidr6y%2Ft1hH4JuzTPP%2F%2F%2Fw%3D%3DscNutFN3ggRNd2WcwFGar0JEJYj%2FCvNBT0nRILDms2Og7dYsxYR5eD7BddafDuUSxIT8fUh0betiHo2AgKod7YrDOR%2FLUjiefYuuPC23vP0EhhS9KWdbDew7L8h4moZBYxjuZuWah2sVOXCU6bylHeinJD2fi8TssCNCFWWTXcGByVwZJ7X67RIS84%2Bmq1agXcQD1noxS%2BFwck1nBaK49RFVd6Z%2BmZ5fvTALbBBPmfKKpJnalZl8YBNTVY%2F%2FSODJ0tjPf%2BkO8sKhS1WW9YdBV03yNYQltN87SjYG1iETcvaD5QUbj8j%2BgWub8moqkNk4QIYNQeQI%2FAKw7OLgJzexWCweMsZPpK61CBykFtbVtVy9Ia%2FIDcyjh15RQN5IM5zaTTGXPLtT04LXQ9V2JVHaeqnFTNKxWUq6U1dBjCG4mpVa1KEUJP%2Bo1hqOgls7QYVk0GLvQWxFx9uhCq%2BMcgWK7juN2FCQxeHAREnJLCjEC1%2Fnoq0pAGSlSx%2B%2FlpdPKUMerJVnN%2Bv%2FqwfkpIz2XakWUSmmuCxujaue8DTUK9e4xcXWsslyxaerMTcYkE%2Ba3Q229o2y147KkGAjDh%2FSQEO0VUZwOV9dp4S7QpwqwVXmEZq7fIwGzGVz23oVlJZpHgP8pYMpEvHVchTJK6LsvDw1iKj%2FglV9IbLJzhS8ns2hAPNcGGidsrWa0UJ7zfU5ghYz6\u0026nvMid\u003d45438540595\u0026catId\u003d50000151",
"storeName": "Speed 마켓"
},
{
"price": 1087000,
"link": "https://cr.shopping.naver.com/adcr.nhn?x\u003dhyATL4EQTSCJI14141N93f%2F%2F%2Fw%3D%3DsRk%2B%2BD2iccSTtJrw9upUuxXSqJ1i3DtXeHbTFdceEh%2FKW6AjQiAZ%2FB4Af9g%2B0FCDNrJpJBj3kysEPAbCBRw86ArDOR%2FLUjiefYuuPC23vP0EhhS9KWdbDew7L8h4moZBYrFRN%2BLM1yJAr78kyjmQeuVavFoQZioHQNBzgV6NBWA6ue%2BYK%2Bd%2BRAmQWYHqELJz%2BvlSSixewNPJGNnWKKU2LLU%2BqWMaHFjcn2Qi%2BNoZq%2Fiik6v2w9jBqMGR4TTsgYaQnbqiQh4KIc1%2B7R9K%2FHxeQP8hxdv3Pmn%2FPwawpIB%2FZSgxMjxacOi%2BJsSCMNBjTIzFea2Xl1Fbag77Pjxwqc%2FE0phJBKTaSsuVYIRNVz8F7i%2Bye2%2B%2BLGasgn1SPx%2B%2BwsW8eqwbK%2BNLjghCocGW4o4m5sPtecQFyE2azzkNtPPJxVUCEDI9mDIyfOSmpdAIqfiafFW4lvPEf9y%2BNKlQBtqAztEifXjHmybBizFclN4U7JQah%2BTRygi%2F1r%2BY%2FGW8ylHG%2FuNMPomocnLCWty6Z6THBGkkn9yfqj5xl8K8PeLq5OoVXYu4v%2BmzgB82Clo5bspGghRPhTYqStO%2FqSsw7nlpfhGXzppE%2BIUXVbzcOFUNQ9XiDeOwjzor8VEyJ1g%2FUPWuIWqEZdn4U861r1ZnfzJAjK1gFlTKFPe21DLnCBqCm7M%2FixNmtY2aBcmzYIqGgGFzu%2FyZl20umiDjdF2swL7yzHw%3D%3D\u0026nvMid\u003d85455581054\u0026catId\u003d50000151",
"storeName": "Two Step"
},
{
"price": 1279200,
"link": "https://cr.shopping.naver.com/adcr.nhn?x\u003dV%2Fhb006vYCMlW%2FabkkcpX%2F%2F%2F%2Fw%3D%3DsOhZZmfYSs45BVMmTOL1eoRshYkx9IQ5rzCD9ym2Ejp%2FRzB%2BoaVCyqiNkrjXYPYIXUHRkCnKbvI2VGdJSPWoNbag2IRyL9IrmhU2tJJCzkgvrOIflvl7ZVJx%2Bxl22SEnOvkAs6vR%2B6RlbGOBOw0blchnrG%2F9DJSAVy9GUUR%2FUh2ds5fWo0DNJ%2Fo0lzPbJYG1up8rTg8Hsbq4gWz4x6HP4C8qXj2vIkEKPE4VNYiU1zUE6iH6stKuG1q8n5%2BFw74kLp1t6%2B%2BXb8TKBKNrp%2BJA%2BjhsC3618HmsntmF01B7VaCAJjvnnruqQjYd4%2FSCfsTcl1tkq3amKHOOxk%2Fso7OOixWvqR2unsG9Pw6XBns%2FftjJo%2BG2TIH2qvnDlCxXH4V6E11PVT7hdN%2BFjcVZaNBq5mV0TOXEOkES0qEaxWvHD4Orredsg4mAua3L2XrbO9ZPFhokmdYwXPOcHE2bt%2BJizwCePcoyt3fweufMhlWz1upsG6Emsta1Dc2ParjzMoniGaDPJYjd8VmPnoCmTaJb%2B%2B3tf4Eep3C2HOrJb4i%2BpcSLjdhQkMXhwERJySwoxAtf5kV8l8Q20RegoAj1ynOcXdGmuCxujaue8DTUK9e4xcXVSCMZAHeM%2B9Cxsjjek7T7StW9Svb%2Fl4tf%2BaXc%2FaEKpNDfOqfqN3bF4pwcILRviipHOvQtRMXkC0o5j108LHj7OlTDDO3XIQ54%2FaIUF0h18HGqUOa4846iGybLWrhAw%2FsBWkbDrUFJ2hBG8QaB8WVzn\u0026nvMid\u003d40171968148\u0026catId\u003d50000151",
"storeName": "알렛츠ALLETS"
},
{
"price": 1291750,
"link": "https://cr.shopping.naver.com/adcr.nhn?x\u003djjR9jRNHVWXaRoT70ZL9T%2F%2F%2F%2Fw%3D%3Ds6UBttSbYvTdyJniKkkUKZte8yZ%2FYWKWLprMnbNkCkOAv%2FnT8Uh8Ngqz%2BFJ5tGt3O26QwuBrhdKyhuAmGEtG4Uag2IRyL9IrmhU2tJJCzkgvrOIflvl7ZVJx%2Bxl22SEnOGc3LeEY%2FFI62jpahvFHll8NagcSl3iH%2FOEhTwotJzxfxjdACsIBxxVYyPYjSvLIWQztWcK4rmBg2xTDekdqZpZ5ksoO5NU26ylSFPtwZwwVTJbvG9iQ4gJvlFaowLRbX6WFubgOpif7sEVcUzG3kx6RkgKJIQj0bGtNP3KpKq2w1in%2FWb1uzJpgdCOr4mtlvP2tfKoQ0NQPyiad34AQ6K9uJWUq0D0CKT8syS3fRHyyqU8NjY8sy9fcMdU9KC8sZAiFWNgVY5moXKBEiMwqHkuWkDjJ0rQWcMkGw0eynwCoLAp2Zct%2FFfyybwQB4kT8h4m%2FJKzftBiGzZOyBIX3DuoTKrQ5QJw5qEXj4ZkG8FdIGWi6R00uV%2BDAgpVR2mQkMsgpOgtFy0FKDW1YUptRTnjw%2BwJTmqlroAQqM0X5DM%2FqcXVy%2BgvBJe1BCxMwYIjAzP7TTXD9xXm0EeGXraW6Vk17UT%2F08Dkot4Grp0h9tRi2j%2BJ0%2Bfg0sTsj2G8ZVQWkuiDTfUcGpRvY2mDclp%2FyW8v9DVojvnjaHdvmdrPNTU2iu6AW8wDhRtWP15WuAQ%2BubJXSFlseqJb%2BD9y1uadTE7g%3D%3D\u0026nvMid\u003d45923657468\u0026catId\u003d50000151",
"storeName": "G마켓"
}
]
크롤링을 하게 되면 반복적으로 페이지를 왔다갔다 하게 되는 경우가 있는데, 일련의 과정을 반복하게 되면 웹에서 크롤러라고 판단하여 서버를 차단하게 된다.
왜냐하면 우리의 눈에는 보이지않는 백엔드 영역에서는 서버로 많은 데이터와 패킷들이 지나다니고 있기 때문이다. 페이지를 왔다갔다하면 데이터가 반복적으로 지나다니는 과정에서 서버가 과부하가 되고, 터져버릴 수 있다. 이런 상황을 방지하기 위해 큰 기업들은 여러가지 함정을 설치한다.
이런식으로 에러가 뜨기 때문에 반복적인 행동을 하지 않도록 주의하자!