본문 바로가기

programming/Gukbi

국비 교육 60일차 - errorPage, 웹 크롤링

728x90
반응형

오늘도 jsp내장 객체인 errorPage를 배웠다. 그리고 프로젝트 완성을 위해 데이터 수집을 해야하기 때문에 웹 크롤링을 배우고 실제 내 프로젝트에 필요한 데이터를 긁는 준비를 해놨다.

 

일단 errorPage부터 보겠다. 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" errorPage="error.jsp"%>
<%--
		web.xml : 톰캣에 전송
		========
			1) 서블릿 등록
			2) 한글 변환 등록 (request를 사용하지 않는다) => 전송 (Model)
			3) 에러페이지 지정
				Socket => Connection
				BufferedReader, OutputStream => PreparedStatement
		1. errorPage : 모든 에러가 한개의 파일로 처리 => jsp안에서 처리
		2. 에러별 처리 => web.xml
			web 에러
			200 : 정상수행
			307 : 임시 페이지로 이동 (파밍)
			400 : 요청이 잘못된 경우
			401 : 접근 불허용
			**404 : 파일이 없는 경우
			405 : 잘못된 데이터 전송 방식 POST(PST)
			**500 : 자바 소스 에러
			503 : 일시 중지 (서비스) => 시스템 점검
			================================ 웹서버에 만들어져 있다
 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

 사이트를 만들면서 발생할 수 있는 다양한 에러페이지들을 처리해주려면 errorPage="xxx.jsp"를 위에 써줘야 가능하다. 

404는 없는 페이지, 500은 자바 소스에러이다. 

 

맛집 데이터를 긁어서 페이지를 출력해보기

package com.sist.dao;

import lombok.Getter;
import lombok.Setter;

/*
 * 	CNO     NOT NULL NUMBER        
	TNO     NOT NULL NUMBER        
	TITLE   NOT NULL VARCHAR2(300) 
	SUBJECT NOT NULL VARCHAR2(300) 
	POSTER  NOT NULL VARCHAR2(260) 
	LINK    NOT NULL VARCHAR2(260) 

 */
@Setter
@Getter

public class FoodCategoryVO {
	private int no;
	private String title;
	private String subject;
	private String poster;
	private String link;
}

 링크까지 같이 만들어서 VO에 저장해준다

 

아래는 jsoup을 이용해서 태그 안의 내용을 긁어오는 코딩

프로젝트에 반드시 필요한 작업이기 때문에 꽤 열심히 들었다. 중요한건 목록 다음에 상세페이지에서 데이터 값을 긁어오기 때문에 꼭 링크값을 따와야 한다는 것이다. 

package com.sist.dao;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

/*
 * 	NO     NOT NULL NUMBER        
	TITLE   NOT NULL VARCHAR2(300) 
	SUBJECT NOT NULL VARCHAR2(300) 
	POSTER  NOT NULL VARCHAR2(260) 
	LINK    NOT NULL VARCHAR2(260) 

 */
public class FoodManager {
	private FoodDAO dao=new FoodDAO();
	public void foodCategoryData()
	{
		try
		{
			int k=1;
			// 연결 => 소스읽기
			Document doc=Jsoup.connect("https://www.mangoplate.com/").get();
			//System.out.println(doc);
			Elements title=doc.select("div.top_list_slide span.title"); // css 선택자 
			Elements poster=doc.select("div.top_list_slide img.center-croping");
			Elements subject=doc.select("div.top_list_slide p.desc");
			Elements link=doc.select("div.top_list_slide a");
			for(int i=0; i<title.size(); i++)
			{
				System.out.println("번호:"+k);
				System.out.println("제목:"+title.get(i).text());
				System.out.println("부제목:"+subject.get(i).text());
				System.out.println("이미지:"+poster.get(i).attr("data-lazy"));
				System.out.println("링크:https://www.mangoplate.com"+link.get(i).attr("href"));
				FoodCategoryVO vo=new FoodCategoryVO();
				vo.setTitle(title.get(i).text());
				vo.setSubject(subject.get(i).text());
				vo.setPoster(poster.get(i).attr("data-lazy"));
				vo.setLink(link.get(i).attr("href"));
				dao.foodCategoryInsert(vo);
				
				k++;
			}
		}
		catch (Exception ex)
		{
			
		}
	}
	
	public static void main(String[] args) {
		FoodManager fm=new FoodManager();
		fm.foodCategoryData();
	}
}

 일단 Manager파일을 만들고 DAO에서 오라클에 데이터를 넣어줄 코드를 짜줘야 한다. 

package com.sist.dao;
import java.util.*;

import java.sql.*;
import com.sist.jdbc.*;
// DBCP => 웹에서만 가능 
public class FoodDAO {
	 private DAOManager dm=new DAOManager();
	 private Connection conn;
	 private PreparedStatement ps;
	 public void foodCategoryInsert(FoodCategoryVO vo)
	 {
		 try
		 {
			 conn=dm.getConnection();
			 String sql="INSERT INTO food_category VALUES("
					   +"(SELECT NVL(MAX(no)+1,1) FROM food_category),?,?,?,?)";
			 ps=conn.prepareStatement(sql);
			 ps.setString(1, vo.getTitle());
			 ps.setString(2, vo.getSubject());
			 ps.setString(3, vo.getPoster());
			 ps.setString(4, vo.getLink());
			 // 실행
			 ps.executeUpdate(); // COMMIT
		 }catch(Exception ex)
		 {
			 ex.printStackTrace();
		 }
		 finally
		 {
			 dm.disConnection(conn, ps);
		 }
	 }
	 public List<FoodCategoryVO> foodCategoryData(int index)
	 {
		 List<FoodCategoryVO> list=new ArrayList<FoodCategoryVO>();
		 try
		 {
			conn=dm.getConnection();
			int start =0;
			int end=0;
			if(index==1)
			{
				start=1;
				end=12;
			}
			else if(index==2)
			{
				start=13;
				end=18;
			}
			else
			{
				start=19;
				end=30;
			}
			String sql="SELECT * FROM food_category "
					+ "WHERE no BETWEEN ? AND ?";
			ps=conn.prepareStatement(sql);
			ps.setInt(1, start);
			ps.setInt(2, end);
			
			ResultSet rs=ps.executeQuery();
			while(rs.next())
			{
				FoodCategoryVO vo=new FoodCategoryVO();
				vo.setNo(rs.getInt(1));
				vo.setTitle(rs.getString(2));
				vo.setSubject(rs.getString(3));
				vo.setPoster(rs.getString(4));
				vo.setLink(rs.getString(5));
				
				list.add(vo);
			}
			rs.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		 finally
		 {
			 dm.disConnection(conn, ps);
		 }
		 return list;
	 }
}

 번호는 자동증가 번호 시퀀스를 사용해주고, 나머지 값들은 크롤링 해온 값들을 채워주는 코드를 짠다. 이렇게 하고 Manager에서 실행을 시켜주면 만들어준 오라클 테이블 안에 값이 채워지게 된다. 

 

이걸 jsp로 화면을 만들어서 띄워주기만 하면 된다. 결과는 아래와 같다

 

 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%--
		특정부분에 다른 JSP를 첨부해서 사용 => 파일을 나눠서 작업이 가능
		유지보수가 좋다 => 조립식
		include => (HTML:<iframe>)
		<%@ include file=""%>
		<jsp:include page=""/> : XML의 단점 문법이 엄격하다
				1. 대소문자 구분, 2. 열고 닫기가 명확, 3. 속성은 반드시 ""
		
		1. JSP + JSP => 소스를 합쳐서 컴파일 => (<%@ include%>)
		2. JSP마다 컴파일 => HTML => <jsp:include>
 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<style type="text/css">
.row{
	width:960px;
	margin:0px auto;
}
</style>
</head>
<body>
<%--
	포함하고 있는 JSP는 request 공유한다
	
 --%>
<jsp:include page="header.jsp"></jsp:include>
<div class="container">
	<div style="height:30px;">
  <jsp:include page="home.jsp"></jsp:include>
  </div>
</div>
</body>
</html>

 근데 이제 main에서는 메뉴바가 있는 header.jsp 따로, 본문이 있는 home.jsp따로 만들어준뒤 include를 통해서 가져와 준다. 

 

 

결국 본문 내용을 보여주고 있는건 home.jsp 파일이다. 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.sist.dao.*,java.util.*"%>
<%
    String index=request.getParameter("index");
    if(index==null)
       index="1";
    FoodDAO dao=new FoodDAO();
    List<FoodCategoryVO> list=dao.foodCategoryData(Integer.parseInt(index));
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
   <div class="row">
    <a href="main.jsp?index=1" class="btn btn-sm btn-danger">믿고 보는 맛집 리스트</a>
    <a href="main.jsp?index=2" class="btn btn-sm btn-success">지역별 인기 맛집</a>
    <a href="main.jsp?index=3" class="btn btn-sm btn-primary">메뉴별 인기 맛집</a>
   </div>
   <div style="height:20px"></div>
   <div class="row">
     <%
         for(FoodCategoryVO vo:list)
         {
     %>
     
          <div class="col-md-4">
		    <div class="thumbnail">
		      <a href="#">
		        <img src="<%=vo.getPoster() %>" alt="Lights" style="width:100%">
		        <div class="caption">
		          <p><%=vo.getTitle() %></p>
		        </div>
		      </a>
		    </div>
		   </div>
     
     <%
         }
     %>
   </div>
</body>
</html>
728x90
반응형