python의 기본 기능으로 간단하게 짜본 6개의 랜덤숫자 코드

뭔가 될거라고 생각해서 만든건 아니지만... 잘맞는다면 행운의 코드라고 생각하자.

 

import random

if __name__ == '__main__':
    result = []

    for i in range(5):
        tmp_res = []
        while True:
            if len(tmp_res) == 6:
                break
            key = random.randint(1, 45)
            if key not in tmp_res:
                tmp_res.append(key)
        tmp_res.sort()
        result.append(tmp_res)

    print(result)

총 6개의 랜덤의 숫자를 5번 수행하도록 만든 코드

5번 수행시킨이유는 그래야 한장으로(?) 나오니까....

 

너무 짧은 코드이기에 설명은 생략!

 

반응형

JSON 파일에 있는 데이터를 Mapping 하여 가지고 오는 방법 중 하나로 ObjectMapper를 이용할 수 있다.

JSON 파일에 있는 Key 값을 java 클래스 파일로 미리 만들어 두고 ObjectMapper의 readValue 함수를 이용하면 쉽게 가지고 올 수 있다.

 

예를 들어 json 형식과 java class 형태를 보자.

{   
    "title": "test news",
    "reporter": "Austin",
     "since": "2017"
}

 

 

 

 

그런데, 여기서 JSON 파일이 다음과 같다면?

{   
    "title": "test news",
    "reporter": "Austin",
    "since": "2017",
    "keyword": "prob"
}

 

아마 이와 같은 에러가 날 것이다.

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "keyword"......

 

이를 해결하기 위해서 java 클래스에 해당 어노테이션을 해주면 된다.

 

@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class NewsInfoVo {
    private String title;
    private String reporter;
    private String since;
}

 

import는 최신 jackson의 버전에 따라 다르다.

 

최신 버전이면

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

이전 버전이면

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

 

이러면 문제 해결!

간단하지만, 생각이 안나는 경우가 있다 보니.. 체크!

반응형

'IT관련 > Java' 카테고리의 다른 글

Java 관련 공부 링크  (0) 2020.01.15

간만에 들어와서 명령어 하나 끄적거리고 가야지!


현재 디렉토리 경로 기준으로 하위 디렉토리 포함 경로 내 모든 텍스트 파일을 출력하는 명령어

find . -type f -name '*.txt' -exec cat {} +


하나의 파일로 합치는건 이것만 추가하면 됨


find . -type f -name '*.txt' -exec cat {} + > output.txt


이러면 output.txt 에 출력한 모든 텍스트가 저장되어 하나로 합쳐지게 된다.


그럼...

반응형

오랜만에 C++ 코드를 보다가 좋은 글인것 같아서 남겨둬야지

거의 새로운 언어를 공부하는 느낌이다.... 그래봤자 금방 익숙해지겠지만 ㅋㅋㅋ


=====================================================================================================


‘기차모델’로 갈아탄 ‘C++17’이 가져온 변화는?

잠깐, C++17? 벌써 C++ 17이 나왔다고?



C++17이 정식으로 승인됐습니다.

지난 9월6일, C++ 표준화 기구의 의장인 허브 서터가 자신의 블로그에 위 제목으로 C++17 표준안이 ISO의 최종 심의 절차에서 만장일치를 통해 승인됐다는 글을 올렸습니다.

이 소식을 듣고 아직 C++11에서 가져온 변화에도 적응하지 못했는데 벌써 C++17 표준이 나왔다는 사실에 놀라는 분들도 계실 것입니다. 한편 C++ 표준에 계속해서 관심을 갖고 계신 분들이라면 이제서야 C++17 표준이 마무리된 것인가 하고 의아해하는 반응을 보일 분도 계시리라 생각됩니다. 이러한 반응들은 모두 예상할 수 있습니다. 왜냐하면 놀랍게도 C++17 표준은 갑자기 완성된 것이 아니라, 오히려 그 반대인 지난 3년간 꾸준히 발전해 왔기 때문입니다. 2011년에 C++11 표준이 발표된 후, 2014년에 C++14 표준이 발표됐고, 계속해서 정기적인 C++ 커미티 미팅을 거치며 기능들이 제안되고, 토론을 통해 C++ 표준으로 수정·통합돼 왔습니다. C++17의 주요 기능 역시 이미 지난해 대부분 기술적으로 마무리된 것들이기도 합니다. C++ 표준화 기구에서는 도대체 지난 몇 년 간 어떤 일들이 벌어지고 있는 것일까요?

C++ 표준의 발전과 역사

C++은 1983년에 태어난 언어이므로, 30살이 훨씬 넘은 언어입니다. 그러나 첫 C++ 표준화는 1998년에 처음 이뤄졌습니다. 그래서 우리가 첫 번째 C++ 표준을 이야기할 때 그 기준은 1998년이라고 하고, C++98이라고 표현하기도 합니다. 98년도에 발표된 첫번째 C++ 표준은 7년간 21번의 미팅을 통해 완성됐습니다. 그리고 그 이후 5년간 C++ 표준화 위원회는 새로운 기능을 추가하기보다는 약간의 휴지기를 거치며 C++98 표준의 버그들을 수정한 03 표준(ISO/IEC 14882:2003)을 2003년도에 발표했습니다. 그리고 이어서 8년 간 21번의 미팅을 거쳐 첫 번째 표준에 크게 기능을 추가한 두 번째 메이저 표준인 C++11 표준을 2011년도에 발표했습니다. 특히 이 C++11은 C++98(03)과 비교해 다른 언어로 보일 만큼 많은 기능이 업데이트돼 C++ 개발자들에게 C++ 언어는 오래되고 정체된 언어가 아니라 계속해서 발전하는 언어라는 깊은 인상을 남겼습니다. 뒤이어 3년, 6번의 미팅을 거쳐 C++11의 마이너 업데이트인 C++14 표준을 만들어냈습니다.

C++ 표준화, ‘기차 모델’로 갈아타다

허브 서터 커미티 의장은 C++11 표준이 발표된 후 그 시점부터 C++ 표준화 위원회의 운영을 조금 다른 방식으로 가져가기로 합니다. C++11 표준이 완성될 때 까지 그 과정을 비교적 조용히 드러내지 않고 활동해 왔던 것과는 달리 그 시점부터는 다음 설명하는 방식들을 통해 활발하게 표준화 과정을 진행하기로 합니다. C++11 표준화를 진행할 때에는 ‘언제까지’라는 마감기한을 못박아두지 않은 채 최종 표준안을 발표할 수 있을 정도로 다 완성되면 내놓겠다고 하면서 말이죠. 또한 C++11에 포함될 ‘기능(Features)들’에만 집중했기 때문에 표준 출시가 계속 지연되는 문제(커미티가 막판에 디자인을 계속해서 바꿈)가 있었습니다. 그래서 C++03 표준안을 낸 후, 차기 표준안의 이름이었던 C++0x는 결국 200x년도가 아닌 2011년에야 C++11 이름을 달고 발표됐습니다. 그 과정에서 C++0x에서 x는 실은 10진수가 아닌 16진수 값이었다는 농담도 나왔습니다. 또한 이러한 진행 방식으로 인해 이 시기에서는 2004년에 가승인(draft)된 표준안도 공식 C++11에 포함돼 출시되기만을 마냥 기다려야만 했습니다.

C++11 표준화를 진행하며 얻은 경험으로 C++ 표준화 위원회는 ‘무엇’을 내놓을지도 중요하지만, ‘언제’ 내놓는 것 역시 매우 중요하다는 걸 깨달았습니다. 그래서 C++11 표준이 출시된 뒤부터는 방법을 달리 가져가기로 결정합니다. 3년마다 표준을 출시하기로 결정하고, ‘언제’를 더 중요하게 다루기 시작한 것입니다. 이것을 ‘기차 모델‘이라고 불렀습니다. 또한 우리가 개발을 진행하며 별도로 구분되는 새로운 기능들을 ‘브랜치’를 따서 작업하는 것처럼, 표준화 스펙에서도 ‘모듈, 파일 시스템, 네트워킹 표준 라이브러리’와 같이 개별 기술 묶음들을 TS(Technical Specification)라는 이름의 실험 기술(베타) 브랜치로 동시에 진행했습니다. 해당 TS 스펙이 충분히 표준화되기에 무르익으면 트렁크(C++ 표준)에 머지(merge)하는 전략을 가져갑니다. 그 과정에서 만약 표준화 기차가 도착했지만(3년마다 돌아오는 C++표준 발표 시기까지) 스펙이 충분하게 완성되지 않았다면 그 TS는 다음 표준 기차를 타게 되는 것입니다.

이러한 새로운 전략에 따라 3년이라는 시간이 지나 2014년 개정된 C++14 표준안을 내놓을 수 있었으며, 다시 3년 만에 정확히 돌아온 기차를 타고 2017년 C++17 표준을 내놓을 수 있게 된 것입니다. 마찬가지로 지난 2017년 7월 토론토 미팅을 통해 방금 C++20을 향하는 기차가 막 출발했고, 우리는 앞으로 3년 뒤 C++20이라는 기차가 도착할 것을 예상할 수 있게 된 것입니다.

C++ 위원회 미팅

현재 C++ 표준화 위원회는 일년에 세 번씩 미팅을 진행하고 있으며, 그 정보들은 C++ 표준화 위원회의 공식 사이트에서에서 확인할 수 있습니다. 최근에 있었던 미팅들과 주요 사건들을 나열해보자면 다음과 같습니다.

연도장소트립 리포트 주요 사건
2015년 5월렉사나, 미국[링크]표준 스펙 버그 수정
Transactional Memory TS, Parallelism TS 표준 발표
2015년 10월코나, 미국[링크1]
[링크2]
Concurrency TS 표준 발표
2016년 2월잭슨빌, 미국[링크]다음 TS들이 C++ 표준으로 합쳐짐
– Parallelism TS(Parallel STL)
– Library Fundamental 1 TS: any, optional, string_view
– File System TS
2016년 6월올루, 핀란드[링크1]
[링크2]
1. 다음 기능들이 표준 draft로 포함됨
– structured binding, if (init;condition)
– variant<>2.C++17 feature가 마무리되고 리뷰 기간에 들어감
2016년 11월이사퀘어, 미국[링크]ISO 리뷰 커멘트를 해결함
2017년 2월코나, 미국[링크]1. C++17이 기술적으로 마무리 됨
2. 마지막 ISO 승인(balloting)을 위해 보내짐
3. 버그 수정
2017년 7월토론토, 캐나다[링크]C++20을 위한 첫번째 미팅
2017년 11월엘버커키, 미국[링크]

C++17 표준이 가져온 변화들

C++17 표준안은 어떤 새 기능들을 포함했고, 어떤 변화를 가져오게 할까요? 새로 발표된 C++17의 표준 가운데 개인적으로 주목할만하다고 생각되는 몇 개의 내용을 살펴보겠습니다. 아래의 예제 코드들은 표준 문서, 블로그 또는 컨퍼런스 등을 통해 발표된 자료들로부터 가져왔으며, 출처는 함께 표시했습니다.

1. 언어(C++ 문법)에서의 변화

a. If and switch with initializer

if (init; condition) 또는 switch (init; condition) 구문처럼 if/switch 안에 조건문과 선언문을 함께 사용할 수 있습니다. 과거에 RAII를 활용한 lock_guard를 사용해야 할 때, 그 lock에 대한 필요성이 전체 scope에 대해서는 필요없는 경우라면 좌측 테이블처럼 {} 괄호를 더 사용해 인스턴스의 lifetime을 제한하기도 하였습니다. 그러나 이젠 if 문 안에 선언문을 넣을 수 있으므로 우측과 같이 사용 가능합니다.

b. Structured bindings

배열, tuple, pair가 주어졌을 때 그 안에 담긴 개별 값들에 대해 로컬 변수 선언과 값 저장을 한 번에 할 수 있도록 합니다.

a와 b의 변경점을 모아서 함께 활용해 본다면, 다음과 같은 코드도 이제 C++17에서는 사용가능합니다. std::map의 insert는 삽입된 iterator와 성공여부를 가리키는 pair를 반환하므로, insert() 를 호출하고 그 성공 여부를 체크하는 동작을 if 구문 한 줄에서 아래처럼 작성이 가능합니다.

c. 기타 중요한 변경 사항들

– Template argument deduction for class templates [링크]
– constexpr if [링크]
– fold expression [링크]

2. 표준 라이브러리에서 변경된 점

a. std::string_view [링크]

std::string_view는 기존 std::string을 사용할 때 불필요하게 일어날 수 있었던 임시 객체 생성을 막을 수 있도록 고안된 클래스입니다. 내부적으로 문자열에 대한 pointer와 length만 가지므로 복사가 쉽고, 메모리를 할당하지 않습니다. std::string 인터페이스와 거의 동일하므로 기존 std::string을 사용하던 코드에서 std::string을 std::string_view로 변경하는 것만으로 쉽고 간단하게 성능상의 이득을 얻을 수 있을 것으로 예상됩니다. 다음 코드는 동일한 역할을 하는 코드지만, C++17 코드에서는 문자열의 복사가 일어나지 않습니다.

▲출처: https://youtu.be/LvwXJjRQfHk

b. std::variant [링크]

boost 라이브러리에 존재하던 variant 타입이 C++ 표준 라이브러리에 머지됐습니다.

▲출처: https://herbsutter.com/2016/06/30/trip-report-summer-iso-c-standards-meeting-oulu/


추가로 눈여겨 볼만한 C++17 새 라이브러리에는 std::optional<>, std::any<>가 있습니다.

C++의 다음 기차, C++20

다음 표준이 될 C++20에는 C++0x 시절부터 논의돼 온 Concept 기능이 드디어 포함될 예정입니다. 특히 코루틴, 네트워킹, 모듈 등이 모두 표준에 포함될 것으로 보여 C++20 역시 큰 변화를 맞이할 것으로 예상됩니다. 마지막으로 현재 각 컴파일러 벤더 별 C++17 지원사항은 다음 페이지에서 확인 가능합니다.

컴파일러 지원 상황

– Clang: https://clang.llvm.org/cxx_status.html
– GCC: https://gcc.gnu.org/projects/cxx-status.html
– MSVC: https://blogs.msdn.microsoft.com/vcblog/ (비주얼 스튜디오 업데이트를 통해 지원이 추가될 때마다 새 글을 통해 공유합니다)

=====================================================================================================

출처 : http://www.bloter.net/archives/291766

반응형

요번엔 Elasticsearch 초간단 실행방법에 대해 알아보자.


알아보기 전에, Elasticsearch가 뭔지에 설명을 하고 넘어가자. 

Elasticsearch 는 분산형 RESTful 검색 및 분석 엔진이다. (홈페이지에도 이렇게 설명을 하고 있다...)

처음엔 데이터 검색엔진이라고 생각했지만, 데이터 분석과 시각화 기능까지 제공하고 있다. 

시각화 기능은 Kibana를 설치하여 이용할 수 있는데, 이 부분은 추후에 진행해보자.


그럼 이제, Elasticsearch 설치부터 알아보자.

참고로, 설치 환경은 Linux 환경 (Ubuntu 16.04) 이다. 


우선 설치 파일은 https://www.elastic.co/kr/downloads/elasticsearch 에서 받을 수 있다.

글 작성시의 최신 버전은 5.5.1이다. 


다운로드 페이지에서 tar 파일을 받아서 설치할 경로에 저장을 한다.

명령어로 받으려면 아래와 같이 하면 된다.


wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.1.tar.gz


다운로드 받은 파일은 tar 파일로 압축을 해제 한다.


tar zxvf elasticsearch-5.5.1.tar.gz 


압축해제를 하고나면, 파일명과 같은 폴더가 생기고, 파일 목록은 아래와 같다.


$~/elasticsearch/elasticsearch-5.5.1$ ls

LICENSE.txt  NOTICE.txt  README.textile  bin  config  data  lib  logs  modules  plugins


bin 폴더에 가서 elasticsearch 를 실행하면 되는데, 

전에 config 폴더에 elasticsearch.yml 파일을 열어서 몇가지 설정만 해놓자.


먼저, 아래 글과 같이 path.logs에 경로를 지정한다. 이름과 같이 로그 파일 저장경로이다.


...

# ----------------------------------- Paths ------------------------------------

#

# Path to directory where to store the data (separate multiple locations by comma):

#

#path.data: /path/to/data

#

# Path to log files:

#

path.logs: /home/austinlee/elasticsearch/elasticsearch-5.5.1/logs

...


다음으로는, IP 설정이다. elasticsearch 서버의 IP 주소를 입력한다. 

일단, 내부적으로 테스트 하는 것이므로 Localhost인 127.0.0.1로 한다.


...

# ---------------------------------- Network -----------------------------------

#

# Set the bind address to a specific IP (IPv4 or IPv6):

#

network.host: 127.0.0.1

#

# Set a custom port for HTTP:

#

#http.port: 9200

#

# For more information, consult the network module documentation.

...


이렇게 설정하고 나서, bin 폴더에 있는 elasticsearch를 실행한다.


./bin/elasticsearch


데몬으로 실행하고 싶으면 다음과 같이 실행하면 된다.


./bin/elasticsearch -d


데몬으로 실행했을 경우, 종료는 해당 pid 를 찾아서  kill 을 하면 된다.


# pid 찾기 

ps -ef | grep elasticsearch 


# 찾은 pid 로 프로세스 죽이기

kill 'pid'


elasticsearch 서버를 실행하고 나서 정상적으로 동작을 하는지, 웹 브라우저를 통해 확인한다.

주소 창에 http://localhost:9200/를 입력하고 접속을 한다. (localhost는 위에서 설정한 IP 주소, 접속  Default 포트는 9200이다.)


{
  "name" : "OR5RLR1",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "Fe_tQmzOT8OVj-K1C7VQYA",
  "version" : {
    "number" : "5.5.1",
    "build_hash" : "19c13d0",
    "build_date" : "2017-07-18T20:44:24.823Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.0"
  },
  "tagline" : "You Know, for Search"
}

정상 동작이면 위와 같은 정보가 나온다.


이렇게 초간단 실행법은 끝!

이제 REST API 를 이용해서 데이터를 저장하고 검색하면 된다. 이에 대한 것은 다음에....






반응형

오랜만에 들어온 김에 요즘 해보고 있는 것에 대해 글을 써보자는 취지로 작성!


요즘 Crawler 를 만들어보고 싶어서 이것저것 알아 본 결과, 개발하기 쉬운 Web Crawler를 선정했다.

 

우선, Web Crawler에 대한 설명은...

아래 링크를 참조하고, 

https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC

개발에 대해 얘기를 해보자.


Youtube를 Crawling 대상으로 선정한 이유는 아무래도 데이터가 많고, 다양하기 때문에 선정하게 되었다. (나름 참고할 문서들도 많았다...)


그리고 개발 언어는 Python을 이용하였고, 버전은 3.5버전이다.

원래 2.7버전을 했었는데, 3.5 버전이 더 빠르다보니(더 안정적인거 같다...) 바꾸게 되었다.


개발하기 전에 먼저 필요한 것은 Python 설치와 BeautifulSoup 설치이다.

Python 설치는 구글에 'Python 설치' 라고 검색하면 잘나와있기에 넘어간다.


BeautifulSoup 은 html 과 xml 문서를 파싱해주는 라이브러리이다.


pip를 이용하여 간단하게 설치할 수 있다.


pip install lxml



Youtube Crawling 의 경우, xml 문서를 파싱하기 때문에 위와 같이 설치하지만, html 파싱을 하는 경우에는 

아래 명령어로 설치를 할 수가 있다.


pip install html5lib



BeautifulSoup 라이브러리를 설치하고 본격적으로 개발을 해보자.


Python에 대해 잘모르지만, BeautifulSoup 문서와 다른 자료들을 참고하여 아래와 같은 소스를 만들었다. 



# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup 

import lxml 

import requests 

import json 

import datetime

 


video_info = { 'title':'', 'video_link':'', 'img_link':'', 'play_time':'', 'hits' : '', 'updated_time':'', 'description':'', 'reg_time':'' } 


def get_video_link(target_url): 

response = requests.get(target_url) 

soup = BeautifulSoup(response.text, "lxml") 

lis = soup.find_all('li', {'class' : 'channels-content-item yt-shelf-grid-item'}) 

for li in lis : 

title = li.find('a', {'title' : True})['title'] 

video_link = 'https://www.youtube.com' + li.find('a', {'href' : True})['href'] 

img_link = li.find('img', {'src' : True})['src'] 


#<span class="video-time" aria-hidden="true"><span aria-label="8분, 55초">8:55</span></span>

play_time = li.find('span', {'class' : 'video-time'}).text 


#<ul class="yt-lockup-meta-info"><li>조회수 2,902,617회</li><li>6개월 전</li></ul>

hits = li.find_all('li')[2].text 

updated_time = li.find_all('li')[3].text 

video_info = { 

'title' : title, 

'video_link' : video_link, 

'img_link' : img_link, 

'play_time' : play_time, 

'hits' : hits, 

'updated_time' : updated_time 

}

 

print(video_info) 


return video_info 


def get_hot_video_info(target_url): 

response = requests.get(target_url) 

soup = BeautifulSoup(response.text, "lxml") 

lis = soup.find_all('li', {'class' : 'expanded-shelf-content-item-wrapper'}) 

for li in lis : 

# exception

try : 

title = li.find('a', {'title' : True})['title'] 

video_link = 'https://www.youtube.com' + li.find('a', {'href' : True})['href'] 

img_info = li.find('img', {'data-thumb' : True})

if img_info != None :

img_link = img_info['data-thumb'] 

else : 

img_link = li.find('img', {'src' : True})['src'] 

#<span class="video-time" aria-hidden="true"><span aria-label="8분, 55초">8:55</span></span>

#play_time = li.find('span', {'class' : 'video-time'}).text 

play_time_info = li.find('span', {'class' : 'video-time'})

if play_time_info != None :

play_time = play_time_info.text

else :

play_time = None

#<ul class="yt-lockup-meta-info"><li>조회수 2,902,617회</li><li>6개월 전</li></ul>

hits = li.find_all('li')[3].text 

updated_time = li.find_all('li')[2].text 

description_info = li.find('div',{'class':True, 'class':'yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2'})

if description_info != None :

description = description_info.text

else :

description = None


now = datetime.datetime.now()

video_info = { 

'title' : title, 

'video_link' : video_link, 

'img_link' : img_link, 

'play_time' : play_time, 

'hits' : hits, 

'updated_time' : updated_time,

'description' : description,

'reg_time' : now.strftime('%Y-%m-%d %H:%M:%S')

}

print(video_info) 


except BaseException as e : 

print(e)

 


return video_info 



target_url = 'https://www.youtube.com/user/CJENMMUSIC/videos' 

target_url2 = 'https://www.youtube.com/feed/trending'


# 특정 채널

#get_video_link(target_url)


# 인기 리스트

get_hot_video_info(target_url2)




위의 소스를 조금씩 파헤쳐보자. 

첫번째 줄인 # -*- coding: utf-8 -*- 이 부분은 한글 인코딩과 관련하여 넣어준 부분이다.


다음으로 import 부분은 필요한 라이브러리를 선언하는 부분이다.


다음 줄에는 video_info 를 선언하는 부분이다. 이것은 Dictionary 타입으로 Key-Value 형식으로 되어 있다. Youtube Crawling 한 데이터 중 필요한 부분을 여기에 저장한다.


이 프로그램에는 두개의 함수가 있다. 하나는 get_video_link 이고 다른 하나는 get_hot_video_info 이다. 


get_video_link 는 특정 채널에 대한 영상 정보를 가져오는 함수이고, get_hot_video_info 는 인기 채널에 대한 영상 정보를 가져오는 함수이다.

참고로 get_video_link 함수는 예외처리가 제대로 안되어 있으므로, 참고를 한다면 get_hot_video_info 함수를 참고하는 것이 좋다.


설명도 get_hot_video_info 함수에 대해서만 해보자. (차근차근 설명을 남기기 위해 쪼개서 설명하자...)


response = requests.get(target_url) 

soup = BeautifulSoup(response.text, "lxml") 

lis = soup.find_all('li', {'class' : 'expanded-shelf-content-item-wrapper'}) 


먼저 target_url 은 Crawling할 Youtube 주소를 의미 하고, 

첫번째 라인은 target_url 로부터 xml 을 요청하는 부분이고, 이에 대한 반환 값은 response 이다.

두번째 라인은 반환값인  response를 BeautifilSoup 라이브러리를 이용하여 파싱을 하는 부분이다. 파싱결과는 soup이다.

세번째 부분은 파싱된 soup에서 li 속성 중 class가 expanded-shelf-content-item-wrapper 인 부분을 찾아서 리스트로 넣는 부분이다.

리스트는 lis 이다.

이 부분을 이해하기 위해선 xml에 대한 지식이 필요하다...



간단하게 설명을 하자면, 

크롬 브라우저에서 Youtube 인기를 접속하여 개발자모드(F12를 누르면됨)를 들어가보면 다음과 같이 나온다. 익스플로러도 가능하다.




위의 그림과 같이 동영상에 파란색으로 나오게 하려면 xml 정보있는 부분 위에  과 같은 표시를 누르고 

동영상 부분에 마우스를 가지고 가면 해당 부분에 대한 xml 위치를 나타낸다. 여기서 보면 저 부분이 li 속성이고 class가 expanded-shelf-content-item-wrapper 라는 것을 알 수 있다. 이 부분에서 해당 동영상에 대한 정보를 가지고 오는 것이다.





다시 코드설명으로 돌아와서 설명을 해보자.


for li in lis : 

# exception

try : 

title = li.find('a', {'title' : True})['title'] 

video_link = 'https://www.youtube.com' + li.find('a', {'href' : True})['href'] 

img_info = li.find('img', {'data-thumb' : True})

if img_info != None :

img_link = img_info['data-thumb'] 

else : 

img_link = li.find('img', {'src' : True})['src'] 

#<span class="video-time" aria-hidden="true"><span aria-label="8분, 55초">8:55</span></span>

#play_time = li.find('span', {'class' : 'video-time'}).text 

play_time_info = li.find('span', {'class' : 'video-time'})

if play_time_info != None :

play_time = play_time_info.text

else :

play_time = None

#<ul class="yt-lockup-meta-info"><li>조회수 2,902,617회</li><li>6개월 전</li></ul>

hits = li.find_all('li')[3].text 

updated_time = li.find_all('li')[2].text 

description_info = li.find('div',{'class':True, 'class':'yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2'})

if description_info != None :

description = description_info.text

else :

description = None


now = datetime.datetime.now()


이 부분은 반복문으로 lis 리스트를 li에 넣고 실질적인 분석을 하는 부분이다. (try 는 혹시 모를 exception을 위해 걸어 놓았다.)

분석은 위에서 간단하게 설명한 xml 분석을 통해서 필요한 정보를 찾고 그 위치를 코드에 입력하는 방식이다.

title 은 동영상의 제목으로, a 속성에 title 정보가 있는 부분에 존재를 한다. 

video_link 는 동영상 페이지로 접속하는 페이지링크로, a 속성에 href 정보가 있는 부분에 존재하며, 공통 도메인인 'https://www.youtube.com'이 빠져 있으므로 직접 추가해줬다.

img_link 는 동영상의 썸네일 이미지정보로, img 속성에 data-thumb 정보가 있다면, data-thumb 에 존재하고, 

data-thumb 정보가 없는 경우, src 정보에 존재한다.

play_time 은 동영상 길이에 대한 정보로, span 속성에 video-time 정보에 존재한다. 이 정보를 존재하지 않는 경우도 있다. (정확한 이유를 아직...)

hits 는 조회 수 정보로, li 속성 중 4번째 위치에 있는 정보이다. (해당 정보안에 li 속성이 여러개 존재하는데, 앞에 3개가 있고 4번째에 조회 수 정보가 존재.)

updated_time 는 업로드 시간 정보로, li 속성 중 3번째 위치에 있는 정보이다.

description 는 동영상 설명에 대한 정보로, div 속성 중 class 정보가 yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2 인 곳에 있는 정보이다.

now 는 현재 Crawling 한 시간 정보이다.


video_info = { 

'title' : title, 

'video_link' : video_link, 

'img_link' : img_link, 

'play_time' : play_time, 

'hits' : hits, 

'updated_time' : updated_time,

'description' : description,

'reg_time' : now.strftime('%Y-%m-%d %H:%M:%S')

}

print(video_info) 


except BaseException as e : 

print(e)

 


return video_info 


추출한 정보들을 video_info 에 위와 같이 저장을 하고, 출력을 한다.

추후에 수집한 데이터를 저장하기 위해서는 이 부분에는 데이터를 전송하는 부분이 추가되어야 한다. 

예외가 발생하는 부분이 있으면 except BaseException as e :  으로 빠지고 계속해서 반복문을 수행한다.

반복문 수행이 끝나면 리턴한다.



target_url = 'https://www.youtube.com/user/CJENMMUSIC/videos' 

target_url2 = 'https://www.youtube.com/feed/trending'


# 특정 채널

#get_video_link(target_url)


# 인기 리스트

get_hot_video_info(target_url2)


target_url2 은 Youtube 인기 채널 주소이고, get_hot_video_info(target_url2) 은 함수를 호출하는 부분이다.


코드에 대한 설명은 여기까지 한다.

혹시 몰라서 특정 채널에 대한 함수를 뺀 설명한 부분만 있는 소스코드는 아래와 같다.


# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup 

import lxml 

import requests 

import json 

import datetime

 


video_info = { 'title':'', 'video_link':'', 'img_link':'', 'play_time':'', 'hits' : '', 'updated_time':'', 'description':'', 'reg_time':'' } 


def get_hot_video_info(target_url): 

response = requests.get(target_url) 

soup = BeautifulSoup(response.text, "lxml") 

lis = soup.find_all('li', {'class' : 'expanded-shelf-content-item-wrapper'}) 

for li in lis : 

# exception

try : 

title = li.find('a', {'title' : True})['title'] 

video_link = 'https://www.youtube.com' + li.find('a', {'href' : True})['href'] 

img_info = li.find('img', {'data-thumb' : True})

if img_info != None :

img_link = img_info['data-thumb'] 

else : 

img_link = li.find('img', {'src' : True})['src'] 

#<span class="video-time" aria-hidden="true"><span aria-label="8분, 55초">8:55</span></span>

#play_time = li.find('span', {'class' : 'video-time'}).text 

play_time_info = li.find('span', {'class' : 'video-time'})

if play_time_info != None :

play_time = play_time_info.text

else :

play_time = None

#<ul class="yt-lockup-meta-info"><li>조회수 2,902,617회</li><li>6개월 전</li></ul>

hits = li.find_all('li')[3].text 

updated_time = li.find_all('li')[2].text 

description_info = li.find('div',{'class':True, 'class':'yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2'})

if description_info != None :

description = description_info.text

else :

description = None


now = datetime.datetime.now()

video_info = { 

'title' : title, 

'video_link' : video_link, 

'img_link' : img_link, 

'play_time' : play_time, 

'hits' : hits, 

'updated_time' : updated_time,

'description' : description,

'reg_time' : now.strftime('%Y-%m-%d %H:%M:%S')

}

print(video_info) 


except BaseException as e : 

print(e)

 


return video_info 



target_url2 = 'https://www.youtube.com/feed/trending'


# 인기 리스트

get_hot_video_info(target_url2)



Web Crawler는 xml 파싱을 해서 필요한 정보가 어느 위치인지를 분석하고 나면, 금방 만들 수 있을 것 같다.

결국 분석 능력이다....


다음엔 Youtube가 아닌 다른 사이트에 대한 Web Crawling을 해봐야겠다. 


반응형

환경은 Ubuntu 16.04에서 작업함.


우선 예제 코드를 git을 통해 가지고 온다.


git clone https://github.com/firebase/friendlychat



가지고 오면 firendlychat 폴더가 생기고 

이안데 web-start 라는 폴더에 보면 index.html 이 있다.


이 폴더에 firebase 프로젝트 생성시 나오는 스니펫(?) 소스 코드를 넣어 준다.


firebase 프로젝트 생성과 소스코드 가져오는 설명은 아래 링크 참조


https://codelabs.developers.google.com/codelabs/firebase-web/#3


index.html 에 소스코드를 입력할때 다음 순서로 넣는다. 빨간 부분이 넣은 부분이다.

<!-- Firebase -->

<!-- ***********************************************************************************************************************

     * TODO(DEVELOPER): Paste the initialization snippet from: Firebase Console > Overview > Add Firebase to your web app. *

     *********************************************************************************************************************** -->


<script src="https://www.gstatic.com/firebasejs/3.5.3/firebase.js"></script>


<script>

  // Initialize Firebase

  var config = {

    apiKey: "AIzaSyCql1C-ZzCVvSoKfnjdj48Y70THgGdYZ-4",

    authDomain: "austin-gcs.firebaseapp.com",

    databaseURL: "https://austin-gcs.firebaseio.com",

    storageBucket: "austin-gcs.appspot.com",

    messagingSenderId: "41293526285"

  };

  firebase.initializeApp(config);

</script>


<script src="scripts/main.js"></script>

</body>

</html>


index.html 에 소스코드를 입력 후, 저장한 뒤에

npm 명령어를 이용하여 firebase-tools 를 설치한다.


만약 npm 명령어가 안된다면 먼저 설치 후, 위 작업을 한다.


sudo apt install npm

sudo npm -g install firebase-tools

firebase 가 제대로 설치 되었는지 확인한다.


sudo firebase version


현재 설치 했을때의 최신 버전은 3.0.8 이다. 


로그인 명령어를 통해 firebase에 로그인 한다. 


sudo firebase login


현재 구글계정을 이용하여 로그인하기 때문에 허용여부에 대한 웹 창이 뜨고 수락하면 된다.



web-start 폴더에서 아래와 같은 명령어로 현재 로그인한 계정의 프로젝트 별명을 설정할수 있다.

sudo firebase use --add



채팅 프로그램을 실행한다.


sudo firebase serve


실행 후, http://localhost:5000 (이게 기본 로컬 주소)로 접속하면 채팅 화면창이 뜬다.

메시지 입력 후, SEND 버튼을 누르면 Sign in 해야된다는 문구가 뜰 것이다...


sign-in 하는 건 소스코드를 입력해야되는 부분이다.


https://codelabs.developers.google.com/codelabs/firebase-web/#6


위 링크를 참조하여 소스 코드를 입력하여 sign-in 버튼을 활성화시켜서 화면에 나오는지 확인한다.
만약, 나오지 않는다면 확인해야할 경우의 수가 몇가지 있다.
1. index.html 순서 확인
2. 브라우저 쿠키 삭제
3. firebase.json 파일에 아래 내용 입력 후, 재 실행 

{

  "hosting": {
    "public": "./",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}


3번의 경우, 안해도 잘되긴 했다...


기존 데이터 불러오기 및 메시지 전송은 아래 링크에 나와 있는 내용으로 진행하면 문제없이 진행된다.


데이터 불러오기

https://codelabs.developers.google.com/codelabs/firebase-web/#7


메시지 전송

https://codelabs.developers.google.com/codelabs/firebase-web/#9


이정도면... 실시간 채팅 앱이 되긴한다.... 룰 설정과 google 계정 외의 다른 메일로의 연동은 다음에 작성해야겠다.




반응형

Ubuntu 16.04 에서 CUDA 7.5를 설치 하려면 먼저 그래픽 드라이버를 설치해야한다. 

CUDA를 다운로드 받아서 설치할때 드라이버 설치 여부를 물어보긴 하지만,

몇 번 시도해본 결과, 시스템이 꼬여서 원복하는 상황을 맞았기 때문에... 

그래픽 드라이버를 별도로 설치 후, CUDA설치 한다.


그래픽 드라이버 설치 전에 


그래픽 드라이버 설치는 repository 등록 후, update 


sudo add-apt-repository ppa:graphics-drivers/ppa

sudo apt-get update


update 이후 apt-get 으로 그래픽 드라이버 설치 


sudo apt-get install nvidia-352*


버전은 CUDA에 맞는 버전으로 한다. 7.5에서는 위 버전으로 하면 될꺼 같다....


만약 기존에 그래픽드라이버가 설치 되어 있다면, 기존 드라이버를 제거 후에 설치해야된다.


sudo apt-get remove --purge nvidia-*



그래픽 드라이버를 설치 완료 했다면 CUDA를 설치한다. 

CUDA 설치 파일 다운로드 경로는 https://developer.nvidia.com/cuda-downloads 이다.



현재 Nvidia에서 Ubuntu 16.04에 대한 CUDA 버전이 별도로 존재 하지 않아서 Ubuntu 15.04 버전의 run 파일을 다운로드 받는다.

다운로드 받은 후, 설치전에 사전에 설치해야되는 게 있다.


sudo apt-get install libglu1-mesa libxi-dev libxmu-dev libglu1-mesa-dev freeglut3-dev


CUDA를 이용하는데 필요한 라이브러리 인거 같다... 자세한건 추후에 더 알아봐야지...


사전 설치 작업이 끝나면 ALT+CTRL+F1 로 Command Mode로 전환한다.

CUDA 설치 전에 Xorg가 실행 중이면 


sudo init 3

sudo service lightdm stop


위의 명령어로 중지 후 설치를 한다.


cd {CUDA 다운로드한 경로}

sudo sh cuda_7.5.18_linux.run


실행하면 설명화면이 뜨고 q를 누르면 accept여부를 묻는다.

accept를 입력하여 다음으로 넘어가면, 그래픽 드라이버 설치 여부를 묻는데 그건 생략을 하고, 이외의 CUDA와 관련된 설치를 묻는건 모두 y를 입력한다. 

command mode여서 별도의 스크린샷은 안올리는걸로.....(약간의 귀찮음...)


성공적으로 설치하고 나면 


sudo service lightdm start

or

reboot


둘 중 하나로 정상동작을 하게 한다. 개인적으로는 reboot이 편했다는....


CUDA 설치가 끝났으면 예제 하나를 돌려서 제대로 설치가 되었는지 확인해보자.

예제는 nbody로...

기본 경로로 설치를 했다면 /usr/local/cuda 에 설치가 되었을 것이다.

cuda 디렉토리에 보면 samples 디렉토리가 있는데, 이것을 우선 권한을 현재 계정으로 부여하자


sudo chown -R {사용자계정명}:{사용자계정명} /usr/local/cuda/samples/


그리고 CUDA 7.5는 gcc 버전이 4.9이상이면 에러를 보내는데, 이 에러를 무시하기 위해서 config 파일을 고친다.


sudo vi /usr/local/cuda-7.5/include/host_config.h


host_config.h 파일을 열면 아래와 같은 부분을 주석처리 한다.


#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 9)


#error -- unsupported GNU version! gcc versions later than 4.9 are not supported!


#endif


그리고 예제로 nbody를 해보기 위해 다음과 같은 순서로 실행해본다.


cd /usr/local/cuda/samples/5_Simulations/nbody

make 

./nbody


정상적으로 작동을 한다면 새로운 창이 뜨고 아래와 같은 화면이 생성된다.




CUDA 7.5 는 정상적으로 설치가 되었으니... 나중에 CuDNN 설치하고, DNN 툴을 설치해서 써봐야겠다.

오늘은 여기까지!



반응형

Maven 을 이용하여 실행 가능한 Jar 파일을 만들어 보자.


게다가 Maven 에서 제공하는 Library 가 아닌 Local Library 를 추가 하는 방법 또한 메모하자.


1. 외부 라이브러리 추가하는 방법


우선, Local Library를 pom.xml 에 추가 하는 방법은 아래 코드를 넣어보자.


<repositories>

<repository>

<id>localrepository</id>

<url>file://${basedir}/lib</url>

</repository>

</repositories>


위의 url 태그 부분에 외부 Library 파일들이 있어야 되고 Dependency 로 추가하기 위해선 파일이 있는 경로를 groupId/artifactId/version/artifactId-version.jar 과 같이 해야 된다.


경로에 파일을 생성 한 뒤, Dependency 관련 정보를 아래와 같이 pom.xml 에 추가 한다. 

(직접 만든 rabbitmq library에 대한 예제. 경로는 "프로젝트 루트경로\lib\rabbitmq\rmq_queue\1.0.0\rmq_queue-1.0.0.jar" 이다.)


<dependencies>

......

<dependency>

<groupId>rabbitmq</groupId>

<artifactId>rmq_queue</artifactId>

<version>1.0.0</version>

</dependency>

......

</dependencies>



2. 실행 가능한 Jar 파일 만들기


실행 가능한 Jar 파일을 만들기 위해선 pom.xml 파일에 Build 태그를 넣어 Plugin들을 추가 한다.


 <build>

<plugins>

......

<plugin>

<artifactId>maven-compiler-plugin</artifactId>

<version>3.1</version>

<executions>

<execution>

<id>default-compile</id>

<phase>compile</phase>

<goals>

<goal>compile</goal>

</goals>

<configuration>

<encoding>UTF-8</encoding>

</configuration>

</execution>

<execution>

<id>default-testCompile</id>

<phase>test-compile</phase>

<goals>

<goal>testCompile</goal>

</goals>

<configuration>

<encoding>UTF-8</encoding>

</configuration>

</execution>

</executions>

<configuration>

<encoding>UTF-8</encoding>

</configuration>

</plugin>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-shade-plugin</artifactId>

<version>2.4.3</version>

<executions>

<execution>

<phase>package</phase>

<goals>

<goal>shade</goal>

</goals>

<configuration>

<!-- XML schema namespaces 오류 수정을 위해 필요함 -->

<transformers>

<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

<resource>META-INF/spring.handlers</resource>

</transformer>

<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

<resource>META-INF/spring.schemas</resource>

</transformer>

<!-- 실행 가능한 jar 파일을 만들기 위해서는 main method가 존재하는 클래스를 명시해 주어야 함 -->

<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

<manifestEntries>

<Main-Class>com.metadataCollector.metadataCollectorMain</Main-Class>

</manifestEntries>

</transformer>

    </transformers>

<!-- Dependency Reduced Pom 파일 미생성 -->

    <createDependencyReducedPom>false</createDependencyReducedPom>

</configuration>

</execution>

</executions>

</plugin>

......

</plugins>

</build>


추가 할때 Main-Class 이름을 넣어 준다. 


위와 같이 모든 준비 작업을 완료하고 mvn package 명령어로 실행가능한 jar 파일을 생성한다.


간단하게 작성했지만... 부족한 부분이 있으면 수정해야지.... 

반응형

+ Recent posts