파이썬 + 셀레니움을 활용한 크롤링 (나사이미지)

https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame=41445 

 

 

Astronaut Photo ISS068-E-41445

Spacecraft nadir point: 17.8° S, 71.2° W Photo center point: Photo center point by machine learning: Nadir to Photo Center: Spacecraft Altitude: 226 nautical miles (419km)

eol.jsc.nasa.gov

 

 

0) Selenium 간단 설명

https://selenium-python.readthedocs.io/getting-started.html

 

 

 

1) 준비물

1 :  크롬드라이버

자신에 맞는 드라이버 다운로드 : https://chromedriver.chromium.org/downloads

내가 쓰는 크롬 버전 확인 : 크롬 우측 상단 점3개 > 설정 > 크롬정보

 

 2 :  작업용 폴더

바탕화면에 작업용 폴더 만들고 드라이버를 그 폴더에다가 넣어준다.

 

3: 셀레니움 설치

pip install selenium

 

 

2) 코드작성

1: 임포트하기 

from selenium import webdriver # 웹열때
from selenium.webdriver.common.keys import Keys # 키 가져오기용
from selenium.webdriver.common.by import By # Xpath이용
import time # 슬립걸때 사용
import urllib # 다운로드

 

 

2: 코드 생각해보기 

 

# 41445 번부터 41558번 까지 다운받고싶음 
# https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame=41445 여기에 들어가서
# 큰 화소수 다운 받아야함   => class="btn btn-light" 버튼 눌러서 모달창 띄우기 
# 모달창에서 이미지주소 긁어서 urllib으로 다운로드함 

# 다운받았으면 페이지 번호 1올려야함 => num += num을 반복 -> while문 써야함

 

 

눌러야하는 부분 xpath 확인하기

 

# 41445번째 xpath : //*[@id="wrap"]/div/div/div[4]/div[1]/a[1]

# 41446번째 xpath : //*[@id="wrap"]/div/div/div[4]/div[1]/a[1]

각 페이지별 고화소 픽셀 위치선택하는 xpath는 동일함

 

# 41445번째 xpath : //*[@id="myModal1"]/div/div/div[2]/img
# 41446번째 Xpath : //*[@id="myModal1"]/div/div/div[2]/img   

각 페이지 모달창에 뜬 사진의 xpath가 동일함

=> Xpath 고정값으로 두고 페이지의 num만 바꾸면 됨

 

 

 

 

3: 코드 작성해보기

# 41445 번부터 41558번 까지 다운받고싶음 
# https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame=41445 여기에 들어가서
# class="btn btn-light" 버튼 눌러서 모달창 띄우기 
# 모달창에서 이미지주소 긁어서 urllib으로 다운로드하기 
# 41445번째 xpath : //*[@id="myModal1"]/div/div/div[2]/img
# 41446번째 Xpath : //*[@id="myModal1"]/div/div/div[2]/img   xpath는 동일하니 num만 바꾸면 되겠네?
# 다운받았으면 num += num을 반복 -> while문 써야함


# 초기번호 페이지번호설정 

num = 41445  # 명시적으로 page_num으로 하는게 좋으나 간단하게 num으로 설정해둠

#화면열기
driver = webdriver.Chrome() # while 안에 넣어버리면 계속 새창이 뜸


while num < 41559 :
    print(num)

    # 다운받을 화면
    driver.get('https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame={0}'.format(num))
    time.sleep(2.1)
    print("화면열기 성공", num)

    # 화소선택버튼 찾기
    search = driver.find_element(By.XPATH, '//*[@id="wrap"]/div/div/div[4]/div[1]/a[1]')
    search.click()
    print("화소선택 버튼 누리기 성공", num)

    # image 주소 가져오기
    img_url = driver.find_element(By.XPATH, '//*[@id="myModal1"]/div/div/div[2]/img' ).get_attribute('src')
    print("주소 가져오기 성공", num)

    # image 다운로드
    urllib.request.urlretrieve(img_url, str(num)+'.png')
    print("다운로드 성공", num)
    time.sleep(5) #다운받는 시간 확보
    num = num + 1
 
    print(num)

 

 

다음에는 24장 모아서 1초짜리 영상으로 자동화 해봐야겠다

24fps 영상 자동화

 

 1. MultipartRequest 객체 생성시, 필요한 인자들
      1. request 내장 객체 (jsp에 이미 있다)
      2. 업로드 될 파일 저장 경로 
      3. 업로드 할 파일 최대 크기
      4. 인코딩 타입 : UTF-8
      5. 업로드된 파일 이름이 같을경우, 덮어씌우기 방지 객체
    

   2. 브라우저에서 보낸 파일 저장할 서버측의 저장 경로
    2-1. PC에 저장(서버쪽X, 서버가 있는 내PC에 저장)
   String path = "C:\\tmp\\"; (pc에 올리면 웹페이지상에서 볼수가없다 )
   
    2-2 서버상에 저장
   String path = request.getRealPath("save"); // 서버상의 save 폴더 실제 경로 찾기
   System.out.println(path);
   3. 업로드 할 파일 최대 크기
   int max = 1024*1024*5;   // 5mb
   4. 인코딩
   String enc = "UTF-8";
   5. 덮어씌우기 방지 객체
   DefaultFileRenamePolicy dp = new DefaultFileRenamePolicy();
   
   6. MultipartRequest 객체 생성
   MultipartRequest mr = new MultipartRequest(request, path, max, enc, dp);
   
   7. 파라미터 받기
   String writer = mr.getParameter("write");
   String sysName = mr.getFilesystemName("upload");   // 업로드 파일 이름
   String orName = mr.getOriginalFileName("upload");   // 파일 원본 이름
   String contentType = mr.getContentType("upload");   // 파일 종류 : 사진, 글....
   
   
   8.DB에 저장
   UploadDAO dao = new UploadDAO();
   dao.insertData(writer,sysName);
   
   
   

<title>image upload</title>
</head>
<body>
   <h1> form page </h1>
      <form action="upload.jsp" method="post" enctype="multipart/form-data">
         작성자 : <input type="text" name="write" /> <br />
         파  일 : <input type="file" name="upload" /> <br />
                <input type="submit" value="전송" />
      
      </form>

</body>
</html>

 

 

 

<title>upload pro</title>
</head>
<%
   request.setCharacterEncoding("UTF-8");
   /*  MultipartRequest 객체 생성시, 필요한 인자들.
   
      1. request 내장 객체 (jsp에 이미 있다)
      2. 업로드 될 파일 저장 경로 
      3. 업로드 할 파일 최대 크기
      4. 인코딩 타입 : UTF-8
      5. 업로드된 파일 이름이 같을경우, 덮어씌우기 방지 객체
      
      */

   // 2. 브라우저에서 보낸 파일 저장할 서버측의 저장 경로
   // 2-1. PC에 저장(서버쪽X, 서버가 있는 내PC에 저장)
   //String path = "C:\\tmp\\"; (pc에 올리면 웹페이지상에서 볼수가없다 )
   
   // 2-2 서버상에 저장
   String path = request.getRealPath("save"); // 서버상의 save 폴더 실제 경로 찾기
   System.out.println(path);
   // 3. 업로드 할 파일 최대 크기
   int max = 1024*1024*5;   // 5mb
   //4. 인코딩
   String enc = "UTF-8";
   // 5. 덮어씌우기 방지 객체
   DefaultFileRenamePolicy dp = new DefaultFileRenamePolicy();
   
   // MultipartRequest 객체 생성
   MultipartRequest mr = new MultipartRequest(request, path, max, enc, dp);
   
   // 파라미터 받기
   String writer = mr.getParameter("write");
   String sysName = mr.getFilesystemName("upload");   // 업로드 파일 이름
   String orName = mr.getOriginalFileName("upload");   // 파일 원본 이름
   String contentType = mr.getContentType("upload");   // 파일 종류 : 사진, 글....
   
   
   // DB에 저장
   UploadDAO dao = new UploadDAO();
   dao.insertData(writer,sysName);
   
   
   
%>
<body>

   <h2>작성자 : <%=writer%> </h2>
   <h2>업로드 파일명 : <%=sysName%></h2>
   <h2>파일 원본이름 : <%=orName%></h2>
   <h2>컨텐트 타입(파일종류) : <%=contentType%></h2>
	
	<img src="/web/save/<%=sysName%>" width="300px"/>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
	<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
	<br />
	<h1 align="center"> 메인 페이지 </h1>
	
	<% 
	if(session.getAttribute("memId") == null){ // 로그인 안했을때 
		
		// 쿠키가 있는지 검사 
		String id = null, pw = null, auto = null; 
		Cookie[] coos = request.getCookies(); 
		if(coos != null){
			for(Cookie c : coos) {
				// 쿠키가 있다면 쿠키에 저장된 값꺼내 변수에 담기
				if(c.getName().equals("autoId")) id = c.getValue();   
				if(c.getName().equals("autoPw")) pw = c.getValue();
				if(c.getName().equals("autoCh")) auto = c.getValue(); 
			}
		}
		
		// 세개 변수에 값이 들어있을 경우 (쿠키 제대로 생성되서 다 갖고 있다.)
		if(auto != null && id != null && pw != null){
			// 로그인 처리되도록 loginPro.jsp 처리 페이지로 이동시키기 
			response.sendRedirect("loginPro.jsp");
		}
		
		// 위 코드 다 지나치면, 
		// session에 memId속성도 없고, 쿠키도 없으니 로그인 버튼 보여주기
	%>
	<table>
		<tr>
			<td> 로그인을 원하시면 버튼을 누르세요 <br />
				<button onclick="window.location='loginForm.jsp'"> 로그인 </button>
			</td>
		</tr>
		<tr>
			<td> 
				<a href="signupForm.jsp"> 회원 가입 </a>
			</td>
		</tr>
	</table>
	<%}else{ // 로그인 했을때  %>
	<table>
		<tr>
			<td> <%=session.getAttribute("memId") %> 님 환영합니다. <br />
				<button onclick="window.location='mypage.jsp'"> 마이페이지 </button>
				<button onclick="window.location='logout.jsp'"> 로그아웃 </button>
			</td>
		</tr>
	</table>
	<%} %>
	
	
	<br /><br />
	<div align="center">
		<img src="img/ham.jpg" width="400px" />
	</div>

</body>
</html>
<%@page import="web.jsp07.model.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>loginPro</title>
</head>
<%
	// loginForm -> Pro (파라미터 들고옴)
	// main -> pro 쿠키들고 (파라미터 X)

	request.setCharacterEncoding("UTF-8"); // 한글깨짐 방지
	// 넘어온 파라미터 꺼내기 (main에서 바로 왔으면 아래 변수 null)
	String id = request.getParameter("id");
	String pw = request.getParameter("pw");
	String auto = request.getParameter("auto");
	
	// 쿠키를 꺼내서 정보가 나오면 위 변수에 저장 
	Cookie[] coos = request.getCookies(); 
	if(coos != null){
		for(Cookie c : coos){
			if(c.getName().equals("autoId")) id = c.getValue();
			if(c.getName().equals("autoPw")) pw = c.getValue();
			if(c.getName().equals("autoCh")) auto = c.getValue();
			System.out.println(c.getName() + c.getValue());
		}
	}

	MemberDAO dao = new MemberDAO(); 
	boolean result = dao.idPwCheck(id, pw); 
	
	if(result){ // id, pw 일치 : 로그인 상태로 만들기 
		// 자동로그인이면 쿠키도 생성 
		if(auto != null){ // 자동로그인 체크했다.
			Cookie c1 = new Cookie("autoId", id);
			Cookie c2 = new Cookie("autoPw", pw);
			Cookie c3 = new Cookie("autoCh", auto);
			c1.setMaxAge(60*60*24); // 24시간
			c2.setMaxAge(60*60*24); // 24시간
			c3.setMaxAge(60*60*24); // 24시간
			response.addCookie(c1);
			response.addCookie(c2);
			response.addCookie(c3);
		}
	
		session.setAttribute("memId", id); 
		response.sendRedirect("main.jsp"); // 메인으로 이동 
	}else{ %>
		<script>
			alert("아이디 또는 비밀번호가 맞지 않습니다..."); 
			history.go(-1);
		</script>
	<%} %>

<body>

</body>
</html>
<%@page import="web.jsp07.model.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>signupPro</title>
</head>
<%  request.setCharacterEncoding("UTF-8"); // post방식 인코딩 처리  %>
<jsp:useBean id="dto" class="web.jsp07.model.MemberDTO" /> <%-- dto 객체 생성 --%>
<jsp:setProperty property="*" name="dto"/> <%-- 넘어온파라미터 dto에 담기 --%>
<%
	MemberDAO dao = new MemberDAO(); 
	dao.addMember(dto); // 회원 가입 처리 메서드 호출 

	// 메인으로 이동 
	response.sendRedirect("main.jsp"); 
	
%>

<body>

</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>signupForm.jsp</title>
	<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
	<br />
	<h1 align="center"> 회원가입 </h1>
	<form action="signupPro.jsp" method="post">
		<table>
			<tr>
				<td>아이디 *</td>
				<td><input type="text" name="id" /></td>
			</tr>
			<tr>
				<td>비밀번호 *</td>
				<td><input type="password" name="pw" /></td>
			</tr>
			<tr>
				<td>비밀번호 확인 *</td>
				<td><input type="password" name="pwch" /></td>
			</tr>
			<tr>
				<td>이름 *</td>
				<td><input type="text" name="name" /></td>
			</tr>
			<tr>
				<td>성별 </td>
				<td>
					남 <input type="radio" name="gender" value="male" checked />
					여 <input type="radio" name="gender" value="female" />
				</td>
			</tr>
			<tr>
				<td>email</td>
				<td>
					<input type="text" name="email" />
				</td>
			</tr>
			<tr>
				<td colspan="2">
					<input type="submit" value="회원 가입" />
					<input type="reset" value="재작성" />
					<input type="button" value="취소" onclick="window.location='main.jsp'" />
				</td>
			</tr>
		</table>
	</form>


</body>
</html>

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> loginForm.jsp </title>
  <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
   <br />
   <form action="loginPro.jsp" method="post">
   <h2 align="center"> 로그인 </h2>
   <table>
      <tr>
         <td>아이디</td>
         <td><input type="text" name="id"></td>
      </tr>
      <tr>
         <td>비밀번호</td>
         <td><input type="password" name="pw"></td>
      </tr>
      <tr>
         <td colspan="2"><input type="checkbox" name="auto" value="1" /> 자동로그인</td>
      </tr>
      <tr>
         <td colspan="2">
         <input type="submit" value="로그인" />
         <input type="button" value="회원가입"  onclick="window.location='signupForm.jsp'"/>
         </td>
      </tr>
   
   </table>
   </form>

</body>
</html>

- 자바

 

package web.jsp07.model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class MemberDAO {

	   	// 커넥션 메서드 
		private Connection getConnection() throws NamingException, SQLException {
			Context ctx = new InitialContext(); 
			Context env = (Context)ctx.lookup("java:comp/env");
			DataSource ds = (DataSource)env.lookup("jdbc/orcl"); 
			return ds.getConnection(); 
		}
		//회원가입 처리
		public void addMember (MemberDTO dto) {
			Connection conn = null; 
			PreparedStatement pstmt = null; 
			ResultSet rs = null; 
			
			try {
				conn = getConnection(); // Naming/SQLException 발생가능 
				String sql = "insert into member values(?,?,?,?,?,sysdate)";
				// 커넥션으로 준비한 쿼리문 주고 실행기능 갖는 pstmt 리턴받기 (쿼리문 준비)
				pstmt = conn.prepareStatement(sql);
				pstmt.setString(1, dto.getId());
				pstmt.setString(2, dto.getPw());
				pstmt.setString(3, dto.getName());
				pstmt.setString(4, dto.getGender());
				pstmt.setString(5, dto.getEmail());
			
			
				int result  = pstmt.executeUpdate(); 
				System.out.println("insert result : " + result);
			
			
				
			}catch(Exception e) { // Naming/SQLException 발생했을때 둘다 받아줄 부모로 처리 
				e.printStackTrace();
			}finally {
				
				if(pstmt != null) try { pstmt.close(); } catch(SQLException e) { e.printStackTrace(); }
				if(conn != null) try { conn.close(); } catch(SQLException e) { e.printStackTrace(); }
			}
			
		}
			
		// 로그인 : id, pw 맞는지 체크해서 결과 돌려주는 메서드
		//			id,pw 맞으면 true, 둘중하나라도 틀리거나 없으면 false
		public boolean idPwCheck(String id, String pw) {
			System.out.println("idPwCheck 호출!");
			boolean result = false; // 최종 결과 리턴해줄 변수 미리 선언
			Connection conn = null; 
			PreparedStatement pstmt = null; 
			ResultSet rs = null; 
			
			try {
				conn = getConnection(); // Naming/SQLException 발생가능 
				String sql = "select * from member where id =? and pw =?";
				pstmt = conn.prepareStatement(sql);
				pstmt.setString(1, id);
				pstmt.setString(2, pw);
				
				rs = pstmt.executeQuery(); 
				// rs에 돌려받은 결과에 따라 result 변수값 변경 
				if(rs.next()) {
					System.out.println("rs.next() -> true");
					result = true;
				}
				
			}catch(Exception e) { // Naming/SQLException 발생했을때 둘다 받아줄 부모로 처리 
				e.printStackTrace();
			}finally {
				if(rs != null) try { rs.close(); } catch(SQLException e) { e.printStackTrace(); }
				if(pstmt != null) try { pstmt.close(); } catch(SQLException e) { e.printStackTrace(); }
				if(conn != null) try { conn.close(); } catch(SQLException e) { e.printStackTrace(); }
			}
			return result; // result변수에 들어있는 결과 리턴 
		}
	}

- 자바

package web.jsp07.model;

import java.sql.Timestamp;

public class MemberDTO {
				private String id;
				private String pw;
				private String name;
				private String gender;
				private String email;
				private Timestamp reg;
			
				
				public String getId() {
					return id;
				}
				public void setId(String id) {
					this.id = id;
				}
				public String getPw() {
					return pw;
				}
				public void setPw(String pw) {
					this.pw = pw;
				}
				public String getName() {
					return name;
				}
				public void setName(String name) {
					this.name = name;
				}
				public String getGender() {
					return gender;
				}
				public void setGender(String gender) {
					this.gender = gender;
				}
				public String getEmail() {
					return email;
				}
				public void setEmail(String email) {
					this.email = email;
				}
				public Timestamp getReg() {
					return reg;
				}
				public void setReg(Timestamp reg) {
					this.reg = reg;
				}
			
}

 

create table member( --테이블 만들기
    id varchar2(50) primary key,
    pw varchar2(50) not null,
    name varchar2(20) not null,
    gender varchar2(20),
    email varchar2(50),
    reg date default sysdate
);
desc member;  -- 테이블(맴버)참조
commit; -- 커밋
select * from member;  -- 출력용

진행 순서 
1) 회원가입에 필요한 항목을 DB 테이블 만들기

2) Member DTO로 변수와 get/set메서드 만들기  

 3) Member DAO 만들기 

 

1 - DB와 연결하는 메서드

2 - 회원가입에 필요한 메서드
받은값들을 연결된 DB에 차례대로 넣어주는 메서드

3 - 로그인에 필요한 메서드 생성 
Id 와 PW가 db값과 같은지 체크하는 메서드


 4) loginForm 만들기 

 

1 - 폼, 액션태그와 input에 변수들 넣어주기
2 - 폰트, 이미지등 CSS스타일 관리 
3 - 로그인, 회원가입 관리 
<form action="태그.jsp" method="post"> 또는 onclick을 이용하여 페이지 이동 만들기
로그인 -> login Pro로 이동
회원가입 -> signupForm 으로이동

 

 

 


   4) -  1 <회원가입 폼 (signup Form)>      

    4)에서 회원가입을 눌렀을때 실행 

 

1 - loginForm 과 유사함
2  -<form action="태그.jsp" method="post"> 
또는 onclick을 이용하여 페이지 이동 만들기
회원가입 -> signup Pro로 이동
취소버튼 -> main 으로이동(로그아웃상태)

 

 

 


     4) -  1  - 1  회원가입 처리폼 (Signup Pro)

 

 1-  DTO 객체 생성후 넘어온 파리미터를 DTO에 담아줌
 2-  DAO 객체 생성후 회원가입 메서드 작동
 3-  main 으로 이동(로그인상태)

 

 

 


4) - 2 로그인 처리폼(login Pro)

 

login Pro에 오자마자 파라미터꺼냄 
쿠키있으면 변수생성     

DAO 객체 생성하여 3) -1 에 로그인에 필요한 메서드 실행

 

 

 <1- 메서드가 실행되어 ip/ pw가 일치하는 경우>

                      ●a -  auto가 null이 아니다! (자동로그인체크)
                                -> 쿠키 객체 생성하고 유효시간과 쿠키값주고 세션 속성값 주고
                                       main으로 보냄(로그인 상태)
 

                      ●b -  auto 가 null 이면
                                     -> 세션 속성값만 주고 바로 
                                           main으로 보냄(로그인 상태) 


** 세션 속성값 -> 난 로그인처리를 했어!

 <2 - 메서드가 실행되었는데 ip/ pw가 일치하는 않는 경우>
 경고창 띄우고 
한칸 뒤로 (history.go(-1) 실행

 


   5 메인 폼 (Main Form)   만들기 

 

 <1 -   세션 속성값이 없을때> (login Pro를 통해 온게 아님-> 로그인으로 온게아님) 
             
              a  -         쿠키가 있다 ->  login pro로 보내줌 (자동로그인 체크한 경우이니 로그인 처리가 되도록)
                             login pro에서 
                                       유효시간, 쿠키값, 세션 속성값 주면서
                                       main으로 보냄
 
              b  -         쿠키가 없다 -> login Form으로 보냄 



< 2 -   세션 속성값이 있다> (login pro에서 들어온거임)(자동로그인x 로그인)

 

+ Recent posts