본문 바로가기

ICIA 수업일지

2021.10.20 수업일지(Spring Framework, Github, Git, Jsoup, Selenium)

- GitHub 사용하기

쉽게 버젼관리용 툴이라고 생각하면된다. 소스코드를 관리하는 서버를 github. 팀장이 팀원초대해서 공유해서 사용하기.

https://github.com/

 

GitHub: Where the world builds software

GitHub is where over 65 million developers shape the future of software, together. Contribute to the open source community, manage your Git repositories, review code like a pro, track bugs and feat...

github.com

 

프로젝트 생성 확인

 

삭제 경로

 

 

- github가 서버라면 git은 클라이언트 역할을 한다. 아래의 페이지에서 해당 운영체제에 맞는 git을 다운받자. 디폴트값으로 설치해도 좋다.

http://git-scm.com/download/win

 

Git - Downloading Package

Downloading Git Now What? Now that you have downloaded Git, it's time to start using it.

git-scm.com

 

설치 후 bash Launch

 

- 로컬저장소를 만들겠다.

C:\home\shop

- 해당 폴더에 프로젝트 소개를 위한 readme.txt를 만들겠다.

 

 

- 이 shop 프로젝트를 github에 올려보도록 하겠다.

 

 

list; ls 커맨드 입력

 

.git 저장소 만들기(com; git init)

 

숨겨진 파일 보기

 

.git에 프로젝트와 관련된 정보가 들어가 있다.

 

 

- 이제 bash에서 이메일과 유저 이름을 설정해주겠다.

이메일과 이름 설정 명령어 git config --global user.email(user.name) "user.email(user.name)"

 

git congif --list로 설정한 내용 보기

 

- 만약 삭제하고 싶으면

$ git config --global --unset user.email

 

- 이제 readme.txt를 .git에 추가하겠다.

- 커밋에는 상세 설명을 적을 수 있다. 설명을 잘 적어놓으면 내가 이 파일을 왜 만들었는지, 왜 수정했는지 알 수 있고 업데이트 버젼을 확인하여 rollback 할 수도 있다.

$ git add . (현재 폴더의 모든 파일 stage에 추가)
$ git add 폴더명 (지정 폴더를 stage에 추가)
$ git rm --cached readme.txt (특정 파일 stage에서 삭제)
$ git rm -r --cached . (state에 모든 파일 삭제)

 

 

- 만약에 log를 확인하고 싶다면 git log command입력

프로젝트 설명 수정을 확인할 수 있다.

 

 

- 만약에 롤백하고 싶으면

 

 

- 그 롤백을 취소하고 싶다면

 

 

- 올리고자하는 원격 저장소의 주소 지정

remote 주소

 

 

- 로컬저장소에 있는 커밋들을 push 명령어로 원격저장소에 올린다. github 로그인 창이 뜨거나 권한부여 여부를 물어본다면 설정을 하고 지정해주면 된다.

확인

 

업로드 확인

 

 

- 원격저장소의 커밋을 로컬저장소에 내려받기

원격저장소의 코드와 버젼 전체를 내 컴퓨터로 내려 받는 것을 clone이라고 한다. clone을 하면 최신 버전뿐만 아니라 이전 버전들과 원격저장소 주소 등이 내 컴퓨터의 로컬저장소에 저장된다.

집에서 작업하는 것 이외에 사무실에서 작업한다고 한다면 C:\office\shop 해당 폴더를 만들어준다. 이 폴더에 허브에 올려놓았던 작업들은 내려받을거다.

 

확인

 

$ git clone 이하 원격 저장소 주소 입력

 

// readme.txt 수정
// bash 수정한 readme.txt 추가
git add readme.txt
// 수정 설명 commit
git commit -m "안녕"
// 서버에 업로드
git push origin master

업로드 확인

 


 

- 크롤링(Crawling)을 이용한 새로운 프로젝트를 만들어보도록 하겠다.

크롤링? 페이지에 자료들을 긁어서 수집하는 방법

jsoup(보이는 페이지에 한해서), selenium(이벤트처리하여 데이터 가지고옴) 라이브러리를 이용해서 크롤링할 수 있다.

 

1. 일단 jsoup을 이용한 크롤링을 해보겠다.

서버를 끄고 라이브러리를 추가하겠다.

/ex11/pom.xml

...
		<!-- 새로운 라이브러리 추가 시작 -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>4.1.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
			<version>4.1.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>4.1.0.RELEASE</version>
		</dependency>
		<!-- jsoup 추가 -->
		<dependency>
			<groupId>org.jsoup</groupId>
			<artifactId>jsoup</artifactId>
			<version>1.12.1</version>
		</dependency>
...

 

라이브러리 확인

 

- 웹페이지 데이터 크롤링 컨트롤러 생성

- 개봉일, 제목, 포스터, 순위를 크롤링 해보겠다.

/ex11/src/main/java/com/example/controller/CrawlingController.java

클래스 확인

 

package com.example.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// 데이터 추출 전용
@RestController
public class CrawlingController {
	
	@RequestMapping("/cgv.json")
	public List<HashMap<String, Object>> cgv(){
		List<HashMap<String, Object>> array = new ArrayList<HashMap<String, Object>>();
		// 크롤링 오류 방지를 위한 예외 처리
		try {
			// jsoup으로 import
			// connect 안에는 크롤링할 페이지 주소
			Document doc = Jsoup.connect("http://www.cgv.co.kr/movies/").get();
			Elements elements = doc.select(".sect-movie-chart ol");
			System.out.println(elements);
		} catch (Exception e) {
			System.out.println("CGV Crawling error : "+e.toString());
		}
		return array;
	}
}

 

콘솔 출력 확인

 

 

- 이제 필요한 데이터를 가지고와 보도록 하겠다.

/ex11/src/main/java/com/example/controller/CrawlingController.java

...
		// 크롤링 오류 방지를 위한 예외 처리
		try {
			// jsoup으로 import
			// connect 안에는 크롤링할 페이지 주소
			Document doc = Jsoup.connect("http://www.cgv.co.kr/movies/").get();
			Elements elements = doc.select(".sect-movie-chart ol");
			for (Element e:elements.select("li")) {
				HashMap<String, Object> map = new HashMap<String, Object>();
				// 순위
				String rank=e.select(".rank").text();
				// 타이틀
				String title=e.select(".title").text();
				// 개봉일
				String date=e.select(".txt-info strong").text();
				// 이미지
				String image=e.select("img").attr("src");
				if(!rank.equals("")){
					map.put("rank", rank);
					map.put("title", title);
					map.put("date", date);
					map.put("image", image);
					array.add(map);					
				}
			}
		} catch (Exception e) {
			System.out.println("CGV Crawling error : "+e.toString());
		}
...

 

json 데이터 확인

 

- 해당 데이터를 출력해주는 page를 만들겠다.

/ex11/src/main/java/com/example/controller/HomeController.java

package com.example.controller;

import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HomeController {
	
	@RequestMapping("/cgv/list")
	public String cgvList(){
		return "cgv";
	}
	
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
		String formattedDate = dateFormat.format(date);
		model.addAttribute("serverTime", formattedDate );
		return "home";
	}
	
}

 

/ex11/src/main/webapp/WEB-INF/views/cgv.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>CGV Movie Chart</title>
<script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
<script
	src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.js"></script>
</head>
<style>
	#tbl{
		border:1px solid white;
		margin:0px auto;
		background: black;
		color: white
	}
</style>
<body>
	<table id="tbl">
	</table>
	<script id="temp" type="text/x-handlebars-template">
{{#each .}}
	<tr class="row">
		<td><input type="checkbox" /></td>
		<td>{{rank}}</td>
		<td><img src="{{image}}" width=100/></td>
		<td>{{title}}</td>
		<td>{{date}}</td>
	</tr>
{{/each}}
</script>
</body>
<script>
	getList();
	function getList() {
		$.ajax({
			type : 'get',
			url : '/cgv.json',
			dataType : 'json',
			success : function(data) {
				var temp = Handlebars.compile($("#temp").html());
				$("#tbl").html(temp(data));
			}
		})
	}
</script>
</html>

 

웹 페이지 출력 확인

 

 

- 다음페이지에서 날씨 데이터를 가지고 오도록 하겠다.

https://www.daum.net/

 

Daum

나의 관심 콘텐츠를 가장 즐겁게 볼 수 있는 Daum

www.daum.net

 

위치 확인

 

/ex11/src/main/java/com/example/controller/CrawlingController.java

인증서 관련 오류로 다시 한번 찾아보기

 


 

2. selenium을 이용한 크롤링을 해보겠다.

cgv.co.kr에서 더보기 버튼을 클릭해서 나오는 영화까지 모두 가지고 올 수 있도록 하겠다.

(1) 우선 크롬 버젼을 확인하여 그에 맞는 드라이버를 설치한다.

chrome://settings/help

버젼 확인

 

https://chromedriver.storage.googleapis.com/index.html?path=95.0.4638.17/ 

 

https://chromedriver.storage.googleapis.com/index.html?path=95.0.4638.17/

 

chromedriver.storage.googleapis.com

 

드라이버의 위치는 상관없지만 해당 경로를 알기 쉽게 프로젝트 폴더 안에 넣겠다.

 

- selenium 라이브러리를 추가하겠다.

/ex11/pom.xml

...
	<dependencies>
		<!-- 새로운 라이브러리 추가 시작 -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>4.1.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
			<version>4.1.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>4.1.0.RELEASE</version>
		</dependency>
		<!-- selenium 추가 -->
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-java</artifactId>
			<version>3.141.59</version>
		</dependency>
...

 

확인

 

/ex11/src/main/java/com/example/controller/CrawlingController.java

...
	// selenium을 이용한 크롤링
	@RequestMapping("/cgvmore.json")
	public List<HashMap<String, Object>> cgvMore() {
		List<HashMap<String, Object>> array = new ArrayList<HashMap<String, Object>>();
		// 크롤링 오류 방지를 위한 예외 처리
		try {
			// 드라이버 위치
			System.setProperty("webdriver.chrome.driver", "C:/data/spring/chromedriver.exe");
			// 드라이버 옵션
			ChromeOptions options = new ChromeOptions();
			// 웹 페이지 안열리게
			options.addArguments("headless");
			// 웹 드라이버
			WebDriver driver = new ChromeDriver();
			driver.get("http://www.cgv.co.kr/movies/");
			
		} catch (Exception e) {
			System.out.println("CGV Crawling error : " + e.toString());
		}
		return array;
	}
...

데이터를 가지고 오지 않은 상태에서는 해당 홈페이지가 열린다.

 

 

- 이제 더보기 버튼 이벤트를 입력해서 페이지가 뜨도록 하겠다.

...
		try {
			// 드라이버 위치
			System.setProperty("webdriver.chrome.driver", "C:/data/spring/chromedriver.exe");
			// 드라이버 옵션
			ChromeOptions options = new ChromeOptions();
			// 웹 페이지 안열리게
			// options.addArguments("headless");
			// 웹 드라이버
			WebDriver driver = new ChromeDriver();
			driver.get("http://www.cgv.co.kr/movies/");
			// 더보기 버튼으로 영화목록 더보기
			WebElement btnMore = driver.findElement(By.className("link-more"));
			btnMore.click();
		} catch (Exception e) {
			System.out.println("CGV Crawling error : " + e.toString());
		}
...

 

더보기 버튼 작동하여 팝업 확인

 

 

...
	// selenium을 이용한 크롤링
	@RequestMapping("/cgvmore.json")
	public List<HashMap<String, Object>> cgvMore() {
		List<HashMap<String, Object>> array = new ArrayList<HashMap<String, Object>>();
		// 크롤링 오류 방지를 위한 예외 처리
		try {
			// 드라이버 위치
			System.setProperty("webdriver.chrome.driver", "c:/chromedriver.exe");
			// 드라이버 옵션
			ChromeOptions options = new ChromeOptions();
			// 웹 페이지 안열리게
			options.addArguments("headless");
			// 웹 드라이버
			WebDriver driver = new ChromeDriver(options);
			driver.get("http://www.cgv.co.kr/movies/");

			WebElement btnMore = driver.findElement(By.className("link-more"));
			btnMore.click();

			List<WebElement> elements = driver.findElements(By.cssSelector(".sect-movie-chart ol li"));
			for(WebElement e:elements){
				HashMap<String, Object> map = new HashMap<String, Object>();
				String title=e.findElement(By.className("title")).getText();
				String image=e.findElement(By.tagName("img")).getAttribute("src");
				String link=e.findElement(By.tagName("a")).getAttribute("href");
				map.put("title", title);
				map.put("image", image);
				map.put("link", link);
				array.add(map);
			}
		} catch (Exception e) {
			System.out.println("CGV Crawling error : " + e.toString());
		}
		return array;
	}
...

 

가장 마지막 데이터를 가지고 왔다.

 


 

- 다음 날씨의 데이터를 가지고 와보겠다.

https://jinseongsoft.tistory.com/310?category=823887 

 

[Selenium] Invisible(display:none) 상태인 Element의 text 가져오는 방법

들어가며 Selenium 사용시 특정 Element의 text 값을 가져오려고 할 때 간혹 해당 Element의 속성이 "display:none" 상태라서 빈 text가 가져와지는 경우가 있습니다. 이유를 살펴보니 Selenium WebDriver는 보이..

jinseongsoft.tistory.com

 

/ex11/src/main/java/com/example/controller/CrawlingController.java

...
	// selenium을 이용한 날씨 크롤링
	@RequestMapping("/weather.json")
	public List<HashMap<String, Object>> weather() {
		List<HashMap<String, Object>> array = new ArrayList<HashMap<String, Object>>();
		try {
			// 드라이버 위치
			System.setProperty("webdriver.chrome.driver", "c:/chromedriver.exe");
			// 드라이버 옵션
			ChromeOptions options = new ChromeOptions();
			// 웹 페이지 안열리게
			options.addArguments("headless");
			// 웹 드라이버
			WebDriver driver = new ChromeDriver(options);
			driver.get("https://www.daum.net/");

			List<WebElement> elements = driver.findElements(By.cssSelector(".list_weather li"));
			for (WebElement e : elements) {
				HashMap<String, Object> map = new HashMap<String, Object>();
				String part = e.findElement(By.className("txt_part")).getAttribute("textContent");
				String status = e.findElement(By.tagName("strong")).getAttribute("textContent");
				String temper = e.findElement(By.className("txt_temper")).getAttribute("textContent");
				map.put("part", part);
				map.put("status", status);
				map.put("temper", temper);
				array.add(map);
			}
			driver.close();
		} catch (Exception e) {
			System.out.println("daum weather Crawling error : " + e.toString());
		}
		return array;
	}
...

 

데이터 get 확인

 

 

- 이제 크롤링한 데이터를 테이블에 저장해보겠다.

/ex11/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml

...
	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
 		<beans:property name="maxUploadSize" value="10485760"/>
	</beans:bean>
	<beans:bean id="uploadPath" class="java.lang.String">
	 	<beans:constructor-arg value="c:/data/upload"/>
	</beans:bean>	
</beans:beans>

 

- 테이블 생성

- go to mysql - boardDB

#2021.10.20
create table tbl_movie(
id int auto_increment primary key,
title nvarchar(200),
image nvarchar(200),
regdate datetime default now()
);

 

/ex11/src/main/resources/mapper/MovieMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.MovieMapper">
 	<insert id="insert">
 		insert into tbl_movie(title,image)
 		values(#{title},#{image})
 	</insert>
</mapper>

 

/ex11/src/main/java/com/example/mapper/MovieDAO.java

package com.example.mapper;

public interface MovieDAO {
	public void insert(String title, String image);
}

 

/ex11/src/main/java/com/example/mapper/MovieDAOImpl.java

package com.example.mapper;

import java.util.HashMap;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class MovieDAOImpl implements MovieDAO {
	@Autowired
	SqlSession session;
	
	String namespace="com.example.mapper.MovieMapper";
	
	@Override
	public void insert(String title, String image) {
		HashMap<String, Object> map = new HashMap<>();
		map.put("title", title);
		map.put("image", image);
		session.insert(namespace+".insert",map);
	}
	
}

 

- 크롤링할때 db에 넣겠다.

/ex11/src/main/java/com/example/controller/CrawlingController.java

...
	// selenium을 이용한 영화 데이터 크롤링
	@RequestMapping("/cgvmore.json")
	public List<HashMap<String, Object>> cgvMore() {
		List<HashMap<String, Object>> array = new ArrayList<HashMap<String, Object>>();
		// 크롤링 오류 방지를 위한 예외 처리
		try {
			// 드라이버 위치
			System.setProperty("webdriver.chrome.driver", "c:/chromedriver.exe");
			// 드라이버 옵션
			ChromeOptions options = new ChromeOptions();
			// 웹 페이지 안열리게
			options.addArguments("headless");
			// 웹 드라이버
			WebDriver driver = new ChromeDriver(options);
			driver.get("http://www.cgv.co.kr/movies/");

			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				// TODO: handle exception
			}
			
			WebElement btnMore = driver.findElement(By.className("link-more"));
			btnMore.click();

			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				// TODO: handle exception
			}

			List<WebElement> elements = driver.findElements(By.cssSelector(".sect-movie-chart ol li"));
			for (WebElement e : elements) {
				HashMap<String, Object> map = new HashMap<String, Object>();
				String title = e.findElement(By.className("title")).getText();
				String image = e.findElement(By.tagName("img")).getAttribute("src");
				String link = e.findElement(By.tagName("a")).getAttribute("href");
				map.put("title", title);
				map.put("image", image);
				map.put("link", link);
				// DB에 데이터 insert
				mdao.insert(title, image); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
				array.add(map);
			}
		} catch (Exception e) {
			System.out.println("CGV Crawling error : " + e.toString());
		}
		return array;
	}

 

insert 확인

 

 

- 이미지명 및 해당 이미지를 저장하기 위해서 테이블을 드랍하겠다.

drop table tbl_movie;

create table tbl_movie(
id int auto_increment primary key,
title nvarchar(200),
image nvarchar(200),
regdate datetime default now()
);

select * from tbl_movie;

확인

 

 

...
	// selenium을 이용한 영화 데이터 크롤링
	@RequestMapping("/cgvmore.json")
	public List<HashMap<String, Object>> cgvMore() {
		List<HashMap<String, Object>> array = new ArrayList<HashMap<String, Object>>();
		// 크롤링 오류 방지를 위한 예외 처리
		try {
			// 드라이버 위치
			System.setProperty("webdriver.chrome.driver", "c:/chromedriver.exe");
			// 드라이버 옵션
			ChromeOptions options = new ChromeOptions();
			// 웹 페이지 안열리게
			options.addArguments("headless");
			// 웹 드라이버
			WebDriver driver = new ChromeDriver(options);
			driver.get("http://www.cgv.co.kr/movies/");

			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				// TODO: handle exception
			}
			
			WebElement btnMore = driver.findElement(By.className("link-more"));
			btnMore.click();

			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				// TODO: handle exception
			}

			List<WebElement> elements = driver.findElements(By.cssSelector(".sect-movie-chart ol li"));
			for (WebElement e : elements) {
				HashMap<String, Object> map = new HashMap<String, Object>();
				String title = e.findElement(By.className("title")).getText();
				String image = e.findElement(By.tagName("img")).getAttribute("src");
				String link = e.findElement(By.tagName("a")).getAttribute("href");
				map.put("title", title);
				map.put("image", image);
				map.put("link", link);
				
				// 이미지 copy(cgv -> tomcat)
				URL url = new URL(image);
				InputStream in = url.openStream();
				String path="c:/data/upload";
				String file ="/movie/"+System.currentTimeMillis()+".jpg";
				OutputStream out = new FileOutputStream(path+file);
				FileCopyUtils.copy(in, out);
				
				mdao.insert(title, file);
				array.add(map);
			}
		} catch (Exception e) {
			System.out.println("CGV Crawling error : " + e.toString());
		}
		return array;
	}
...

이미지 업로드 및 테이블 insert 확인