tibero, oracle, nettezza(네티자) 비교

 

오라클은 ANSI SQL 표준을 준수하지 않는 DB이다.

하지만, 금융쪽은 장애 등을 고려하여 안정성이 높은 오라클을 어쩔수 없이 사용하였고,  그이후 단가가 낮은 DB를 도입하는 것을 업종 특성상 꺼려하고 있어, 금융쪽에서 업무를 한다면 무조건 오라클에 익숙해야 한다. 따라서 MSSQL, MySQL 등과 비교해 보면, 질의형 query라는 큰 틀에서는 차이를 느끼지 못하지만, 조인/Null값 체크, 서브쿼리, 페이징 기법 등을 비교해보면 다름을 알 수 있다. 그말은 DBMS를 변경하게 되면 쿼리 호환성을 반드시 검토해야 한다. 

DBMS의 후발주자인 tibero, netezza는 전략적으로 공공과 금융시장을 타켓으로 하였기에 DBMS 변경에 따른 작업(결국 비용)을 최소화하여 시장을 공략하기 위해 오라클과 동일한 문법을 채택하였다. 다만, 오라클의 기본 문법을 따라할 수 있었으나, 오라클의 분석함수 등 일부 기능는 지원하지 않는다. 

tibero를 먼저 살펴보면,

거의 모든 문법이 동일해서 전환이 용이하다. 사실 기존 구축된 시스템에 분석함수(partition by, window구문 등)을 사용하는 경우가 드물다. 설령 존재할지라도 대체 가능할 정도의 숫자이기에 재개발하면 된다. 게다가 만약 일부만 tibero를 도입한다면, DBLink로 이종DB간의 연결되 가능해서 중요시스템과 비중요시스템을 구분하여 도입할 수도 있다. 다만, 일부 제약사항이 있기에 도입전에 반드시 제약사항을 검토하자. 

몇년 전만할지라도 티베로의 이중화(TAC)가 불안했으나, 지금은 많은 개선을 통해 안정화가 되었다고 한다. 가성비를 고려한다면 도입 검토를 하지 않을 이유가 없다. 게다가 국가에서 국산SW를 우선 이용할 것을 권고하고 있어서 공공/금융에서 많이 이용하다 보니, 많은 피드백을 거쳐 발전하고 있는 것 같다. 

 많은 비오라클 DBMS가 있음에도 "굳이", 오라클과 티베로를 비교하는 이유는 국가 정책 때문이다. 한국 소프트웨어 발전을 위해 공공은 국산 솔루션을 우선 검토하고 있어, 공공에서는 최근 Tibero 디비가 몇백억대 납품실적까지 생겼다. 사실 많이 사용하다보면, 문제점에 대해 개선해 가면서 버전업을 하고, 발주자는 다시 구매하여 개선된 제품을 이용하는 선순환 구조가 형성된다. 또한, 금융에서도 최근 홈페이지 등 일부 업무에서는 다양한 DBMS를 활용하고자 하는데 사실 오라클 비용이 부담되기 때문이다. 

netezza(네티자)를 살펴보면,

네티자는 기본적으로 정보계DBMS이다. 즉, 거래 목적이 아닌 통계 목적이다. 게다가 PDA(Pure Data System)라는 IBM에서 어플라이언스로 판매하고 있어서, 하드웨어와 소프트웨어 일체형이다. 자료 규모에 따라 구매한다. 압축률은 10배(?) 정도라고 하지만, 사실 압축률은 자료의 타입에 따라 다르다.! 만약 자료에 한글이 포함되었다면, 1글자당 3byte를 차지하여 압축률이 낮고, 영문이나 숫자로만 되어 있다면 압축률이 높다. 즉, 무조건 압축률이 좋은게 아니라 자료에 따라 높을 수 있다.

쿼리는 거의 오라클과 대동소이해서 오라클 쿼리를 그대로 통계(netezza)에 이용할 수 있다. 다만, 일부 substring 등의 시작이 0이 아니라, 1로 시작하는 등 작은 차이는 존재한다. 

통계DB 특성상 Column-wise 하기에 속도는 체감상 Sybase에 견줄만하다. 다만, 이것도 통계DB에 쿼리를 이렇게 저렇게(조인 방식) 하다보면, 어떻게 질의문을 작성해야 답이 잘 나오는지 본인이 습득해야 한다. 다만, 조인없는 단순 쿼리는 누구라도 빠른 답을 얻을 수 있다. 1억건 기준 1~3초 이내 답을 얻을 수 있다.

 아마 여러분이 10년 넘은 금융회사의 직원이라면 이용하고 있는 정보계 DB는 Sybase(사이베이스)일 것이다. 사이베이스는 서버와 별도의 스토리지를 구매하여 사용하기에 자료량이 폭증할지라도 스토리지만 추가로 구매하여 할당하면 되서 부담이 적으나, PDA는 어플라이언스 장비라 서버 자체를 구매해야 하는데, 상위 버전으로 올라 갈때 마다 비용이 상당히 올라 간다(50%이상?). 하지만, Sybase 솔루션과 ETL(Extract, Tranform, Load) 솔루션의 비용이 상당히 높아 다른 제품과 비교를 해보는 것도 좋을 것 같다. 

사실 정보계 솔루션은 20명(3명이내일지도 모름) 이내의 내부직원만 사용하는 솔루션인데, 비용은 5억~10억 이상 발생하는 아주 고가의 제품이다. 하지만, 회사가 전략적 판단을 하기 위해 적시(빠른)에 다양한 통계를 뽑기 위해서는 충분한 가치가 있는 제품이다. 그럼에도 비용이 걱정된다면 다른 제품도 비교해봄직하다.

 

 

Posted by 목표를 가지고 달린다
,

테슬라의 성공비결, 실패를 수용하는 자세

Best Effort,형, 실패보단 다음 스텝의 목표에 치중하는 조직

테슬라의 Best Effort형 개발 사이클은 그들이 혁신적인 기술을 계속해서 개발하고 시장에서 성장하도록 도와주는 핵심적인 요소 중 하나입니다. 이 방법은 다른 자동차 제조사들이 사용하는 "보증형" 개발 방법과는 다릅니다. "보증형" 방법에서는 모든 것이 완벽하게 작동해야 하며, 프로토타입 차량을 제작하고 무수한 테스트를 수행하여 결함이 없는 제품을 만들어야 합니다. 그러나 이 방법은 매우 비용이 많이 들고 시간도 오래 걸립니다.

반면에, 테슬라는 Best Effort형 개발 방법을 사용하여 최초의 디자인 도면을 발표하고 프로토타입 차량을 만들 때 15대 정도만 만듭니다. 그리고 이를 바탕으로 내부 평가, 내구성 테스트, 충돌 테스트, 연비 테스트, 라이딩 컴포트 및 조향 안정성 평가 등을 한번에 수행합니다. 이러한 방식으로 테슬라는 개발 비용과 시간을 크게 절감할 수 있었습니다. Best Effort형 개발 방법은 시행착오를 받아들이는 것을 포함하여 실패를 수용하고 이를 토대로 빠른 속도로 진전하는 방법입니다. 테슬라는 이 방법을 사용하여 이전에 없었던 혁신적인 기술을 개발하고 시장에서 성장할 수 있었습니다. 이 방법은 조직 내에서 실패를 받아들이는 문화를 조성하며, 불필요한 회의나 회의에서 시간을 낭비하는 것 대신 데이터를 확보하고 실험을 빠르게 수행합니다.

또한, 테슬라의 CEO인 엘론 머스크는 고유한 경영 방식을 가지고 있습니다. 그는 빠른 속도로 실험하고 데이터를 수집한 후 다음 단계로 전진하는 것을 선호합니다. 또한 실패를 두려워하지 않고, 실패에서 배운 것을 바탕으로 더 나은 제품을 만들어 나가기를 원합니다. 이러한 방식은 조직 내에서 실패를 받아들이는 문화를 조성하고, 테슬라가 지금까지 성장해 온 핵심적인 요소 중 하나입니다.

스페이스X 발사 장면

테슬라는 스페이스X는 빠르게 실패하는 문화를 가졌지만, 그것이 실패해도 괜찮다는 것을 의미하는 것은 아니었습니다. 실패는 말 그대로 실패이고, 로켓의 개발은 큰 비용과 노력을 필요로 하는 일이기에 발사 실패의 피해는 컸습니다. 로켓 발사에 실패할 때마다 스페이스X의 구성원들은 크게 실망하고 낙담했습니다. 세 번의 로켓 발사 실패에 대한 기록에서 특히 인상 깊었던 부분은, 그들이 실망과 좌절감에 오래 머무르지 않고 그다음 미션으로 빠르게 전환하는 태도였습니다. 오랜 시간과 노력을 들여 진행했던 프로젝트가 실패했을 때, 일론 머스크를 포함한 리더들은 다음 스텝의 목표를 빠르게 제시했습니다. 그리고 엔지니어들은 그 목표를 달성하는 방법을 재빨리 찾았습니다. 주어진 문제를 해결하는 것이 그들이 가장 잘하는 일이었습니다.(2006년 3월, 스페이스X 첫 번째 발사 이후, 2008년 9월 4번째 발사만에 우주 궤도 진입 성공)

그 결과, 테슬라는 세계 최대의 전기 자동차회사로 거듭날 수 있었습니다.

'개발자 넋두리' 카테고리의 다른 글

형상관리 시스템 도입 전에 고민거리...  (0) 2019.07.04
Posted by 목표를 가지고 달린다
,

관리자는 직접 코딩하지 않고, 주로 기획과 평가를 담당합니다.

 

기획에 집중하다보면 UI/UX에 대한 체계적인 접근과 명료한 법칙을 고려해야 합니다. 자신의 경험에만 의존하지 말고, 다른 제품과 다른 관점에서 검토하고 장단점을 비교하여 결정해야 합니다. 또한, 조직 규모를 고려하여 개발된 앱을 평가하는 것이 중요합니다. 팀원들의 의견도 적극적으로 수용하여 개발 방향성을 제시해야 합니다.

최근 UX 관련 인터넷 글에서는 토스 앱이 자주 언급됩니다. 실제로 토스 앱은 매우 사용하기 편리합니다. 불편한 부분을 모두 제거하여 깔끔한 앱으로 만들었으며, 알림창, 화면 배치, 안내 및 프로세스도 표준에 맞게 구성되어 있습니다. 게다가 토스 앱은 네이티브 앱으로 개발되어 있어서 화면 전환 등에서 더욱 부드러운 사용감을 제공합니다.
* 앱 개발을 2가지로 나뉠수 있는데, 하이브리드(하나의 소스로 아이폰, 안드로이드 배포)와 네이티브(아이폰 전용 개발, 아니드로이드 전용개발) 이다. 하이브리드앱은 관리 측면, 네이티브는 최적화 측면에서 장단점이 있다.

그럼 존 야블론스키가 저술한 ≪UX/UI의 10가지 심리학 법칙≫에서 소개하는 10가지 UX 법칙을 보면서 왜 토스앱이 정말 잘 만들어진 것인지 뜯어보았다.

< 제이콥의 법칙 : 익숙한 방식 >

사용자가 오래 사용하면서 축적된 경험에 기반하여 새로운 제품을 평가한다는 것을 말합니다. 따라서 기존 방식을 완전히 무시하고 새로운 방식으로 서비스를 제공하거나 리모델링하면 사용자들은 처음부터 다시 학습해야 하기 때문에 불편해하게 됩니다. 금융 서비스 앱인 토스는 익숙한 인터페이스와 사용성을 제공하여 사용자들이 쉽게 적응할 수 있는 것이 그 예시입니다.

< 피츠의 법칙 : 쉬운 터치 >

목표물의 거리와 크기에 따라 목표물에 도달하는 데 걸리는 시간이 달라진다는 것입니다. 따라서 터치할 수 있는 객체 간의 거리는 적당해야 하며, 각 객체의 크기와 흐름도 고려되어야 합니다. 또한 모바일 디바이스에서는 사용자의 시선이 중심부에 집중되므로, 여러 객체 간 리스트를 나열할 때에는 Vertical 형태로 나열하는 것이 좋습니다.

< 테슬러의 법칙 : 불편함을 최소화 >

모든 시스템에는 더 이상 줄일 수 없는 일정 수준의 복잡성이 존재한다. 토스는 사용자가 입력한 계좌번호에서 은행별 계좌번호 고유의 패턴을 파악하여 추천 은행명 버튼을 제공함으로써, 사용자가 일일이 은행을 찾아볼 필요를 줄이고자 합니다. 이를 통해 사용자의 불편함의 간극을 줄이도록 서비스를 제공합니다.

< 힉의 법칙 : 선택지 최소 >

선택지가 너무 많으면 사용자들의 인지 부하가 증가한다는 것입니다. 선택지의 개수가 증가하면 선택 시간이 늘어나고, 사용자들은 스트레스를 받게 됩니다. 따라서 정보를 펼쳐서 보여주는 것보다는 필요한 정보만을 간결하게 제공하는 것이 좋습니다.

< 밀러의 법칙 : 질문 갯수 및 구역(경계) 명확히 >

우리는 작업 기억에 7(+-2)개의 항목만 저장할 수 있다는 것입니다. 따라서 토스에서는 적당한 객체 수와 확실한 경계선을 두어 덩어리화하여 사용자에게 보다 쉽게 정보를 전달하고자 합니다.

< 포스텔의 법칙 : 요청량 최소, 1thing / 1page >

사용자에게 요청하는 정보의 양이 많을수록 인지부하가 증가하고, 피로도가 쌓인다는 것입니다. 이에 따라 토스에서는 "1 thing / 1 page" 철학을 따라 사용자에게 보수적으로 정보를 제공하고, 사용자의 편의성을 고려한 간편한 회원가입 프로세스를 제공합니다.

< 피크엔드의 법칙 : 순간의 실패를 부드럽게~ >

사용자 경험은 오랜 이용을 바탕으로 한 합계가 아니라, 절정의 순간이나 마지막 순간에 느낀 감정이 크게 작용한다. 우리는 앱을 사용하면서 중요했던(기억나는) 순간, 특히 '실패했던 순간'을 더 오래 기억하려는 경향이 있다. 토스는 실패의 순간도 최대한 부드럽게 표현하기 위해 귀여운 애니메이션이나 토스 특유의 친근한 문구를 보여줌으로써 작은 실패로 느껴지도록 불편함을 최소화합니다.

< 심미적 사용성 효과 : 이쁜게 쓰기도 좋다 >

디자인이 아름답다면 사용성도 높아질 것이라는 심리적 효과를 말합니다. 토스의 캐주얼하고 둥글둥글한 인터페이스 디자인은 금융앱이 가지고 있던 딱딱한 이미지와 달리 사용자들에게 더욱 친근하고 쉽게 다가올 수 있도록 도와줍니다.

< 폰 레스토프 효과 : 색다른 것만 기억하는 효과 >

비슷한 여러 객체 중에서 가장 색다른 것만 기억한다는 효과를 말합니다. 이를 활용하여 특정 기능이나 정보를 강조하고자 할 때는 진한 컬러나 보색 컬러를 사용하는 것이 효과적입니다. 처음 서비스에 유입된 사용자에게 길을 알려주거나, 새로운 기능을 소개할 때, 혹은 알림이나 배지를 사용할 때 자주 마주할 수 있습니다. 그러나 시각적 강조를 너무 많이 사용하면 사용자의 집중력을 저하시켜 산만해지게 만들 수 있으니 주의가 필요합니다.

< 도허티 임계 : 딜레이 없는 서비스 >

사용자의 관심을 유지하고 생산성을 높이기 위해서는 0.4초 이내에 시스템 피드백을 제공해야 한다는 원칙입니다. 토스의 경우, 대출 심사 등 외부 정보를 호출하는 구간에서는 귀여운 애니메이션을 제공하여 사용자의 딜레이를 덜 느끼도록 도와줍니다.

채드윅 님의 브런치에서 더 자세한 내용을 확인할 수 있습니다.

토스앱은 사용하면 할수록 대단하다고 생각되는 것이, 직관적이기에 별다른 허들없이 새로운 서비스를 쉽게 경험할 수 있습니다. 그리고 게임요소를 많이 접목하여 계속 접속을 유도하고 있습니다. 최근에는 블루투스를 활용한 '친구와 함께 토스 켜고'를 통해 젊은 사람들 사이에 유행을 하고 있고, 나이드신 분들 사이에서는 건강과 함께 챙기는 '만보기'를 통해 매일매일 40원~100원씩 건강과 재미를 함께 즐기신다고 합니다.

앞으로도 토스앱의 꾸준한 발전을 기대합니다.

 

Posted by 목표를 가지고 달린다
,

 

UI를 제작하는데 어려움을 느끼는 개발자들은 기본적으로 UI를 쉽게 제작해주는 툴(프레임워크)를 이용하는 것이 편리하다. 팀이 있어 분업화되어 있으면 모를까? 혼자 개발하는 경우에는 자율성을 보장해주는 개발툴 보다는 기본적으로 제공하는 컴포넌트가 많은 툴을 이용하는 것이 오히려 생산성도 좋고, 결과(제품)을 만들 수 있다.

Flutter에 대해서는 UI기반을 쉽게 만들수 있는 프로토 타입용이라고만 알고 있었지만, 이번에 혼자 책을 보면서 알아가고 있다. 책들의 내용은 기본적으로 UI를 어떻게 하면 이쁘게 뽑아낼 수 있을까? 어떻게 만들까? 하는 부분에 집중되어 있지 코딩을 자세히 알려주지 않는다. 결국 Flutter는 개발자를 위한 툴이라는 생각이 든다. 하지만 내가 정작 원하는 기능 구현을 하기 위해서는 한계나 복잡도가 높다고 하는데, 지금 당장 내가 원하는 것은 결과물을 만드는 것이라, 인내하기로 했다.

생존코딩책을 읽으면서, 기본적인 문법은 Skip하고, 나중에 참고할만한 사항을 위주로 정리하고자 한다. 그리고 이동하면서 만들 수 있기에 Github for Desktop으로 소스 관리를 하고자 한다.

* 타입검사( is, is! 키워드) : if( a is int) { } , if ( a is! int) { }
* 출력시 $를 이용하여 쉽게 표현 : print('hello $greet ');
* 출력시 $, {} 이용하여 쉽게 표현 : print('hello {_student.name}, bro'}, print('10y later , {$_age + 10} year ')
* 익명함수 : ([인수명]) { [동작 또는 반환값] } : (number) { return number%2==0; };
* 람다식 : ([인수명]) => [동작 또는 반환값]
ex ) (number) => number%2== 0; (위의 익명함수와 동일한 결과)
* 선택 매개변수 : 함수 호출시 매개변수를 {}으로 감싸 선택적으로 입력 가능
ex) void something( {String name, int age}) {}
something(name : '홍길동', age : 10); OK
something(name : '홍길동') OK
something(age : 10) OK
something() OK
* 선택 매개변수와 필수 매개변수 혼합시 필수를 먼저!!!
ex) void something( String name, {int age}) {}
something(name : '홍길동', age : 10); OK
something(name : '홍길동') OK
something(age: 10) Fail
* 선택 매개변수는 기본값 설정 가능
ex) void something( String name, {int age =10}) {}
something(name : '홍길동'); OK & age = 10
* 삼항 연산을 이용한 분기 : [조건] ? [참일 때 값] : [거짓일 때 값]
ex) age > 20 ? 'adult' : 'child'
* 접근 지정자 : 변수명 앞에 _기호를 붙이지 않으면 외부에서 접근 가능하고, 붙이면 접근 불가능(캡슐화). 어쩐지 예제들 보면, _ 기호를 붙인 예제들이 많음
ex ) person._age = 10; Fail 접근 불가
person.age = 10; OK 접근 가능
* 클래스를 생성할 때, 생성자를 만들지 않으면 기본 생성자를 사용할 수있고, 사용자 정의 생성자를 추가하면 기본 생성자를 사용할 수 없다. 다만, 사용자 정의 생성자 정의시 선택 매개변수를 사용하면 동일하게 이용 가능
ex ) class Person {
String name,
int _age;
Person ( { this.name, this._age} );
}
* 믹스인(with) : 상속하지 않고 다른 클래스의 기능을 가져오거나, 오버라이드할 수 있음
ex ) class Goblin implements Monster { }
class DarkGoblin extends Goblin with Hero { }
* Map, Set, List
* 함수를 변수에 대입 :
ex ) void greeting(String text) {
print (text);
}
var f = greeting;
f('hello');
* forEach() : ( E element ) {} 형태의 함수를 인수로 받음.
ex) items.forEach(print); // 1, 2, 3, 4, 5
items.forEach( (e) { // 1, 2, 3, 4, 5
print(e)
} );
items.forEach( (e) => print(e));
* where 조건 이용 : filter 기능
ex) items.where ( (e) => e%2 == 0).forEach(print); // 2, 4
* map : 반복되는 값을 다른 형태로 변환하는 방법 제공
ex) items.where ( (e) => e%%2 ==0).map( (e) => '숫자 $e').forEach(print);
* toList : 다트에서 함수형 프로그래밍을 지원하는 함수 대부분은 Iterable<T> 라는 인터페이스 타입 인스턴스를 반환하는데, 실제 코딩할 때는 리스트를 많이 활용함
ex ) final result = items.where ( (e) => e%2 == 0).toList();
* toSet : List에서 집합의 특성인 중복을 제거하는 방법
ex ) final result = items.where ( (e) => e%2 == 0).toSet().toList();
* any() : 리트스에 특정 조건을 충족하는 요소가 있는지 검사할 때 유용함
ex) print ( items.any((e)=> e%2==0)); // true
* 계산식 표기법(임수변수를 만드는 단계 생략)
ex) print(items..add(6)..remove(2)); // 출력시 6추가 2삭제지만, items값은 변경없음.
* 컬렉션 if : 컬렉션 내부에 if문을 이용할 수있어 소스가 간결함
ex ) print( [ 1, 2, 3, 4, 5, if (promoActive) 6] ); // promoActive 값에 따라 6 포함여부 결정
* 컬렉션 for
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
* null처리 : 컴파일러가 소스 분석해서 오류를 예측할는데, 객체의 속성 접근시 . 연산자 대신 ?. 연산자를 사용하면 객체가 null 일때, 에러를 발생하는 대신 null 반환
ex ) print (name?. length) ; 또는
print(name?. length ?? 0 ) 으로 기본값 처리 가능.
* null safety : 버전이 올라가면서 널값 체크하는 기능이 강화되어, if문으로 확실히 널값에 대한 예외처리를 해줘야 하지만, 개발자가 로직상 null이 올수 없다고 판단이 되면, . 연산자가 아니라, !. 연산자로 접근하면 문제 없음.
ex ) print(name!.length);

책은 전체적으로 입문용으로 복잡하지 않고 쉽게 기본 앱 구조에 대해 설명하고 있어 훌륭함. DB연동 등을 복잡하게 하지 않고, 페이지도 구조화하기 보다는 1source로 쉽게 접근할 수있게 구성되어 있음. 다만, Java 등 오래된 언어와 달리 Python처럼 버전에 따른 문법 변경이 있어서 인터넷에서 원인을 찾아야 할 경우가 종종 있음.
대표적인 오류가 RaisedButton 버튼이 deprecated되어 ElevatedButton 로 교체해야 하거나, Null Safety 정책으로 !. 를 이용해야 하는 경우이다.

 

 

 

 

 

Posted by 목표를 가지고 달린다
,

API를 문서를 읽지 않고, 도전하는 개발자의 실수

# 사전준비 #

가. 텔레그램 계정 : 기존 보유자도 Setting(환경설정)에서 '@' 로 시작하는 이름이 있는지 확인. 없다면 '편집'에서 Username에 입력하면, @홍길동 으로 등록
나. 챗 검색에서 'BotFather'를 검색한후, New Bot 을 생성하고, 아래 그림에서 가려진 부분이 토큰(Token)값임.

다. 챗 검색으로 나와, New Bot을 검색한 후, 대화 1~2개를 던짐
라. 텔레그램은 채팅방마다 Chat-ID를 부여하는데, 나와 Bot의 Chat-id를 찾아야 함
브라우저창에 'https://api.telegram.org/Bot생성시 받은 TOKEN값/getUpdates' 을 입력하면 결과 나옴
(아래의 id 가 Chat-ID 값임)

{"ok":true,"result":[{"update_id":770558652,
"message":{"message_id":3,"from":{"id":5113991,"is_bot":false,"first_name":"Kam","last_name":"dh","username":"teleno0","language_code":"ko"},"chat":{"id":5113991,"first_name":"Kam","last_name":"dh","username":"teleno0","type":"private"},"date":1677135418,"text":"Fjdjdjd"}}]}

여기서 잠깐 트러블 슈팅!!!
저 화면이 안나오는 경우는 2가지
하나. ok는 정상인데, 아래와 깉이 id 값이 없음. 이럴 때는 다시 Bot에게 대화를 한 후 브라우저에 동일하게 접속하면 나옴

{"ok":true,"result":{"id":603078,"is_bot":true,"first_name":"Tellm0","username":"Tellm0_bot","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false}}

둘. 토큰값 잘못 입력.
브라우저에 입력할 'https://api.telegram.org/Bot생성시 받은 TOKEN값/getUpdates' 에서 Token값에는 '603~~Xc0' 앞에 'bot'이라는 접두어를 붙어야 한다. 만약 그래도 오류가 나면, 값을 타이핑치지 말고 복사&붙여넣기로 입력..

# 대화시도 #

import telegram, asyncio             # 정책변경으로 async만 가능 

CHAT_ID = '5113996'                  # 상수는 대문자로 선언
TELE_TOKEN = '6030794********dXc0'   # 상수는 대문자로 선언

async def send_text(bot, text) :
    await bot.send_message(CHAT_ID, text)

msg = 'new is start yes' 
 
bot = telegram.Bot(token=TELE_TOKEN)
asyncio.run(send_text(bot, msg))

사전 확인한 CHAT_ID와 토큰으로 메시지를 보내면 된다. crontab 등으로 특정시간대가 되면, 웹크롤링을 수행하여 텔레그램으로 전달해주면 일일이 사이트를 조사할 필요없이 편리하게 이용 가능할 것 같다. 다른 예제들로는 Bot에게 특정어를 입력하면 해당 업무를 수행할 수 있도록 개발할 수도 있다.

# 트러블 슈팅 #

telegram.error.Forbidden: Forbidden: bot can't send messages to bots

Bot이 Bot에게 메시지를 전달할 수없다. 아마 여러분이 이용하고 입력한 CHAT_ID가 사용자나 사용자와 대화하고 있는 채팅방ID가 아닌 BotID일 수 있다. 다시 확인해보자.

RuntimeWarning: coroutine 'Bot.send_message' was never awaited

텔레그램 정책 변경으로 동기방식의 메시지 전송이 불가능하다. 인터넷의 대부분의 예제가
bot = telegram.Bot(token=TELE_TOKEN)
bot.send_message(CHAT_ID, msg)
이와 유사한데, 이제는 이렇게 보낼 수 없다. 위의 방식대로 asyncio.run()을 이용한 비동기 방식을 이용하자.

Posted by 목표를 가지고 달린다
,

웹크롤링 핵심인 웹element 식별. 그중에 Xpath에 대해 좀더 알아보자

XPATH 의미
./li 현재 태그의 바로 하위에 있는 li 태그
../li 바로 상위에 있는 태그의 하위에 있는 li 태그
//li 문서 전체 중 모든 li태그
//li//ul 문서 전체 중 모든 li 태그의 하위에 있는 모든 ul 태그
//li[@id='myid'] 문서 전체 중 id 속성이 'myid'인 li태그
//*[@id='myid'] 문서 전체 중 id 속성이 'myid'인 모든 태그
//input[@class!='myclass'] 문서 전체 중 class 속성이 'myclass'가 아닌 input 태그
//a[text() = '2'] 문서 전체 중 태그 내용이 '2' 인 a 태그
//a[contains(text(), '다음')] 문서 전체 중 태그 내용에 '다음' 이 포함되는 a 태그
//a[contains(@id,'this')] 문서 전체 중 id 속성에 'this'가 포함된 a 태그
//a[starts-with(@id, 'this')] 문서 전체 중 id 속성이 'this'로 시작되는 a 태그
//a[@class='myclass' and contains(text(), '제목')] 위의 조건을 2개 이상 요구할 경우 and 로 나열한다.
//a[@class='myclass' or contains(text(), '제목')] 위의 조건(2개 이상) 중 1개만 만족해도 된다면 or 로 나열한다

# Expected_conditions에 정의된 조건 목록(페이지 로딩 소요에 따른 이벤트 처리)

from selenium.webdriver.support import expected_conditions as EC
로 먼저 import 한다.

조건 클래스 의미 예시
title_is 웹사이트 제목이 특정 문자열과 일치 여부 확인 EC.title_is('네이버')
title_contains 웹사이트 제목에 특정 문자열 포함 확인 EC.title_contains('네이')
url_conditions 웹사이트 url(주소)에 특정 문자열 포함 확인 EC.url_contains('account')
visibility_of_element_located 특정 태그의 화면에 표시여부 확인 EC.visibility_of_element_located(By.ID, 'spec_id')
text_to_be_present_in_element 특정 태그 내용에 특정 문자열 포함 확인 EC.text_to_be_present_in_element_value(By.ID, 'spec_id'), '특정문자열')
element_to_be_clickable 특정태그 클릭가능 확인 EC.element_to_be_clickable(By.ID, 'spec_id')

# 파이썬에도 Thread(쓰레드)가 존재한다.#

try :
	t = Thread(target=함수명, args=(param1, param2..))
    t.start()
except Exception as e :
	pass #무시

위 처럼 except로 예외문에 대해서, print(e)를 출력해서 확인해도 내용 파악이 어렵다면, sys 모듈의 exc_info()함수를 호출해서 확인할 수도 있다.

import sys
try : 
	1/0
except :
	err = sys.exc_info()
    for e in err :
    	print(e)

# 자바처럼 생성자를 만들수 있다. __init()__.#

파이썬도 클래스를 생성할 수 있는데, 자바처럼 생성할때 인자를 받거나, 초기 작업을 하는 것은 선택적이다. 만약 초기작업이 필요하면, 아래와 같이, 클래스 안에 init함수를 선언하면 된다. 그리고 enter와 exit는 클래스 입장/퇴실할 때 호출되는 함수인데, 반복되는 내용을 입력하면 자동호출된다.
*클래스안에서 메소드 및 멤버 변수를 이용할 때, 반드시 self를 추가하지만, 이용할 때는 붙이지 않는다.

class Usedatabase :
	def __init__(self, config : dict) -> None :
    	self.configuration = config
        
    def __enter__(self) -> 'cursor' :
    	self.conn = mysql.connector.connect(**self.configuration)
        self.cursor = self.conn.cursor()
        return self.cursor
    
    def __exit__(self, exc_type, exc_value, exc_trace) -> None:
    	self.conn.commit()
        self.cursor.close()
        self.conn.close()

# 파일을 읽는 때는 with 절을 이용하세요. #

with open('vstart.log') as log :
	contents = log.read()

일반적으로 파일을 open('vstart.log', 'r') 로 읽어도 좋지만, with 문과 함께 쓴다면, 종료시 file.close()를 하지 않아도 자동으로 닫아준다. 큰 프로젝트가 아니라면 문제되지 않으나 개발자의 실수를 커버해주는 좋은 코딩 습관이다.

Posted by 목표를 가지고 달린다
,

selenium 이용 중 페이지 로딩을 기다리는 2가지 방법

#1. 항목을 가져와야 하는데, 오류 발생

object of type 'WebElement' has no len()

이런 경우, elems = driver.find_element(By.CLASS_NAME, '클래스명') 로 elems를 선언할 때, 함수를 단수형태로 가져왔기에 배열이 아니라, 단순(1개의) 항목이라 len(elems) 하면 오류가 발생한다. driver.find_elements(By.CLASS_NAME, '클래스명') 처럼 복수로 가져올 수 있도록 수정
#2. Xpath로 설정했는데, WebDriver(selenium)이 항목을 식별할 수 없다.

Message: no such element: Unable to locate element:

이런 경우, 문서 구조에서 iframe 을 포함하는 것인지 확인. 네이버 카페의 경우 "cafe_main" 이라는 iframe내에 게시글들이 들어가 있는 구조라서,
iframe = driver.find_element(By.ID, 'cafe_main')
driver.switch_to.frame(iframe)
이런식으로 driver를 switch해줘야 함. 만약 다시 원래 페이지 구조로 돌아오려면,
driver.switch_to_default_content()를 호출하면 됨.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.keys import Keys
from webdriver_manager.chrome import ChromeDriverManager
import time
import datetime as d
from openpyxl import Workbook

xlsx = Workbook()
sheet = xlsx.active
sheet.append(['Title', 'Link', 'Published date'])

try:
    options = Options()
    options.add_experimental_option("detach", True)
    options.add_experimental_option("excludeSwitches", ["enable-logging"])
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=options)
    
    keyword = '유형자산'                      
    driver.get('https://cafe.naver.com/parksamaccount')

    elem = driver.find_element(By.ID, 'topLayerQueryInput') 
    elem.send_keys(keyword)
    elem.send_keys(Keys.RETURN)

    iframe = driver.find_element(By.ID, 'cafe_main')
    driver.switch_to.frame(iframe)

    articles = driver.find_elements(By.CLASS_NAME, 'td_article')
    print(len(articles))
    for article in articles :
        title = article.find_element(By.TAG_NAME, "a")
        print(title.text)    
except Exception as e :
    print(e)    
finally :
    #driver.quit()
    print('ee')

#3. 책의 소스 또는 블로그의 소스가 실행이 안되는 경우, 참고하는 자료의 버전을 확인하고 버전을 맞춰본다.
print(library.__verison__) 확인후 재설치

Posted by 목표를 가지고 달린다
,

selenium 이용 중 페이지 로딩을 기다리는 2가지 방법

사실 3가지다. 첫번째는 sleep(3) 이런식으로 특정 시간(3~5초 정도) 기다리게 하는 것이다.
두번째는 클릭할 수 있는 객체가 나타낼때까지 기다기는 것이다. expected_conditions 포함

from selenium.webdriver.support import expected_conditions as EC

   driver.get('https://ww.instagram.com/')
    wait = WebDriverWait(driver, 5)   #최대 5초 기다림.
    cond = EC.element_to_be_clickable((By.LINK_TEXT, '로그인'))
    btn = wait.until(cond)
    btn.click()

세번째는 객체가 보여질 때까지 기다리는 것이다. expected_conditions 포함

from selenium.webdriver.support import expected_conditions as EC

    WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located(
          (By.CLASS_NAME, "_a9_1"))).click()

 

Posted by 목표를 가지고 달린다
,