Spring Projcect/배당금 프로젝트

Chapter 02. 스크래핑(Scraping)

계란💕 2022. 9. 12. 18:12

2.1 스크래핑(Scraping)이란?

 

스크래핑(scraping)이란?

  • 웹 스크래핑은 HTML문서를 받은 후, 문서를 파싱(parsing)해서 필요한 데이터만 추출하는 것을 말한다.
  • 자바보다는 파이썬으로 스크래핑을 많이 이용한다.

 

  • 요청 수가 몰리는 경우, 요청을 받는 서버는 부하가 걸릴 수밖에 없다.
    • DDOS 공격이란 서버에 부하를 주면서 트래픽을 폭주 시켜서 서버가 다운되도록 하는 악의적인 공격 방식이다.
    • DDOS(Distribited Denial Of Service, 분산 서비스 거부 공격): 시스템을 악의적으로 공격해서 해당 시스템의 리소스를 부족하게 해서 사용하지 못하도록 하는 공격을 말한다.
    • ex) 대량의 데이터 패킷을 통신망으로 보내고 특정 서버에 수많은 접속 시도를 하는 등 다른 이용자가 정상적으로 서비스 이용을 하지 못하게 하거나 서버의 TCP(Transmission Control Protocol, 전송 제어 프로토콜) 연결을 바닥내는 등의 공격이 DDOS에 해당한다.
  • 따라서, 스크래핑할 때 우리가 요청을 날리는 웹 서버에  부하가 가지 않는 수준으로만 진행해야 한다.
  • 스크래핑을 허용하는 소스인지 아닌지 어떻게 알 수 있을까?
    • 보통 url/robots.txt에 규칙이 정의되어 있다. 만약, 없는 경우에는 보수적인 정책으로 진행한다.
    • allow: 접근을 허용하는 경로는 표시
    • disallow: 접근을 허용하지 않는 경로 표시
    • User-agent: * => 규칙이 모든 로봇에 대해 적용된다는 뜻이다.
  •  루트 경로를 통해 확인 가능하다.   ex) https://www.google.com/robots.txt

 

 

 

2.2 웹 사이트 분석하기

  • 야후 파이낸스
    • 허용 가능한지 확인한다.  https://finance.yahoo.com/robots.txt
    • quote - 배당금 정보를 disallow 한다는 내용 없으니 사용 가능 
    • 그렇지만 서버에 무리가 갈 만큼 요청을 보내면 안 된다.
  • 코카 콜라 배당금 정보를 가져오자.

 

 

 

2.3 스크래핑 구현 (1)

  Ex) 배당금 스크래핑 구현

  • Jsoup으로 가져온다. 웹 사이트에 요청을 보내서 html 문서를 받아온다.
    • JSoup: 커넥션으로부터 html 문서를 받아서 파싱된 형태로 document  인스턴스로 만드는 역할을 하는 Java 라이브러리이다.
    • jsoup.org/apidocs에서 jsoup에 대한 정보 확인 가능
    • getElementsByAttributeValue(String key, String value) 사용
    • Find elements that have an attribute with the specific value.
      • 구체적인 value와 속성을 가지는 element를 찾는다.
    • https://jsoup.org/apidocs/org/jsoup/nodes/Element.html

 

  • 파이낸스 사이트의 표에 대한 html 정보를 보여준다.

 

  • 테이블 정보 가져오기
    • Jsoup.connect("url")하면 url에 연결되고 Connection 인스턴스를 반환한다.
    • 이 때 생성된 connection.get(0)을 하면 HTML 문서 Document가 반환된다.
    • document.getElementsByAttributeValue("data-test", "historical-prices")
<hide/>
package com.dayone;
import java.io.IOException;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SampleApplication {
    public static void main(String[] args) {

        SpringApplication.run(SampleApplication.class, args);

        try {
            Connection connection = Jsoup.connect("https://finance.yahoo.com/quote/COKE/history?period1=99100800&period2=1662940800&interval=1mo&filter=history&frequency=1mo&includeAdjustedClose=true");
            Document document = connection.get();
            Elements eles = document.getElementsByAttributeValue("data-test", "historical-prices");
            Element ele = eles.get(0);  // 여러 개 중에 테이블 하나만 가져온다.
            System.out.println("ele = " + ele);
            
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

  Note) 실행 결과 - 테이블 정보가 나온다.

<hide/>
ele = <table class="W(100%) M(0)" data-test="historical-prices">
 <thead>
  <tr class="C($tertiaryColor) Fz(xs) Ta(end)">
   <th class="Ta(start) W(100px) Fw(400) Py(6px) Pend(6px)"><span>Date</span></th>
   <th class="Fw(400) Py(6px) Pend(6px)"><span>Open</span></th>
   <th class="Fw(400) Py(6px) Pend(6px)"><span>High</span></th>
   <th class="Fw(400) Py(6px) Pend(6px)"><span>Low</span></th>
   <th class="Fw(400) Py(6px) Pend(6px)"><span>Close*</span></th>
   <th class="Fw(400) Py(6px) Pend(6px) Whs(nw)"><span>Adj Close**</span></th>
   <th class="Fw(400) Py(6px) Pend(6px)"><span>Volume</span></th>
  </tr>
 </thead>
 <tbody>
  <tr class="BdT Bdc($seperatorColor) Ta(end) Fz(s) Whs(nw)">
   <td class="Py(10px) Ta(start) Pend(10px)"><span>Sep 01, 2022</span></td>
   <td class="Py(10px) Pstart(10px)"><span>476.89</span></td>
   <td class="Py(10px) Pstart(10px)"><span>480.58</span></td>
   <td class="Py(10px) Pstart(10px)"><span>445.03</span></td>
   <td class="Py(10px) Pstart(10px)"><span>459.44</span></td>
   <td class="Py(10px) Pstart(10px)"><span>459.44</span></td>
   <td class="Py(10px) Pstart(10px)"><span>204,600</span></td>
  </tr>
  ....

 

 

 

2.4 스크래핑 구현 (2)

  Ex) 테이블에서 배당금 정보만 가져오기 

  • table = thead+ tbody + tfoot으로 이뤄진다.
    • 따라서, get(1) 하면 tbody만 가져올 수 있다.
    • get(2)하면 tfoot을 가져올 수 있다.
  • for문을 순회하면서 우리가 필요한 배당금만 가져올 수 있도록 한다.
    • 배당금은 모두 "Dividend"로 끝나는 특성을 이용한다.
<hide/>
package com.dayone;
import java.io.IOException;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SampleApplication {
    public static void main(String[] args) {

        SpringApplication.run(SampleApplication.class, args);

        try {
            Connection connection = Jsoup.connect("https://finance.yahoo.com/quote/COKE/history?period1=99100800&period2=1662940800&interval=1mo&filter=history&frequency=1mo&includeAdjustedClose=true");
            Document document = connection.get();
            Elements eles = document.getElementsByAttributeValue("data-test", "historical-prices");
            Element ele = eles.get(0);  // 여러 개 중에 테이블 하나만 가져온다.
            Element tbody = ele.children().get(1);

            for (Element e : tbody.children()) {
                String txt = e.text();
                if(!txt.endsWith("Dividend")){
                    continue;
                }
                System.out.println(txt);               
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

  Note) 실행 결과 - 배당금 정보만 불러온다.

  • 이제 아래 결과를 공백 기준으로 split 할 계획
<hide/>
Jul 28, 2022 0.25 Dividend
Apr 27, 2022 0.25 Dividend
Jan 27, 2022 0.25 Dividend
Oct 21, 2021 0.25 Dividend
Jul 22, 2021 0.25 Dividend
Apr 22, 2021 0.25 Dividend
Jan 21, 2021 0.25 Dividend
Oct 22, 2020 0.25 Dividend
Jul 23, 2020 0.25 Dividend
Apr 22, 2020 0.25 Dividend
Jan 23, 2020 0.25 Dividend
Oct 24, 2019 0.25 Dividend
Jul 25, 2019 0.25 Dividend
Apr 25, 2019 0.25 Dividend
Jan 24, 2019 0.25 Dividend
Oct 25, 2018 0.25 Dividend
Jul 26, 2018 0.25 Dividend
Apr 26, 2018 0.25 Dividend
Jan 25, 2018 0.25 Dividend
Oct 26, 2017 0.25 Dividend
Jul 26, 2017 0.25 Dividend
Apr 26, 2017 0.25 Dividend
Jan 25, 2017 0.25 Dividend
Oct 26, 2016 0.25 Dividend
Jul 27, 2016 0.25 Dividend

 

 

  Ex) 배당금액 구분 짓기

  • Integer.parseInt()와 Integer.valueOf()의 차이는?
    • Integer.parseInt(): 원시 데이터 int 타입을 반환한다.
    • Integer.valueOf(): 래퍼 객체 Integer 객체를 반환한다.
<hide/>
package com.dayone;
import java.io.IOException;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SampleApplication {
    public static void main(String[] args) {

        SpringApplication.run(SampleApplication.class, args);

        try {
            Connection connection = Jsoup.connect("https://finance.yahoo.com/quote/COKE/history?period1=99100800&period2=1662940800&interval=1mo&filter=history&frequency=1mo&includeAdjustedClose=true");
            Document document = connection.get();
            Elements eles = document.getElementsByAttributeValue("data-test", "historical-prices");
            Element ele = eles.get(0);  // 여러 개 중에 테이블 하나만 가져온다.
            Element tbody = ele.children().get(1);

            for (Element e : tbody.children()) {
                String txt = e.text();
                if(!txt.endsWith("Dividend")){
                    continue;
                }

                String[] splits = txt.split(" ");
                String month = splits[0];
                int day = Integer.valueOf(splits[1].replace(",", ""));
                int year = Integer.valueOf(splits[2]);
                String dividend = splits[3];
                System.out.println(year + "/" + month + "/" + day + " -> " + dividend);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

  Note) 실행 결과

<hide/>
2022/Jul/28 -> 0.25
2022/Apr/27 -> 0.25
2022/Jan/27 -> 0.25
2021/Oct/21 -> 0.25
2021/Jul/22 -> 0.25
2021/Apr/22 -> 0.25
2021/Jan/21 -> 0.25
2020/Oct/22 -> 0.25
2020/Jul/23 -> 0.25
2020/Apr/22 -> 0.25
2020/Jan/23 -> 0.25
2019/Oct/24 -> 0.25
2019/Jul/25 -> 0.25
2019/Apr/25 -> 0.25
2019/Jan/24 -> 0.25
2018/Oct/25 -> 0.25
2018/Jul/26 -> 0.25
2018/Apr/26 -> 0.25
2018/Jan/25 -> 0.25
2017/Oct/26 -> 0.25
2017/Jul/26 -> 0.25
2017/Apr/26 -> 0.25
2017/Jan/25 -> 0.25
2016/Oct/26 -> 0.25
2016/Jul/27 -> 0.25

 

 

출처 - https://zero-base.co.kr/

 

제로베이스 - 누구나 취업하는 가장 합리적인 취업 스쿨

코딩 부트 캠프 개발자, 데이터 사이언티스트, 마케터, PM, 디자이너 등 제대로 공부하고 확실하게 취업하세요. 당신의 삶의 전환점이 될 제로베이스 스쿨입니다.

zero-base.co.kr

'Spring Projcect > 배당금 프로젝트' 카테고리의 다른 글

Chapter 06. 완성도 높이기  (0) 2022.09.20
Chapter 05. 회원 관리  (0) 2022.09.19
Chapter 04. 서비스 구현  (0) 2022.09.14
Chapter 03. 서비스 설계  (0) 2022.09.13
Chapter 01. 프로젝트 환경 설정  (0) 2022.09.12