Study/연습

빅데이터 저장 시스템 출력 - 기사 제목 출력

상맹 2021. 9. 29. 16:55
반응형

1. 스프링부트 + 몽고DB 연결
2. 크롤링 (뉴스 데이터)
3. 몽고 저장 - 배치프로그램 (1분마다)
4. API 컨트롤러 구축
5. Flask 서버 만들어서 API 호출해서 시각화


1) application.yml 설정

application.properties → 파일명 'yml'로 변경

spring mongodb host → port → database 입력

spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: greendb

2) test 파일 만들어서 JUnit test

 

test -> util 패키지 생성 -> NaverCrawTest 생성

public class NaverCrawTest {
	
	int aid = 1;
	
	@Test
	public void test1() {
		
		String aidStr = String.format("%010d",aid);
		String url = "https://news.naver.com/main/read.naver?mode=LSD&mid=shm&sid1=102&oid=022&aid=" + aidStr;
		
        RestTemplate rt = new RestTemplate();
        
        //html
        String html = rt.getForObject(url, String.class);
        System.out.println(html);
	}
}

* exchange 

 requestEntity : post, put 사용

 responseType : json data를 지정 타입으로 변환해서 받는다.

 

3) html 분석

* title id 찾기 : #articletitle

* company class 찾기 : .press_log img → 속성값 title 사용

* createdAt class 찾기 : .t11 

 

4) pom.xml jsoup 라이브러리 dependency 추가

 - NaverCrawTest 추가

	String html = rt.getForObject(url, String.class);
		
	Document doc = Jsoup.parse(html);
		
	Element companyElement = doc.selectFirst(".press_logo img");
	String compnayAttr = companyElement.attr("title"); // title 또는 alt

	Element titleElement = doc.selectFirst("#articleTitle");
		
	Element createdAtElement = doc.selectFirst(".t11");
		
	String company = compnayAttr;
	String title = titleElement.text();
	String createdAt = createdAtElement.text();

5) Batch package 생성 후 NaverNewsCrawsBatch 생성

 ① NewsappApplication

@EnableScheduling
@SpringBootApplication
public class NewsappApplication {

	public static void main(String[] args) {
		SpringApplication.run(NewsappApplication.class, args);
	}

 

② NaverNewsCrawBatch

 - 생성자 사용 시 자동 생성되는 _id를 넣을 수 없으므로 Builder 사용

@RequiredArgsConstructor
@Component
public class NaverNewsCrawsBatch {
	
	private int aid = 1;
	private final NaverNewsRepository naverNewsRepository;
	
	
	@Scheduled(fixedDelay = 1000*60*1)
	public void newsCraw() {
		
		List<NaverNews> newsList = new ArrayList<>();
		
		for(int i = 1; i<6; i++) {
			
		String aidStr = String.format("%010d",aid); 
		String url = "https://news.naver.com/main/read.naver?mode=LSD&mid=shm&sid1=102&oid=022&aid=" +aidStr;
		RestTemplate rt = new RestTemplate();
		
		try {
			// {"username":"ssar" , "password":"1234"}
			String html = rt.getForObject(url, String.class);
			Document doc = Jsoup.parse(html);

			Element companyElement = doc.selectFirst(".press_logo img");
			String compnayAttr = companyElement.attr("title"); // title 또는 alt
			Element titleElement = doc.selectFirst("#articleTitle");
			Element createdAtElement = doc.selectFirst(".t11");
			
			String company = compnayAttr;
			String title = titleElement.text();
			String createdAt = createdAtElement.text();
			
			NaverNews nn = NaverNews.builder()
					.company(company)
					.title(title)
					.cratedAt(createdAt)
					.build();
					
			newsList.add(nn);
			
		} catch (Exception e) {
			System.out.println("통신 오류");
			
		}
		aid++;
		}
		naverNewsRepository.saveAll(newsList);
		
	}
}

③ Domain package 생성

 - NaverNews

@Builder
@AllArgsConstructor
@Data
@Document(collection = "naver_news") // 몽고DB 컬렉션 이름 지정
public class NaverNews {
	@Id
	private String _id;
	private String company;
	private String title;
	private String cratedAt; // 날짜 몽고DB save() 하면 무조건 미국 시간(+9시간)으로 들어감
}

 - NaverNewsRepository

public interface NaverNewsRepository extends MongoRepository<NaverNews, String>{

		@Query(value="{title: ?0, company: ?1}")
		LIst<NaverNews> mFindByTitleAndCompany(String title, String company);
}

④ web package 생성 - controller 생성

@RequiredArgsConstructor
@RestController
public class NaverNewsController {
	
	private final NaverNewsRepository naverNewsRepository;
	
	@GetMapping
	public CMRespDto<?> findAll(){
		List<NaverNews> naverNewsList = naverNewsRepository.findAll();
		return new CMRespDto<>(1,"성공",naverNewsList);
	}
}

⑤ web package 내부 dto package 생성 - CMResDto 생성

 

@AllArgsConstructor
@NoArgsConstructor
@Data
public class CMRespDto<T> {
	private int code;
	private String msg;
	private T data;
}

localhost:8080 실행시 화면


파이썬 사용해서 Flask로 뿌리기

 

1. flask, request 설치

# pip install requests
# pip install flask

 

2. router.py

from flask import Flask, render_template
import requests

app = Flask(__name__)


@app.route('/naverNews')
def naverNews():
    response = requests.get("http://localhost:8080/naverNews")
    cmRespDto = response.json();
    if cmRespDto["code"]==1:
        return render_template("index.html", naverNewsList=cmRespDto["data"])
    else:
        return "데이터를 가져올 수 없습니다"

if __name__ == '__main__':
    app.run(debug=True)

3. index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>네이버뉴스 리스트</title>
</head>
<body>
    <table border="1">
        <tr>
            <th>신문사</th>
            <th>기사제목</th>
            <th>기사발행일</th>
        </tr>
        {% for naverNews in naverNewsList%}
        <tr>
            <td>{{naverNews.company}}</td>
            <td>{{naverNews.title}}</td>
            <td>{{naverNews.createdAt}}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

4. setinterval javascript 추가 ( index.html 에 추가)

    <script>
        setInterval(function(){
            location.reload();
        }, 1000*60*1
        )
    </script>

localhost:5000/naverNews 접속시 입력결과 확인

 

반응형