크롤링이란?(Crawling)
'기다'라는 뜻의 crawl의 명사형인데, 소프트웨어와 같은 무언가가 인터넷을 돌아다니며 정보를 수집해 오는 작업을 의미
동적 크롤링 vs 정적 크롤링
개발 환경
SpringBoot 2.7.17 gradle-groovy
security5
JPA
Oralcle Develper
의존성을 추가하면 굳이 다운로드 할 필요 없음 !
implementation("org.jsoup:jsoup:1.17.2")
yes24 에서 검색한 자격증에 관한 책을 인기순으로 정리된 순서대로 크롤링할 건데 그중에서 이번엔 '책이름', '책가격', '책이미지'를 가져올거다
package com.web.domain;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@Builder
@Entity
@Table(name ="BOOKCRAWL")
public class Yes24BookCrawl {
@Id
private String bookName;
private int bookPrice;
private String imageName;
// 기본 생성자 추가
public Yes24BookCrawl() {
}
public Yes24BookCrawl(String bookName, int bookPrice, String imageName) {
this.bookName = bookName;
this.bookPrice = bookPrice;
this.imageName = imageName;
}
}
@Service
public class BookCrawlService {
@Autowired
private CrawlRepository crawlRepository;
public BookCrawlService(CrawlRepository crawlRepository) {
this.crawlRepository = crawlRepository;
}
public void saveYes24BookCrawl(Yes24BookCrawl bookCrawl) {
crawlRepository.save(bookCrawl);
}
public void saveYes24BookCrawls(List<Yes24BookCrawl> bookCrawls) {
crawlRepository.saveAll(bookCrawls);
}
public String generateSearchUrl() {
try {
String searchQuery = "컴퓨터활용";
//URL에 한글을 입력받기 위헤 인코더 입력
String encodedQuery = URLEncoder.encode(searchQuery, StandardCharsets.UTF_8.toString());
return "https://www.yes24.com/Product/Search?domain=ALL&query=" + encodedQuery;
} catch (UnsupportedEncodingException e) {
// 예외 처리: 인코딩에 실패한 경우
e.printStackTrace();
return null; // 또는 예외를 다시 던질 수 있음
}
}
@PostConstruct
public void getBooktDates() throws IOException {
String Book_Data_URL = generateSearchUrl(); //인코딩한 URL String 변수에 담기
Document doc = Jsoup.connect(Book_Data_URL).get(); //URL에 담긴 정보 전부 불러오기
//필요한 정보만 가져오기
String cssSelector = "#yesWrap #ySchContSec #sGoodsWrap .sGoodsSec section#goodsListWrap div.sGoodsSecArea ul#yesSchList li div.itemUnit";
//전체 가져왔던 데이터중 내가 필요한 정보만 불러오기
Elements contents = doc.select(cssSelector);
//확인용
System.out.println(contents);
//리스트에 저장할 객체 생성
List<Yes24BookCrawl> bookCrawls = new ArrayList<>();
for(Element content : contents) {
String name = content.select("div.item_info div.info_row.info_name a.gd_name").text();
String priceString = content.select("div.item_info div.info_row.info_price strong.txt_num em.yes_b").text();
// 숫자만 추출하여 변환
int price = Integer.parseInt(priceString.replaceAll("[^0-9]", ""));
// 이미지 크롤링
Element imgElement = content.select("div.item_img div.img_canvas span.img_item span.img_grp a.lnk_img em.img_bdr img.lazy").first();
String imageUri = imgElement.attr("data-original");
Yes24BookCrawl bookCrawl = Yes24BookCrawl.builder()
.bookName(name)
.bookPrice(price)
.imageName(imageUri)
.build();
System.out.println(bookCrawl.toString());
bookCrawls.add(bookCrawl);
}
//JPA로 DB에 저장
saveYes24BookCrawls(bookCrawls);
}
//전체 출력해줄 메서드
public List<Yes24BookCrawl> getAllBooks() {
return crawlRepository.findAll();
}
}
3번에서 사용한 JPA를 위한 Repository 만들어줍니다
package com.web.persistence;
import org.springframework.data.jpa.repository.JpaRepository;
import com.web.domain.Yes24BookCrawl;
public interface CrawlRepository extends JpaRepository<Yes24BookCrawl, String> {
}
컨트롤러를 생성해서 url을 통해 페이지로 이동할 수 있게 처리해줍니다
package com.web.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.web.domain.Yes24BookCrawl;
import com.web.service.BookCrawlService;
@Controller
public class MainController {
@Autowired
private BookCrawlService bookCrawlService;
@GetMapping("/books")
public String showBooks(Model model) {
List<Yes24BookCrawl> books = bookCrawlService.getAllBooks();
model.addAttribute("books",books);
return "/books";
}
}
책이름과 가격과 사진을 띄워줄 html을 templates에다가 만들어서 작성
컨트롤러에 주소와 이름이 일치하게 작성하면 됩니다
타임리프를 이용해서 정보를 보여줄거기 때문에 타임리프를 쓸 수 있는 코드를 추가해준 후에 간단한 테이블을 생성해줍니다
참고로 타임리프가 적용이 안될시에 properties에서 타임리프 설정이 되어있나 확인
# Thymeleaf 설정
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>BookList</title>
</head>
<body>
<h2>Book List</h2>
<table border="1">
<thead>
<tr>
<th>Book Name</th>
<th>Price</th>
<th>Image</th>
</tr>
</thead>
<tbody>
<tr th:each="book : ${books}">
<td th:text="${book.bookName}"></td>
<td th:text="${book.bookPrice}"></td>
<td>
<!-- 이미지 표시 (이미지 경로는 예시로 넣어주세요) -->
<img th:src="${book.imageName}" alt="Book Image" width="100">
</td>
</tr>
</tbody>
</body>
</html>