<aside> 🚨 일반적으로, 야놀자는 크롤링을 허용하지 않습니다. 하지만, 야놀자 부트캠프를 참여하면서 야놀자측에서 상업적 목표가 없음을 판단하여 크롤링을 허용했습니다.
</aside>
PM 요청사항
더미데이터의 수집/ 생성을 위해 만든 파일이며, DB 구축시 필드명은 백엔드 쪽에서 편한 방식으로 지정해주시면 됩니다 (파일의 필드명은 데이터 수집을 위함)
'글 작성 시각'은 정렬 필터 에서 최신 등록순 때문에 추가 하였습니다.'최신 등록순' 정렬을 어떻게 할 수 있을지 추후 논의 하면 될 듯 합니다.
입력된 데이터는 Chat GPT로 생성한 단순 예시 입니다
⚠️ 상품 상세 페이지 기획서 참고(약간의 수정 있을수 있음) : (개선 전) 상품 상세 페이지
Java
로 Selenium
을 활용하여 동적 웹 크롤링 진행Selenium과 ChromeDriver 설치
Chrome Driver 다운로드 : https://googlechromelabs.github.io/chrome-for-testing/
(Chrome 버전에 맞춰서 설치)
selenium implementation 진행
//crawling
implementation 'org.seleniumhq.selenium:selenium-java'
implementation 'org.seleniumhq.selenium:selenium-api'
implementation 'org.seleniumhq.selenium:selenium-chrome-driver'
ChromeOption : Chrome 드라이버의 속성을 조작하기 위한 WebDriver
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--no-sandbox");
chromeOptions.addArguments("--disable--gpu");
chromeOptions.addArguments("--start-minimized");
chromeOptions.addArguments("--disable-popup-blocking");
System.setProperty("webdriver.chrome.driver",
"/Users/qwert/Downloads/chromedriver-mac-arm64/chromedriver");
ChromeDriver
ChromeDriver chromeDriver = new ChromeDriver(chromeOptions);
for (int i = 0; i < localNumberArray.length; i++) { //지역 개수에 따라 반복
String localNumber = localNumberArray[i];
String url = BASE_URL + localNumber + SUFFIX_URL;
chromeDriver.get(url); //해당 url을 chromeDriver로 가져온다.
chromeDriver.manage().timeouts().implicitlyWait(Duration.ofMillis(3000));
// 정해진 시간,초만큼 로딩 시간을 기다린다.
크롤링 로직은 크게 야놀자 웹 사이트에서 데이터 갖고오기
& %호텔에 맞춰 데이터를 가공 및 DB에 저장
2개로 분리
야놀자 웹 사이트에서 데이터 갖고오기
메인페이지의 지역필터는 [서울, 부산, 제주, 경기, 인천, 강원, 경상, 전라, 충청]으로 구분
지역에 대한 구분은 r-”지역코드“ 지역코드로 구분을 한다.
해당 지역필터의 페이지에서 각 호텔들을 list로 담아와야 한다. (1차 크롤링)
String hotelDetailUrlPath = "div.PlaceListBody_listGroup__LddQf > div > div > a";
List<WebElement> hotelDetailElements = chromeDriver.findElements(
By.cssSelector(hotelDetailUrlPath));
list에 담은 호텔들을 하나씩 빼서 호텔 상세 페이지의 데이터를 조회한다.
for (WebElement hotelDetailElement : hotelDetailElements) {
try {
String hotelUrl = hotelDetailElement.getAttribute("href");
System.out.println(hotelUrl);
ChromeDriver secondChromeDriver = new ChromeDriver();
secondChromeDriver.get(hotelUrl);
secondChromeDriver.manage().timeouts()
.implicitlyWait(Duration.ofMillis(3000));
서비스에 필요한 데이터를 추출한다.
ex) 호텔 이름
// 호텔 이름
String hotelNameClassName = "css-1g3ik0v";
WebElement hotelNameElement = getElement(CLASS_NAME, hotelNameClassName,
secondChromeDriver);
ex) 호텔 이미지, 방이미지
String imgPath = "//*[@id=\\"__next\\"]/div/div/main/article/div[1]/section/div[1]/div/div/div[3]/div/span/img";
WebElement hotelImgElement = getElement(XPATH, imgPath, secondChromeDriver);
String hotelImgUrl = hotelImgElement.getAttribute("src");
String nextImgBtnClassName = "css-ln49wb";
WebElement nextBtn = getElement(CLASS_NAME, nextImgBtnClassName,
secondChromeDriver);
nextBtn.click();
WebElement roomImgElement = getElement(XPATH, imgPath, secondChromeDriver);
String roomImgUrl = roomImgElement.getAttribute("src");
%호텔에 맞춰 데이터를 가공 및 DB에 저장
위에서 추출한 데이터를 %호텔의 테이블에 맞춰서 entity build 진행
Room room = Room.builder()
.roomName(roomNameElement.getText())
.checkIn(LocalTime.of(checkInHour, checkInMin))
.checkOut(LocalTime.of(checkOutHour, checkOutMin))
.standardPeople(Integer.parseInt(String.valueOf(peopleNumArray[3])))
.maxPeople(Integer.parseInt(String.valueOf(peopleNumArray[11])))
.bedType(randomBedType)
.roomTheme(roomTheme)
.build();
hotelRoomRepository.save(hotel);