Tags crawler
11월 3 2018

AliExpress 크롤링 프로젝트

프로젝트 정보

  • 시작일자 : 2018.11.01

  • 사용언어 : Java, JS(아주 조금)

  • 사용기술

    • JAVAFX
    • JAVA-Maven
    • Selenium
  • 개발목적 : 외주

개발 상황 정보

TODO

DONE

  • UI 디자인
  • Reader 구현
  • Crawler 구현
  • ImageResize Util
  • Image Differ 구현
  • Excel Writer 구현
  • 가격 설정 구현
  • 자동종료 + 재시작
  • 수집 완료시 Modal창
  • 비동기 튜닝

SCREENSHOT

crawler-ui-capture

문제점(?)

  1. thread를 daemon으로 설정하여도, main thread가 종료될 때, finalize를 호출하지 않는 듯 하다. 그래서, selenium과 chromedriver를 이용하는 특성 때문에 직접적으로 reader.exit() 메소드를 호출 한 후에 main thread를 종료하도록 설정하였다.

  2. aliexpress를 js 사용 없이 확인해보면 lazy - loading이 적용되어있는 것을 확인 할 수 있는데, img 태그에 image-src 라는 속성을 잠시동안 줌으로써 page의 빠른 로딩을 꾀하였다.

  3. java의 (iterable.)forEach method는 for문과 같이 동작하는게 아니라서 break를 쓸 수 없다. 그래서 만든것이 RuntimeException을 상속하여 BreakException이라는 custom Exception을 내부적으로 사용했다. Exception이 발생하면 그것을 catch해 forEach구문을 탈출할 수 있게 한 것이다. 이것이 for/while loop + break 와 비교했을 때 어떤 성능저하를 불러올지는 모르겠지만, 편하게 forEach를 사용하기 위해서 꼭 필요한 존재임은 확실하다.

“BreakException.java”

1
2
3
4
5
6
7
8
9
10
package utils;

public class BreakException extends RuntimeException{

private static final long serialVersionUID = -2431473453374656968L;

public BreakException(String arg) {
super(arg);
}
}

“ImageDiffer.java” 중 두 이미지를 비교하는 와중 중복되는 이미지를 발견했을 시 삽입한 코드.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
try {
if (targetImage != null) {
imgs.forEach(imgName -> {
double diffPercent = ImageDiff.getDifferencePercent(imageDiffPath + "\\" + imgName,
targetImage);
if (diffPercent < 10.00) {
throw new BreakException("same img found :: " + imgName);
}
});
passedCount.getAndIncrement();
String name = getNextImgName();
saveImg(imageSavePath, name, targetImage);
saveImg(imageDiffPath, name, targetImage);
imgs.add(name);
d.setMainImg(name);
// System.out.println("DIFF :: " + d);
passedData.add(d);
}
} catch (BreakException e) {
System.out.println(e.getMessage());
continue;
// 같은 이미지 발견
} catch (IOException e) {
e.printStackTrace();
}

  1. javaFX 관련 문제점
    javaFX Thread가 아닌 Thread (따로 작성한 thread class, 익명 thread class 등..) 에서 javaFX UI에 관련된 명령을 실행할 경우

<java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9>

위와 같은 Exception이 발생하게 되어있다. 따라서, 해당 명령을 javaFX Thread가 아닌 곳에서 실행시키고 싶을 경우
다음과 같은 코드로 익명 javaFX thread를 생성 및 실행할 수 있다.

1
2
3
4

Platform.runLater( ()-> { // java lambda expression
doStuffRelatedJavaFx();
});
  1. javaFX application의 재시작 구성

“AECController.java” 에서의 restart() method

1
2
3
4
5
public void restart() {
reader.exit(); // reader 내에 chromeDriver를 다루고 있기 때문에 정상동작을 위해서는 reader를 종료한 후에 동작해야 한다.
saveConfs();
Main.restart();
}

“Main.java” 의 구성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

package application;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.fxml.FXMLLoader;


public class Main extends Application {

private static Stage stage; // stage를 종료하기 위해서는 static으로 설정하는것이 좋다.

@Override
public void start(Stage primaryStage) {
try {
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("ali.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setResizable(false);
stage = primaryStage;
} catch(Exception e) {
e.printStackTrace();
}
}


public static void restart() {
stage.close();
Platform.runLater( ()->{
new Main().start( new Stage() );
});
}

public static void main(String[] args) {
launch(args);
}
}

COMMENT

[2018-11-03] 개발에 지칠땐 포스팅이 최고인듯 하다.
[2018-11-06] 일단 구현하려했던 것들을 모두 구현하였다. 추가적으로 작업할 것은 남아있지만 이 정도 개발속도면 나름 만족스럽다.
[2018-11-27] 마지막으로 기능 추가요청과 함께, 프로그램 사용에 따른 전체 PC 속도 저하문제에 관한 분석 요청을 해주셨는데 그에 따라 단순 multi-threading 을 비동기방식으로 튜닝하여 CPU usage reducing에 성공하였다.

dev
1
Powered by Hexo
Original Theme Weightless
Owner Dev.secr3t