From e3505049a597ce8af8aa1501e0878aebf3858141 Mon Sep 17 00:00:00 2001 From: Ethan Date: Fri, 21 Jun 2024 23:43:35 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20Ipad=20=ED=81=AC=EB=A1=A4=EB=A7=81=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../itracker/crawl/service/CrawlService.kt | 2 +- .../{IpadAirMapper.kt => IpadAir5Mapper.kt} | 2 +- .../service/mapper/ipad/IpadAirM2Mapper.kt | 52 ++++++++++++++++++ .../service/mapper/ipad/IpadProM4Mapper.kt | 54 +++++++++++++++++++ .../service/response/IpadCrawlResponse.kt | 3 ++ .../itracker/crawl/service/util/Crawler.kt | 2 +- .../service/util/helper/DriverConnector.kt | 2 +- 7 files changed, 113 insertions(+), 4 deletions(-) rename src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/{IpadAirMapper.kt => IpadAir5Mapper.kt} (97%) create mode 100644 src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAirM2Mapper.kt create mode 100644 src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadProM4Mapper.kt diff --git a/src/main/kotlin/backend/itracker/crawl/service/CrawlService.kt b/src/main/kotlin/backend/itracker/crawl/service/CrawlService.kt index 44cab6b..928aa54 100644 --- a/src/main/kotlin/backend/itracker/crawl/service/CrawlService.kt +++ b/src/main/kotlin/backend/itracker/crawl/service/CrawlService.kt @@ -26,7 +26,7 @@ class CrawlService( fun crawlIpad(): List { val url = getCrawlUrl(CrawlTargetCategory.IPAD) - val products = crawler.crawl(url) + val products = crawler.crawlWithClick(url) return crawlMapper.toIpad(products) } diff --git a/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAirMapper.kt b/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAir5Mapper.kt similarity index 97% rename from src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAirMapper.kt rename to src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAir5Mapper.kt index 25955a4..4b977da 100644 --- a/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAirMapper.kt +++ b/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAir5Mapper.kt @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component private const val IPAD_AIR_5_GEN = "iPad Air 5세대" @Component -class IpadAirMapper : IpadMappingComponent { +class IpadAir5Mapper : IpadMappingComponent { override fun supports(subCategory: String): Boolean { return IPAD_AIR_5_GEN == subCategory diff --git a/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAirM2Mapper.kt b/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAirM2Mapper.kt new file mode 100644 index 0000000..5a222b4 --- /dev/null +++ b/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadAirM2Mapper.kt @@ -0,0 +1,52 @@ +package backend.itracker.crawl.service.mapper.ipad + +import backend.itracker.crawl.ipad.domain.Ipad +import backend.itracker.crawl.ipad.domain.IpadCategory +import backend.itracker.crawl.service.response.IpadCrawlResponse +import backend.itracker.crawl.service.vo.DefaultProduct +import org.springframework.stereotype.Component + +@Component +class IpadAirM2Mapper : IpadMappingComponent { + + override fun supports(subCategory: String): Boolean { + return subCategory.contains("iPad Air M2") + } + + override fun toDomain(product: DefaultProduct): Ipad { + val names = product.name.split(",") + .map { it.trim() } + .toList() + + val title = names[0].split(" ") + val company = title[0] + val releaseYear = title[2] + val category = IpadCategory.I_PAD_AIR + val chip = "M2" + val size = title[5] + val generation = "6" + val color = names[1] + val storage = names[2] + val isCellular = names[3].contains("Cellular") + + return IpadCrawlResponse( + coupangId = product.productId, + company = company, + name = product.name, + category = category, + chip = chip, + storage = storage, + color = color, + size = size, + releaseYear = releaseYear.toInt(), + isCellular = isCellular, + generation = generation, + productLink = product.productLink, + thumbnail = product.thumbnailLink, + basePrice = product.price.basePrice, + discountPercentage = product.price.discountPercentage, + currentPrice = product.price.discountPrice, + isOutOfStock = product.price.isOutOfStock + ).toDomain() + } +} diff --git a/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadProM4Mapper.kt b/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadProM4Mapper.kt new file mode 100644 index 0000000..93381cf --- /dev/null +++ b/src/main/kotlin/backend/itracker/crawl/service/mapper/ipad/IpadProM4Mapper.kt @@ -0,0 +1,54 @@ +package backend.itracker.crawl.service.mapper.ipad + +import backend.itracker.crawl.ipad.domain.Ipad +import backend.itracker.crawl.ipad.domain.IpadCategory +import backend.itracker.crawl.service.response.IpadCrawlResponse +import backend.itracker.crawl.service.vo.DefaultProduct +import org.springframework.stereotype.Component + +@Component +class IpadProM4Mapper : IpadMappingComponent { + + override fun supports(subCategory: String): Boolean { + return subCategory.contains("iPad Pro M4") + } + + override fun toDomain(product: DefaultProduct): Ipad { + val names = product.name.split(",") + .map { it.trim() } + .toList() + + val title = names[0].split(" ") + val company = title[0] + val releaseYear = title[2] + val category = IpadCategory.I_PAD_PRO + val chip = "M4" + val size = title[5] + val generation = "5" + val glass = title[7] + val color = names[1] + val storage = names[2] + val isCellular = names[3].contains("Cellular") + + return IpadCrawlResponse( + coupangId = product.productId, + company = company, + name = product.name, + category = category, + chip = chip, + storage = storage, + color = color, + size = size, + glass = glass, + releaseYear = releaseYear.toInt(), + isCellular = isCellular, + generation = generation, + productLink = product.productLink, + thumbnail = product.thumbnailLink, + basePrice = product.price.basePrice, + discountPercentage = product.price.discountPercentage, + currentPrice = product.price.discountPrice, + isOutOfStock = product.price.isOutOfStock + ).toDomain() + } +} diff --git a/src/main/kotlin/backend/itracker/crawl/service/response/IpadCrawlResponse.kt b/src/main/kotlin/backend/itracker/crawl/service/response/IpadCrawlResponse.kt index 7b35eda..f2280f0 100644 --- a/src/main/kotlin/backend/itracker/crawl/service/response/IpadCrawlResponse.kt +++ b/src/main/kotlin/backend/itracker/crawl/service/response/IpadCrawlResponse.kt @@ -14,6 +14,7 @@ data class IpadCrawlResponse( val storage: String, val color: String, val size: String, + val glass: String = "", val releaseYear: Int, val isCellular: Boolean, val generation: String, @@ -33,6 +34,7 @@ data class IpadCrawlResponse( storage: String, color: String, size: String, + glass: String = "", releaseYear: String, isCellular: Boolean, generation: String, @@ -51,6 +53,7 @@ data class IpadCrawlResponse( storage = storage, color = color, size = size, + glass = glass, releaseYear = releaseYear.toInt(), isCellular = isCellular, generation = generation, diff --git a/src/main/kotlin/backend/itracker/crawl/service/util/Crawler.kt b/src/main/kotlin/backend/itracker/crawl/service/util/Crawler.kt index 0adf4e7..5f152ed 100644 --- a/src/main/kotlin/backend/itracker/crawl/service/util/Crawler.kt +++ b/src/main/kotlin/backend/itracker/crawl/service/util/Crawler.kt @@ -105,7 +105,7 @@ class Crawler( val targetButton = buttons.firstOrNull { helper.findGrandParentElement(it) .findElement(By.className("carousel-header__title")).text == subcategory - } ?: throw CrawlException("해당 subcategory의 버튼을 찾을 수 없습니다. subcategory: $subcategory") + } ?: return products var clickCount = 0 while (clickCount++ < maxClicks) { diff --git a/src/main/kotlin/backend/itracker/crawl/service/util/helper/DriverConnector.kt b/src/main/kotlin/backend/itracker/crawl/service/util/helper/DriverConnector.kt index 01804fd..ff4668b 100644 --- a/src/main/kotlin/backend/itracker/crawl/service/util/helper/DriverConnector.kt +++ b/src/main/kotlin/backend/itracker/crawl/service/util/helper/DriverConnector.kt @@ -12,7 +12,7 @@ import java.time.Duration private const val USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" -private const val DEFAULT_WAIT_TIME = 5L +private const val DEFAULT_WAIT_TIME = 3L @Component class DriverConnector {