우선 프로그램을 실행할 환경의 '크롬 브라우저 / 크롬 드라이버 / selenium' 3가지의 버전이 서로 호환되도록 세팅해야 한다.
- LINK
- selenium jar 파일 다운로드
- LINK
- chrome driver 파일 다운로드
selenium을 사용한 크롤링은 자바 보다는 파이썬으로 더 많이 구현하는 것 같다.
코드에서 주요한 일부분만 정리하였다.
import java.util.*;
import java.time.*;
import java.nio.file.*;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.*;
import org.openqa.selenium.JavascriptExecutor;
public class getInstagram {
public static final String WEB_DRIVER_ID = "webdriver.chrome.driver";
public static final String WEB_DRIVER_PATH = "C:\\chromedriver.exe";
...(생략)...
List<String> users = Files.readAllLines( Paths.get("D:\\insta_users.txt") );
users = users.stream().map(String::trim).collect(Collectors.toList());
users.removeAll(Arrays.asList("", null));
public static void main(String[] args) throws Exception {
try {
System.setProperty(WEB_DRIVER_ID, WEB_DRIVER_PATH);
} catch (Exception e) {
e.printStackTrace();
}
ChromeOptions options = new ChromeOptions();
options.addArguments("headless"); // GUI 없이 실행
WebDriver driver = new ChromeDriver(options);
드라이버 옵션을 설정하고 로드한다. 중간중간 테스트를 위해서는 headless 옵션을 제거하는게 좋다.
수집 대상 계정명(id)을 텍스트 파일에 라인별로 미리 입력해 두었다.
혹시 공백이 있을지 모르므로 List 전체에서 제거.
String url = "https://www.instagram.com/accounts/login/";
driver.get(url);
try {Thread.sleep(2000);} catch (InterruptedException e) {}
driver.findElement(By.name("username")).sendKeys(USER_ID);
driver.findElement(By.name("password")).sendKeys(USER_PASS);
driver.findElement(By.xpath("//div[text()='로그인']")).click();
try {Thread.sleep(4000);} catch (InterruptedException e) {}
if ( driver.findElements(By.xpath("//button[text()='나중에 하기']")).size() > 0 ) {
driver.findElement(By.xpath("//button[text()='나중에 하기']")).click();
}
sendKeys 메소드는 keyDown과 keyUp을 한번에 처리하는 것이라고 설명되어 있다.
문자열 외에 열거형인 Keys의 상수를 사용하여(Keys.SHIFT, Keys.ARROW_UP 등) 키를 입력할 수 있다.
키보드 조작이 여러 단계를 거쳐야 하는 경우 Actions 클래스를 사용하여 연결할 수 있다.
new Actions( driver ).sendKeys( driver.findElement(By.name("password")), USER_ID).sendKeys(Keys.ENTER).perform();
for (int i=0; i<users.size(); i++ ) {
url = "https://www.instagram.com/" + users.get(i) + "/";
driver.get(url);
System.out.println( driver.getCurrentUrl() );
try {Thread.sleep(2000);} catch (InterruptedException e) {}
// 해당 계정의 메인 페이지가 로딩되기까지 기다린다
new WebDriverWait(driver, Duration.ofSeconds(10)).until( ExpectedConditions.presenceOfElementLocated(By.xpath("//div[@role='tablist']")) );
WebDriverWait 클래스는 지정한 시간만큼 기다리면서 조건을 만족하는지 체크하고, 만족 시 바로 넘어간다.
ExpectedConditions 클래스에서 사용할만한 다른 메서드는 urlToBe, numberOfElementsToBeMoreThan 등이 있다.
JavascriptExecutor js = (JavascriptExecutor)driver;
String href = null;
ArrayList<String> articles = new ArrayList<String>();
int cntScroll = 0;
// 스크롤을 끝까지 내리면서 게시물 URL을 수집한다. 마지막에 도달하면 loading div가 사라진다.
while ( !driver.findElements(By.className("_aanh")).isEmpty() ) {
js.executeScript("window.scrollTo(0, document.body.scrollHeight);");
try {Thread.sleep(1000);} catch (InterruptedException e) {}
List<WebElement> tagA = driver.findElements(By.tagName("a"));
JavascriptExecutor는 자바스크립트를 실행할 수 있는 인터페이스.
계정별 페이지 접속 시 24개의 게시물을 보여주고, 맨 아래까지 스크롤했는데도 게시물이 더 있는 경우 로딩 gif가 표시되면서 12개씩 더 불러오므로, 최초 게시물에 도달하려면 스크롤을 여러 번 해야 한다.
for (int j=0; j<list.size(); j++) {
System.out.println( "downloading...." );
URL urlImage = new URL( list.get(j) );
String fileName = Paths.get(urlImage.getPath()).getFileName().toString();
String USER = users.get(i).replace(".", "_");
File dir = new File("D:/download/" + USER);
if ( !dir.exists() ) {
dir.mkdir();
}
try {Thread.sleep(1000);} catch (InterruptedException e) {}
downloadFile(urlImage, "D:/download/" + USER + "/" + USER + "_" + fileName);
}
계정별로 폴더가 없으면 생성하고 다운로드한다.
참고문헌 및 관련링크.
'코딩 > JAVA & JSP' 카테고리의 다른 글
Eclipse - Spring MVC Project 템플릿 항목이 없는 경우 (0) | 2024.12.03 |
---|---|
Eclipse - 이클립스, JDK, 스프링 STS3 요구(호환) 버전 (0) | 2024.12.03 |
Log4j2 configuration - No log4j2 configuration file found (0) | 2016.09.05 |
JAVA - apache poi 모든 셀 읽기 (0) | 2016.09.05 |
JAVA - apache poi 셀 서식 판단하여 값 읽기 (0) | 2016.08.31 |