Notice
Recent Posts
Recent Comments
Link
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

코딩기록

230608 [Spring BOOT] External Library (디테일), Jsoup(크롤링), 본문

study

230608 [Spring BOOT] External Library (디테일), Jsoup(크롤링),

9-99zy 2023. 6. 8. 08:52

23_Editor (detail + bHit)

 

BoardController

@GetMapping(value="/detail.do")
	public ModelAndView detail(@RequestParam String idx) {
		return service.detail(idx);
	}

 

BoardService

@Transactional 을 사용하면 하나의 요청에 두개의 매서드를 보낼 때 두개의 매서드가 서로 관련이 있으면 원자성(all or nothing) 으로 전부 되거나 하나가 안되면 실행이 안되야 한다.

디테일 페이지에 들어가려는데 오류가 났는데, 조회수가 하나 올라가는 현상이 발생하는걸 방지하기 위해 Transactional을 사용한다.

 

// 어떤 예외 할건지, 아이솔레이션 을 어떤걸로 해줄건지 근데 얘 하나만 걸어주면 된다???
	@Transactional
	public ModelAndView detail(String idx) {
		dao.upHit(idx);
		BoardDTO dto = dao.detail(idx);
		ModelAndView mav = new ModelAndView("detail");
		mav.addObject("bbs", dto);
		
		return mav;
	}

 

BoardDAO

void upHit(String idx);

BoardDTO detail(String idx);

 

mapper

<update id="upHit">
   UPDATE editor SET bHit = bHit+1
   	WHERE idx = #{idx}
 </update>
   
 <select id="detail" resultType="board">
   SELECT * FROM editor 
   	WHERE idx = #{idx}
 </select>

 

detail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Basic Editor</title>

<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css">
<link rel="stylesheet" href="/richtexteditor/res/style.css">
<script src="/richtexteditor/rte.js"></script>
<script src="/richtexteditor/plugins/all_plugins.js"></script>


<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<style>
	table{
		magin-left : 45px;
	}
	table, th, td{
		border : 1px solid lightgray;
		border-collapse: collapse;
	}
	#content{
		display:none;
	}
</style>
</head>
<body>
		<table>
			<tr>
				<td>${bbs.user_name}</td>
			</tr>
			<tr>
				<td>${bbs.subject}</td>
			</tr>
			<tr>
				<td>
					<div id="div_editor"></div>
				</td>
			</tr>
			<tr>
				<td>
					<button onclick="location.href=/list.do">
						리스트
					</button>
				</td>
			</tr>
		</table>
		<div id="content">${bbs.content}</div>

</body>
<script>
	
	var config = {};
	config.editorResizeMode = "none"; // 에디터 크기 조절 : none
	// 상세보기에서는 필요한 툴바만 노출할 예정(html 저장, 출력, pdf 저장, 코드보기)
	config.toolbar="simple";
	config.toolbar_simple="{save, print, html2pdf, code}"
	
	
	var editor = new RichTextEditor('#div_editor',config);
	editor.setHTMLCode($('#content').html()); // editor 에 내용 넣기
	editor.setReadOnly();

</script>
</html>

 

결과 : 

리스트에서 제목 클릭 후 디테일 들어갔을 때 

detail.jsp 에서 상세보기에서는 필요한 툴바만 노출해 줬기 때문에 save, print, html2pdf, code 이 4개의 툴바만 나온다.

 

 

 


 

 

24_Jsoup

  •  외부 사이트나 파일의 HTML 을 가져와 parsing 해 준다.
  • 정적 페이지에 적합하다.(스크롤을 내릴 때 마다 덧붙여지는 것은 안된다.)
  • 속도가 빠르고 css selector 를 차용하여 원하는 요소를 추출하기 좋다.
  • 라이브러리 별도의 프로그램이 없다.
  • 프로그램 접근을 막아놓은 사이트에서는 데이터를 가져 올 수 없다.
  • jquery 와 비슷하다 (attr...)

 

기본설정 : jsp,jstl

maven 라이브러리

pom.xml 에 붙여넣기

 

 

<!-- jsoup -->
	<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
	<dependency>
	    <groupId>org.jsoup</groupId>
	    <artifactId>jsoup</artifactId>
	    <version>1.15.3</version>
	</dependency>

 

 

크롤링 해와서 원하는 요소 만 가져오는 법

네이버 해외 야구 + itworld

 

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<style></style>
</head>
<body>
	<p>
	<a href="connect.do" target="_blank">
		특정사이트 연결(네이버 해외야구)
	</a>
	</p>
	<p>
	<a href="getElem.do" target="_blank">
		특정 요소만 가져오기(itworld)
	</a>
	</p>

</body>
<script></script>
</html>

 

JsoupController

@Controller
public class JsoupController {
	
	Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired JsoupService service;
	
	@GetMapping(value="/")
	public String home() {
		return "home";
	}
	
	@GetMapping(value="/connect.do")
	public String connect(Model model) throws IOException {
		
		// 기본 URL
		String url = "https://sports.news.naver.com/wbaseball/record/index";
		// 추가 파라메터
		HashMap<String, String> params = new HashMap<String, String>();
		params.put("category", "mlb");
		params.put("year", "2023");
		params.put("league", "NL");
		
		Document doc = Jsoup.connect(url).data(params).get();
		logger.info("doc : "+doc);
		model.addAttribute("elem", doc);
		model.addAttribute("full", true);
		
		return "result";
	}
	
	
	@GetMapping(value="/getElem.do")
	public ModelAndView getElem() throws Exception {
		
		Document doc = Jsoup.connect("https://www.itworld.co.kr/howto").data("page","1").get();
		
		return service.getElem(doc);
	}
}

 

JsoupService

@Service
public class JsoupService {

	Logger logger = LoggerFactory.getLogger(getClass());

	// 크롤링은 쉽지만 원하는걸 솎아내올 때 힘들다.
	public ModelAndView getElem(Document doc) {
		
		ModelAndView mav = new ModelAndView("result");
		
		// 요소를 가져오는 방식
		// 1. js 방식 : doc.getElementById("test");		
		// 2. css 방식 : doc.select("#test");
		// div 중에서 node-list 한칸 뛰면(div .node-list) div 자식요소 중 node-list가 됨
		 
		// 노드리스트를 가져올 때 = 하나의 리스트
		Elements elems = doc.select("div.node-list");
		// 따라서 size = 1
		logger.info("elems size : "+elems.size());
		// 한개만 가져옴(0번째) - 하위 항목을 가져옴
		Element elem = elems.get(0);
		logger.info("elem : "+elem); // node-list
		Elements cardList = elem.select("div.card");// div중 card인것
		
		String url = "";
		String title = "";
		String content = "";
		
		ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String,String>>();
		
		for (Element card : cardList) { // cardList에서 하나씩
			HashMap<String, String> map = new HashMap<String, String>();
			
			// h5 에 card-title 하위에 a 태그 속성, 어떤속성? href 라는 속성 가져오기
			// url = card.select("h5.card-title a").attr("href");
			
			// h5중에 card-title 의 하위요소중 a 의 주소
			map.put("url", "https://www.itworld.co.kr" + card.select("h5.card-title a").attr("href"));
			// h5중에 card-title 의 하위요소중 a 의 html값
			map.put("title", card.select("h5.card-title a").html());
			
			// How-To : 파일볼트 복구 키를 잊었을 때 대처하는 방법 : /howto/293239 (제목과 url)
			map.put("content", card.select("p.card-text.crop-text-2").html());
			list.add(map);
		}
		mav.addObject("elem", list);
		mav.addObject("full", false);
		
		return mav;
	}
}

 

result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<style></style>
</head>
<body>
	<c:if test="${full}">${elem}</c:if>
	<c:if test="${!full}">
		<c:forEach items="${elem}" var="item">
			<ul>
				<li class="title"><a href="${item.url}">${item.title}</a></li>
				<li>${item.content}</li>
			</ul>
		</c:forEach>
	</c:if>
</body>
<script></script>
</html>

 

 

 


 

25_Selenium

  • 본래는 웹 사이트 테스트 도구(일련의 과정을 자동으로 해 주는 매크로 개념)
  • 웹 페이지 접근 시 특정한 순서가 있는 경우 유용하다.
  • 속도는 Jsoup 에 비해 느린편 이며 사용 브라우저의 드라이버가 필요 하다.

 

 

하려면 크롬 브라우저 드라이버 다운로드

https://chromedriver.chromium.org/downloads

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 114, please download ChromeDriver 114.0.5735.90 If you are using Chrome version 113, please download ChromeDriver 113.0.5672.63 If you are using Chrome version 112, please download ChromeDriver 112.0.5615.49

chromedriver.chromium.org

 

gdj63 에 붙여넣기 (라이센스는 무시)

 

maven 가서 라이브러리 가져오기

 

4.4.0

<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.4.0</version>
</dependency>