본문 바로가기
오늘은 뭘 배울까?/etc

자바로 셀레니움(Selenium)을 써보자 :: 크롤링

by Kim Juhwan 2020. 12. 25.

1. 셀레니움이란?
2. 셀레니움 사용법
    2-1. Chrome 버전 확인
    2-2. Chrome WebDriver 다운로드
3. 웹페이지 분석
4. 코드 작성
5. 크롤링
    5-1. 셀레니움으로 크롤링을 하는 이유
    5-2. 정적 페이지? 동적 페이지?
    5-3. 동적 페이지 확인하기
    5-4. 크롤링 하기
6. 부록
    6-1. robot.txt
    6-2. 로봇 접근을 비허용 한다면?
    6-3. 셀레니움은 크롤링에 적합한 도구인가?

 


 

1. 셀레니움이란?

 

https://www.youtube.com/watch?v=uUIFN0mHpE4

 

내가 즐겨보는 유튜버 '노마드 코더'님이 위와 같은 영상을 올린 적이 있다.

인스타그램 댓글과 게시물을 자동으로 달아주는 봇을 만드는 내용이었는데

저 영상을 보면서 '우워어어어 개쩐다 자동화 봇을 만든다고?' 이런 생각을 했다.

이때 셀레니움에 대해서 처음 듣게 되었다. 그래서 나는 봇을 만들 때 사용하는 거구나 정도만 알고 있었는데

이번에 공부를 하면서 한 번 사용해보았다.

 

 

  • 웹 사이트를 테스트할 때
  • 봇을 만들 때 (자동댓글 봇, 구독자 수 늘리기 봇 이런 거...)

 

조사해 본 결과 셀레니움을 위와 같이 활용될 수 있는 프레임워크이다.

사실 원래 목적은 웹 사이트를 테스트하기 위해 개발된 건데

인터넷에 검색하면 봇을 만드는데 많이 사용되고 있다.

아무튼 셀레니움을 이용하면 내가 직접 마우스로 브라우저를 클릭하고 네이버에 들어가서 아이디 비번을 치고 로그인을 누르고 이런 작업을 안 해도 된다는 거다! 셀레니움으로 만든 프로그램이 대신해줄 거니까!

 

 

2. 셀레니움 사용법

2-1. Chrome 버전 확인

브라우저 열기 - 설정 - 도움말 - Chrome 정보

 

셀레니움을 사용하기 전에 해야 할 것이 있다.

우선 사용할 브라우저를 정해야 하는데 나는 크롬을 사용하기로 했다.

그리고 브라우저 버전을 알아내야 한다. 위 그림처럼 따라 들어가면

 

 

크롬 버전 87.0.4280.88

이렇게 자신이 설치한 크롬의 버전을 알 수 있다.

 

 

2-2. Chrome WebDriver 다운로드

http://chromedriver.chromium.org/downloads

 

이제 WebDriver를 설치해주어야 한다.

이때 2-1에서 확인한 자신의 크롬 버전과 맞는 드라이버를 설치해주어야 한다.

그리고 만약 크롬이 아닌 다른 브라우저를 이용하기로 했다면 그 드라이버를 설치해주어야 한다.

다운로드한 exe파일은 실행하지 말고 잘 가지고 있다가 4-1에서 사용하면 된다.

 

 

3. 웹 페이지 분석

네이버 사이트에서 F12를 누르면 HTML 코드를 볼 수 있다.

 

어렸을 때 인터넷을 하다가 키보드를 잘못 눌러 이런 창이 뜨면

뭐 잘못된 줄 알고 화들짝 놀라서 인터넷을 껐던 기억이 있다.

뭐 암튼.. F12를 누르면 웹 페이지가 어떻게 작성되었는지 코드를 볼 수 있다.

 

나는 네이버 아이디랑 비밀번호를 자동으로 입력하고 로그인까지 하는 프로그램을 만드려고 한다.

그러기 위해서 저기 저 'NAVER 로그인'이라는 버튼의 ID가 무엇인지 알아내야 한다.

 

 

 

 

상단에 있는 저 버튼을 클릭하면 아주 쉽게 ID를 알아낼 수 있다.

일단 클릭

 

 

 

그다음 ID를 알아내고 싶은 곳을 클릭하면 파란색 박스로 그에 해당하는 코드를 보여준다.

 

<a href="https://nid.naver.com/nidlogin.login?mode=form&amp;url=https%3A%2F%2Fwww.naver.com" class="link_login" data-clk="log_off.login">...</a></a>

 

이렇게 적혀있다.

웹 프로그래밍을 배우지 않았다면 이게 왠 외계어인가 싶겠지만... 우리가 필요한 건 ID다.

어디 보자...

???????????? 아니 세상에 ID가 없다.

그렇다면 class 이름을 사용하면 된다. 여기서는 link_login이 클래스 이름이다.

값을 찾는데 꼭 ID가 필요한 건 아니고 element를 구분할 수 있는 지표가 필요한 것뿐이니...

 

 

 

다행히도 link_login이라는 이름의 클래스는 이 버튼에서만 쓰인다.

 

Ctrl + F를 눌러 클래스 이름을 검색해보자.

ID는 유일한 값이지만 class 이름은 중복될 수 있으니 검색을 해보고

만약 한 군데에서만 쓰이면 그냥 이걸로 사용하면 된다.

 

 

 

4. 코드 작성

public class NaverLogin {

	private WebDriver driver;
	private WebElement element;
	private String url;
	
 	// 1. 드라이버 설치 경로
	public static String WEB_DRIVER_ID = "webdriver.chrome.driver";
	public static String WEB_DRIVER_PATH = "C:/chromedriver/chromedriver.exe";
	
	public NaverLogin (){
		// WebDriver 경로 설정
		System.setProperty(WEB_DRIVER_ID, WEB_DRIVER_PATH);
				
		// 2. WebDriver 옵션 설정
		ChromeOptions options = new ChromeOptions();
		options.addArguments("--start-maximized");
		options.addArguments("--disable-popup-blocking");
        
		driver = new ChromeDriver(options);
		
		url = "https://www.naver.com/";
	}
	
	public void activateBot() {
		try {
			driver.get(url);
			Thread.sleep(2000); // 3. 페이지 로딩 대기 시간
			
			// 4. 로그인 버튼 클릭
			element = driver.findElement(By.className("link_login"));
			element.click();
			
			Thread.sleep(1000);
			
			// ID 입력
			element = driver.findElement(By.id("id"));
			element.sendKeys("아이디입니다");
			
			// 비밀번호 입력
			element = driver.findElement(By.id("pw"));
			element.sendKeys("비밀번호입니다");
			
			// 전송
			element = driver.findElement(By.className("btn_global"));
			element.submit();
		}catch (Exception e) {
			e.printStackTrace();
		} finally {
			driver.close(); // 5. 브라우저 종료
		}
	}
	
	public static void main(String[] args) {
		NaverLogin bot1 = new NaverLogin();
		bot1.activateBot();
	}
}

 

# 주석 1.

3-1에서 받은 Chrome Driver 파일의 위치를 지정한다.

위 코드에서 지정한 경로의 의미는 C드라이브 밑에 chromedriver폴더 밑에 있는 chromedriver.exe파일 이라는 뜻이다.

 

# 주석 2.

드라이버의 옵션을 설정해준다.

여러 가지 옵션이 있지만 코드에서 사용한 것은 브라우저를 최대 크기로 실행하기와 팝업 창 무시하기이다.

다른 옵션들을 사용하면 브라우저를 실행하고 동작하는 데 걸리는 딜레이를 줄일 수 있다 (속도 개선)

 

# 주석 3.

브라우저를 열고 사이트에 접속하는데 은근 시간이 걸린다.

그래서 창이 다 뜨기까지 시간을 벌기 위해 강제로 2초간 동작을 멈추게 하였다.

 

# 주석 4.

메서드 설명
driver.findElement(By.className("    ")) 클래스 이름으로 element 찾기
driver.findElement(By.id("    ")) 아이디로 element 찾기
click() 버튼 클릭
sendKeys(str) 텍스트 입력
submit() 서버로 전송 (제출)

 

# 주석 5.

할 일을 다 마치면 브라우저를 종료한다.

브라우저를 종료하고 싶지 않다면 이 부분을 삭제하면 된다.

 

 

 

5. 크롤링

5-1. 셀레니움으로 크롤링을 하는 이유

동적 페이지는 HTML을 긁어온다고 해서 원하는 데이터를 얻을 수가 없다. 딱 그 부분만 그냥 텅 비어있을 것이다.

사용자가 직접 요청을 하면 그제야 동적 페이지가 완성되기 때문에

단순히 HTML을 긁어오는 것으로는 크롤링이 불가능하다.

그렇기 때문에 나 대신 브라우저를 띄워 요청을 해줄 셀레니움을 사용하는 것이다.

 

(2021.02.20 추가)

웹에 대해 지식이 부족하다보니 헛소리를 많이 적어놨는데...

셀레니움으로 크롤링을 하는 이유는 로그인 해야만 볼 수 있는 페이지를 긁어온다거나 할 때 사용하기 위해서이다.

동적 페이지라고 할지라도 HTTP request를 이용하면 원하는 값을 가져올 수 있다.

 

 

5-2. 정적 페이지? 동적 페이지?

정적 페이지란 사용자가 웹 페이지에 접속했을 때(= 요청을 보냈을 때)

추가적인 처리과정 없이 보여주는 페이지를 말하며

 

동적 페이지란 사용자가 웹 페이지에 접속했을 때(= 요청을 보냈을 때)

요청에 따른 추가적인 처리과정을 거쳐 보여주는 페이지를 말한다.

 

스크롤을 내릴 때마다 게시글들을 추가적으로 보여준다거나

댓글 더보기를 누르면 일정 개수의 댓글을 추가적으로 보여주는 등

사용자의 요청에 따라 그때그때 페이지의 내용이 바뀌는 것동적 페이지라 할 수 있다.

 

 

 

5-3. 동적페이지 확인하기

 

F12를 눌러 톱니바퀴를 클릭한다.

 

 

 

 

Preferences - Debugger - Disable JavaScript를 클릭한다.

 

 

 

 

이제 F5를 누르면 아무것도 없는 빈칸으로 보이는 부분이 있다.

검색어 순위, 광고 배너 등...

이런 부분이 바로 동적 페이지이다.

HTML을 긁어오면 저 부분에 해당하는 부분에 아무런 정보가 담겨있지 않다는 것이다.

저 부분을 크롤링하기 위한 방법 중 하나로 셀레니움을 사용할 수 있는 것이다.

 

 

 

5-4. 크롤링 하기

멜론 인기차트

 

크리스마스에 이러고 있는 불쌍한 내 인생...

멜론 홈페이지에서는 좋아요 수를 동적으로 관리하고 있다.

5-3에서 설명한 방법을 사용하면 모든 노래의 좋아요 수가 0으로 나오는 것으로 알 수 있다.

1위 노래의 노래 제목과 좋아요 수를 가져오려고 한다.

 

 

XPath 알아내기

 

3-1에서는 id나 클래스 이름을 이용해 파싱 하는 것을 다루었는데

사실 XPath를 이용해서도 파싱을 할 수 있다.

우측 클릭 - Copy - Copy full XPath를 클릭하면

 

/html/body/div/div[3]/div/div/div[3]/form/div/table/tbody/tr[1]/td[4]/div/div/div[1]/span/a

 

대충 이런 형태의 XPath가 복사되는데

웹에 대한 게시물이 아니므로 자세한 설명은... 생략

 

(2021-01-02 추가)

Copy full XPath로 하면 상황에 따라 안되는 경우가 종종 있어서

(댓글이 없을때랑 댓글이 있을때랑 html 구조가 다르다던지 등)

Copy XPath를 하는 게 맞는 것 같다.

 

 

public class melonBot {

	private WebDriver driver;
	private WebElement element;
	private String url;

	public static String WEB_DRIVER_ID = "webdriver.chrome.driver";
	public static String WEB_DRIVER_PATH = "C:/chromedriver/chromedriver.exe";

	public melonBot() {
		// WebDriver 경로 설정
		System.setProperty(WEB_DRIVER_ID, WEB_DRIVER_PATH);

		// WebDriver 옵션 설정
		ChromeOptions options = new ChromeOptions();
		options.addArguments("--disable-popup-blocking");

		driver = new ChromeDriver(options);

		url = "https://www.melon.com/chart/index.htm";
	}

	public void activateBot() {
		try {
			driver.get(url);

			Thread.sleep(2000);

			// 곡 제목 파싱
			element = driver.findElement(By.xpath("/html/body/div/div[3]/div/div/div[3]/form/div/table/tbody/tr[1]/td[4]/div/div/div[1]/span/a"));
			String title = element.getAttribute("title");

			// 좋아요 수 파싱
			element = driver.findElement(By.xpath("/html/body/div/div[3]/div/div/div[3]/form/div/table/tbody/tr[1]/td[6]/div/button/span[2]"));
			String cntLike = element.getText();
			
			System.out.println("1위 노래는 [" + title + "]입니다.");
			System.out.println("좋아요 수는 [" + cntLike + "]입니다.");
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			driver.close();
		}
	}

	public static void main(String[] args) {
		melonBot bot1 = new melonBot();
		bot1.activateBot();
	}
}

 

이전 코드에서는 element를 By.id와 By.className으로 찾았는데 이번에는 By.xpath로 찾았다.

편한 방법으로 사용하면 될 것 같다.

 

 

 

6. 부록

6-1. robot.txt

셀레니움으로 크롤링하는 것은 보다시피 굉장히 쉽다.

근데 정보가 돈이 되는 이 시대에 이렇게 남의 사이트에서 정보를 마구 긁어와도 되는 것일까?

정답은 "아니다."이다.

 

https://www.google.com/robots.txt
www.naver.com/robots.txt
https://www.melon.com/robots.txt

 

사이트별로 로봇의 접근을 허용하는 곳도 있고, 부분적 허용하는 곳도 있고, 막는 곳도 있다.

그래서 모든 사이트들은 접근에 대한 내용을 robot.txt라는 파일 안에 적어둔다.

이 파일은 사이트 주소 뒤에 /robot.txt를 붙이면 확인할 수 있다.

 

 

 

 

구글 사이트의 robots.txt

 

이런 내용의 텍스트들을 확인할 수 있는데

로봇의 접근을 허용하는 경로는 Allow

허용하지 않는 경로는 Disallow에 적어둔다.

 

자세한 해석 방법은 위키백과에 적혀있다.

 

로봇 배제 표준 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 로봇 배제 표준(robots exclusion standard), 로봇 배제 프로토콜(robots exclusion protocol)은 웹 사이트에 로봇이 접근하는 것을 방지하기 위한 규약으로, 일반적으로 접근

ko.wikipedia.org

 

 

 

6-2. 로봇 접근을 비허용 한다면?

크롤링을 해보면 알겠지만, 사실 robots.txt에 "로봇의 접근을 금지합니다!"라고 적어놔도 접근이 가능하다.

robots.txt, 즉 로봇 배제 표준은 권고안이기 때문이다.

 

 

 

robots.txt는 어떻게 보면 경고문...

 

그렇다면 무시하고 크롤링을 해도 되느냐..? 그건 아니다.

만약 회사에서 인력과 자금을 투자해 모은 정보를 경쟁사에서 쏙 빼간다면 문제가 될 것이다.

실제로 그렇게 해서 유죄를 받은 판례도 있다.

 

학생이 공부를 하기 위해 크롤링을 하는 것은 서버에 부하를 일으키지도 않을 거고 이익을 창출하지도 않을 것이다.

이런 경우 나는 "윤리를 지키는 내에서 사용하는 것은 문제가 없다."라고 말하고 싶다.

어쨌든 하지 말라고 했으면 안 하는 것이 원칙이긴 하다.

판단은 본인의 몫이고, 책임도 본인의 몫이다.


(2021.02.08 내용 추가)

토이 프로젝트를 진행하면서 학교 사이트를 크롤링했다.

오늘 학교 담당 부서에 전화해서 문의를 드려보니 썩 내키지 않아 하시는 반응이었다.

"안된다!"라고 말씀하시진 않았지만 "안 하는 걸 권장드리고 싶다"정도로 정중히 말씀해주셨다.

나는 재학생이기도 하고 공개되어있는 공지사항 정도만 긁어오는 거라 허락해주실 거라 생각했는데 반응이 달라서 당황했다.

이야기를 들어보니 몇 년 전 나처럼 비슷한 걸 시도한 학생이 있었는데

협조를 해줬다가 뭔가 문제가 생긴 적이 있었나 보다.

만약 사용을 원하시면 학과장님을 통해 연락 주시면 감사드리겠다고 말씀해주셨다.

학교 사이트는 혹시라도 크롤링한 정보를 오용/남용 했을 때 학교 이미지에 누가 될 수도 있기 때문에

더욱 예민할거라는 생각이 뒤늦게야 들었다. (프로젝트 이제야 다 완성했는데 세상에나)

 

결론은... 사이트 담당자한테 먼저 물어보자..

 

 

 

6-3. 셀레니움은 크롤링에 적합한 도구인가?

셀레니움을 사용해보면 알겠지만 굉장히 느리다.

당장 구글에만 검색해도 셀레니움을 이용하는 방법이 가득하다.

이렇게 느린데 왜 사용할까에 대해 궁금해서 검색을 해보았다.

 

 

OKKY | 크롤링 관련 셀레니움 등에 대해서 질문 있습니다.

안녕하십니까. 자바 Jsoup을 이용해서 크롤링 하려다보니 스크립트로된 파일들은 크롤링이 되지 않는다는걸  알게됐습니다. 셀레니움을 이용하면 이 문제를 해결할 수 있다고 하는데  셀레니움

okky.kr

 

 

Selenium 크롤링을 해보며 느낀 점

Selenium의 장점 실제 브라우저를 실행 시켜서 돌아가기 때문에, 웹페이지에 구현된 정적인 페이지뿐만 아니라, 동적인 페이지까지 긁어낼 수 있다. 그래서 느리다. 디버깅 시, 브라우저에서 눈으

pcmc.tistory.com

 

정적 페이지로만 이루어진 부분은 HTML을 긁어와 처리하고

셀레니움을 꼭 이용해야 하는 부분은 headless와 같은 드라이버 옵션을 이용해서

속도를 개선하는 것이 최선일 것 같다.

반응형

댓글