Selenium은 웹 드라이버를 통해 웹 브라우저를 자동화하여 웹 테스트를 도와주는 툴이다. 말은 착하지만 매크로를 만들거나 크롤링 할때도 도움이 된다. ^^ 실제 브라우저를 띄우고 코드를 수행할 수 있으며, 일반적으로 크롤링 하는 방식보다 훨씬 더 상호작용을 사람같이! 할 수 있다. 페이지가 다 뜰때까지 기다리고, 클릭하고, 입력하는 등...
그러면 Node.js 에서 selenium을 사용하는 방법을 익혀보자.
패키지 설치
먼저 selenium-webdriver 패키지를 설치해야한다.
npm i selenium-webdriver
파이어 폭스 브라우저로 Selenium을 실행해야 할 경우, geckodriver를 설치해야한다.
npm i geckodriver
실행환경이 Ubuntu일 경우 geckodriver 설치는 다음과 같이한다.
wget https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-linux32.tar.gz
tar -xvzf geckodriver-v0.24.0-linux32.tar.gz
chmod +x geckodriver
코드 작성
세팅이 끝났으니, selenium으로 네이버를 실행하고 종료하는 코드를 작성 해 보겠다. (app.js)
const {Builder, By, Key, until} = require('selenium-webdriver');
(async function example() {
let driver = await new Builder()
.forBrowser('firefox')
.build();
try {
// 네이버 실행
await driver.get('https://www.naver.com/');
}
finally{
driver.quit();
}
})();
node app.js
를 실행해보면 Firefox 브라우저가 열리고, 네이버에 접속 후 창이 꺼질 것이다.
그럼 유용한 메소드 전부를 활용해서 네이버 검색어 결과를 추리는 코드를 작성 해 보겠다.
세부 사항은 주석을 참조하면된다.
- Input에 텍스트 입력하기
- 요소 클릭하기
- Loop를 돌며 Element 내용 읽기
const {Builder, By, Key, until} = require('selenium-webdriver');
(async function example() {
let driver = await new Builder()
.forBrowser('firefox')
.build();
try {
// 네이버 실행
await driver.get('https://www.naver.com/');
// Javascript를 실행하여 UserAgent를 확인한다.
let userAgent = await driver.executeScript("return navigator.userAgent;")
console.log('[UserAgent]', userAgent);
// 네이버 검색창의 id는 query이다. By.id로 #query Element를 얻어온다.
let searchInput = await driver.findElement(By.id('query'));
// 검색창에 '회 숙성하는 법'을 치고 엔터키를 누른다.
let keyword = '회 숙성하는 법'
searchInput.sendKeys(keyword, Key.ENTER);
// css selector로 가져온 element가 위치할때까지 최대 10초간 기다린다.
await driver.wait(until.elementLocated(By.css('#header_wrap')), 10000);
// total_tit라는 클래스 명을 가진 element들을 받아온다.
let resultElements = await driver.findElements(By.className('total_tit'));
console.log('[resultElements.length]', resultElements.length)
// 검색 결과의 text를 가져와서 콘솔에 출력한다.
console.log('== Search results ==')
for (var i = 0; i < resultElements.length; i++) {
console.log('- ' + await resultElements[i].getText())
}
// 검색결과의 첫번째 링크를 클릭한다.
if (resultElements.length > 0) {
await resultElements[0].click();
}
// 4초를 기다린다.
try {
await driver.wait(() => { return false; }, 4000);
} catch (err) {
}
}
finally{
// 종료한다.
driver.quit();
}
})();
크롤링에 자주 쓰이는 메소드들은 거의 나온것 같다! 이 코드를 실행시키면, 네이버에 회 숙성하는 법을 검색하고 제일 첫번째 글을 클릭한뒤, 종료하게 된다. 실행시 로그는 다음과 같다.
[UserAgent] Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:83.0) Gecko/20100101 Firefox/83.0
[resultElements.length] 11
== Search results ==
- 입질의 추억 :: 생선회를 숙성하는 방법(숙성회를 먹는 이유) - 입질의 추억
- 다시마 숙성회, 광어 곤부지메 만드는 방법
- 참돔 숙성회 만드는 방법
- 생선회 맛있게 먹는법!! Part.4 숙성회가 맛있는 이유
- 사가정 맛집 도미회가 맛있는슌락 맛있는 참돔 마쓰가와 숙성법
- 참치회 인터넷 주문 배송 :: 참치 해동/숙성 하는 법. 참치몰 후기
- 노량진수산시장 모듬회, 숙성회, 방어회 싸게먹는법
- 연남동 맛집, 경양마구로! 숙성시킨 참치회로 만든 회덮밥! 최고! (+ 맛있게 먹는 )
- 연안부두1월제철수산물 10키로이상 특대방어 가격 시세 숙성대방어회먹는법 장군씨푸드
- 연어 숙성 하는법::생연어 곤부지메해서 회 떠먹기
- 이렇게 맛있는 12월의 수산물이라니! 과메기부터 굴, 방어까지 겨울 수산물 레시피
For Non-gui systems
GUI가 없는 Ubuntu등 서버OS에서 이 코드를 실행하려고하면, (내 기억이 맞다면) 아래와 같은 오류가 날 것이다. 이때는 headless 모드로 selenium을 실행시켜 주어야한다. headless로 설정하게 되면 실제 브라우저가 보이지 않는다.
selenium.common.exceptions.WebDriverException: Message: invalid argument: can't kill an exited process
Firefox Options에서 headless 모드를 설정할 수 있다. options에는 이 외에도 다른 유용한 설정을 할 수 있다. 아래는 몇가지 예시다.
const {Builder, By, Key, until} = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');
(async function example() {
let driver = await new Builder()
.forBrowser('firefox')
.setFirefoxOptions(
new firefox.Options()
// headless 모드 사용
.headless()
// 창 크기 설정
.windowSize({
width: 640,
height: 480
})
// custom user agent 설정하기
.setPreference("general.useragent.override", "custom-user-agent")
)
.build();
try {
// ... your code
}
finally{
driver.quit();
}
})();
맺으며
오늘 Selenium을 가지고 놀면서 Cloudflare로 보호되는 웹을 뚫어보려고 삽질을 했는데 결국 실패해서 그냥 저냥 알게된 사용법을 블로그에 올려봤다. ㅠㅠ 그래도 실제 브라우저로 딱딱딱 집어주는 코드를 작성할 수 있다니 다음에 유용한일이 생기겠지...
마지막으로 Javascript용 Selenium document 주소 뿌리고 가겠다.
https://www.selenium.dev/selenium/docs/api/javascript/index.html
'프로그래밍 > JS, Node.js' 카테고리의 다른 글
DOMContentLoaded와 jQuery document.ready()의 중요한 차이점 (0) | 2021.10.31 |
---|---|
React JS 개념 잡기 - 빠르게 한 번 훑어보고 싶다면 (0) | 2021.01.08 |
[해결법] CasperJS: /usr/bin/env: ‘python’: No such file or directory (0) | 2021.01.03 |
Javascript에서 라디안(radian, 호도) 구하는 함수, Math.radians() 만들기 (0) | 2018.10.28 |
[Node.js] Nodemailer로 Gmail 연동하여 이메일 보내기 (0) | 2018.10.03 |