사실 개인적으로 NumPy 공부가 처음이 아니기에,

너무 기본적인 부분은 skip 하고 계속 기억하면 좋을만한 것들만 추려서 포스팅하겠다.

 

 

1. Environment

 

뭔가 차별점을 두기 위해 실습 환경을 다음과 같이 정해서 진행해보겠다.

  - Ubuntu 20.04

  - Miniconda + conda-forge

  - Jupyter Notebook

 

혹시 모를 저와 같은 삐딱한 마음을 먹으신 분들이 계시면, 아래 링크를 참고하세요 ^^

- 회사에서 Anaconda 사용하기 (Miniconda + conda-forge)

 

conda를 이용하여 가상환경을 생성하고,

 

 

Jupyter Notebook 패키지들을 설치하고,

 

 

Jupyter Notebook을 실행하면 된다.

 

 

그러면 아래와 같이 예쁜 웹 페이지가 짜잔~

 

 

실제 잘 동작하는지까지만 조금 더 살펴보자.

 

 

Local 환경에서는 기본적으로 numpy 라이브러리도 설치가 안되어 있기에 필요하다면 설치를 해줘야 한다.

이런 불편함(?)이 앞으로 종종 발생하겠지만, 바로 이런 부분이 know-how 이자, 역량이라고 믿는다! 😁

 

 

 

2. Axis

매번 방향이 헷갈려서 일단 값 넣어보고, 결과 확인 후 '어? 이게 아닌가?'하는 ... 그 악명 높은 axis !!!

 

 

왜 axis 위치가 자꾸 변하는걸까?

아래 코드를 잘 살펴보자.

 

 

shape에서 나오는 순서대로 번호가 매겨진다고 생각하면 될 것 같다.

책에서는 다음과 같이 설명해주고 있다.

 

 

같은 이야기를 하고 있으니 각자 편한 방법으로 기억하면 되겠다.

 

 

 

3. Data Type

사실 그리 신경을 쓰지 않았던 부분이긴 한데,

이번에 데이터 타입 코드에 대해 새롭게 알게 되어서 좋았다! (비트와 바이트를 넘나드는 표기법 왠지 싫다!)

 

 

코드를 이용해서 확인해보면 다음과 같다.

 

 

기본값으로 64비트 = 8바이트나 사용하다니! 이런 부르주아 같은 넘파이 !!!

 

 

 

4. Make ndarray

리스트나 튜플로부터 넘파이 배열을 만드는 것은 아래 내용 참고해보면 된다.

 

 

일련의 데이터 생성과 함께 차원을 변경하는 것까지 살펴보면 다음과 같다.

 

 

이번에는 0부터 100까지의 임의의 숫자로 3차원 넘파이 배열을 만드는 것을 살펴보자.

 

 

수학의 기본은 0과 1이다 😁

원하는 차원만 입력해주면 된다.

 

 

 

 

5. Operations

이제 본격적으로 연산에 대해서 알아보자.

 

 

행렬에서의 사칙연산은 같은 위치끼리의 연산으로 이루어진다.

위의 예시를 꼼꼼하게 살펴보기 바란다.

 

하지만, 행렬 연산의 꽃은 사칙 연산이 아니라 "행렬 곱셈"이다.

영어로는 'Matrix Multiply"이지만, 약자인 "matmul"로 더 많이 불리운다.

연산 기호로는 "@"가 쓰인다.

 

 

우리의 colorful한 책에서는 다음과 같이 친절하게 연산 과정을 설명해준다!

이 그림 하나면 끝이다!!! 😍

 

 

의외로 종종 사용하게 되는 비교 연산도 할 수 있다.

 

 

 

 

6. Functions

넘파이가 기본적으로 제공해주는 다양한 함수들이 있다.

 

 

넘파이 함수에 배열을 넣어주는 방법 말고,

넘파이 배열에서 바로 함수를 호출하는 방법도 있다.

 

 

그런데, 모든 함수가 이렇게 되는 것은 아닌 것 같다.

조심해서 사용해야 할 것 같다.

 

 

많이 사용하는 집계 함수들에 대해서도 알아보자.

 

 

함수의 파라미터로 axis를 넣으면 원하는 방향으로의 값을 계산할 수도 있다.

 

 

 

 

7. Indexing and Slicing

넘파이 배열의 특정 위치에 있는 값을 확인하고 싶다면? 인덱싱을 이용하면 된다!

 

 

처음에 이런 사용법을 봤을 때 깜짝 놀랐다. ","를 사용하다니????

자고로 배열이라면 "[ ]"을 이용해야지 !!!

 

 

그렇다! 배열처럼 사용할 수도 있다.

 

하지만, 넘파이에서 다루는 데이터 타입을 배열이라 생각하지 말고,

"행렬"이라고 생각을 하면서 ","를 사용하는 것을 기준으로 삼아야 할 것이다 😎

 

이번에는 slicing에 대해서 살펴보자.

 

 

"asi[0, 0:2]"에 대해서 말로 설명을 해보면,

"0 행에 있는 0부터 2 이전까지(1까지)의 컬럼에 있는 값으로 이루어진 행렬(배열)"이다.

 

"맨 처음부터" 또는 "맨 끝까지"와 같은 표현도 가능하다.

 

 

아무것도 명시하지 않으면 all의 의미를 갖는다.

 

 

 

8. Boolean Indexing

넘파이 행렬에 특정 조건에 맞는지 여부를 확인하려면 다음과 같이 할 수 있다.

 

 

행렬 크기는 유지하면서 Boolen 값으로 채워지게 된다.

이것을 이용하면 다음과 같이 할 수 있다.

 

 

특정 조건에 맞는 값만 채워져있는 새로운 행렬(배열)이 만들어진다.

당연한 이야기이지만, 조건을 굳이 변수에 담지 않고 바로 사용할 수도 있다.

 

단순히 출력에만 이용할 것이 아니라 값 변경에도 활용할 수 있다.

 

 

 

 

9. Integer Array Indexing

특정 행렬(배열)에 있는 값들을 이용해서 다른 행렬을 만들고자 할 때 사용할 수 있는 방법이다.

 

 

다차원 형태로 만들 수도 있다.

 

 

 

 

10. reshape

ML이나 DS에서도 많으 쓰이지만, 특히 DL에서 많이 사용되는 reshape 😍 행렬(배열)의 형태 바꾸기 !!!

 

 

당연한 것이지만, 요소 개수가 맞아 떨어져야 한다.

만약 안맞으면?

 

 

에러를 밷어낸다 😅

 

특이한 파라미터 "-1"은 일종의 "auto"라고 보면 될 것 같다.

 

 

정해진 값을 기준으로 알아서 값을 맞춰준다.

 

reshape() 함수의 사촌인 resize() 함수도 있다.

 

 

reshape()은 원본을 직접 수정하지 않고, resize()는 원본 자체를 변경한다.

 

DL 공부할 때 많이 사용하는 평탄화(flatten)를 해보자.

 

 

실제로는 reshape(-1)을 많이 사용하는 것 같다.

 

 

 

11. Transpose

행과 열을 바꾸는 전치(transpose)에 대해서 살펴보자.

 

 

두 행렬을 행렬곱 하면 어떻게 될까?

 

 

첫번째 행렬의 행의 개수와 두번째 행렬의 열의 개수가 맞지 않아 행렬곱을 할 수가 없다.

앞 또는 뒤에 있는 행렬을 전치해줘야 한다.

 

 

원본 값을 수정하지는 않는다. 원본 자체를 바꾸고 싶으면 "bt = bt.T" 와 같이 사용해야 한다.

 

 

 

12. stack / split

행렬을 합치는 것이 stack, 분할하는 것이 split이다.

 

행렬을 합칠 때에는 수평(horizontal) 방향으로 합칠 것인지,

수직(vertical) 방향으로 합칠 것인지 정해서 해야 한다.

 

 

분할도 방식은 똑같은데, 몇 조각으로 쪼갤 것인지만 추가해주면 된다.

 

 

*stack 계열과 마찬가지로 사용할 수 있는 것이 conatenate() 함수도 있다.

 

 

axis 값을 이용해서 방향을 지정할 수가 있다.

그런데, 아래와 같은 에러를 만날 수 있다.

 

 

어!? 아까 vstack()은 잘 되었는데!? 왜 에러가!?

 

 

css 행렬을 경우 1차원이기 때문이다.

같은 차원끼리만 concatenate()를 할 수가 있다.

그래서 같은 차원으로 만들어서 진행하면 된다.

 

*split() 함수의 경우 행렬을 나눠주는 것인데,

마지막 2개의 행만 뽑아오고 싶거나 하면 어떻게 해야할까?

 

그런 경우에는 slicing을 이용하면 될 것 같다.

 

 

우와아아.... 정말 길다.

연습문제까지 포함하면 총 88페이지까지의 분량이다.

 

연습문제는 나중을 위해 아껴 두겠다. (절대 퓌곤해서가 아니다! 정말! 정말이라구!)

반응형

대학원 연합 모임을 같이 하는 분이 책을 냈다고 하여 바로 책을 구매했는데,

마침 또 이 책을 가지고 스터디를 한다고 하여 이렇게 기록을 위한 포스팅도 남겨 본다.

 

책 표지

 

처음엔 그냥 아는 분이 쓴 책이라 하여 별 생각없이 구매한건데,

유튜브 강의, 오픈카톡방, 핸드북 ... 그리고 이렇게 스터디 모임까지 직접 ... 와우! 정성이 가득 !!!!

 

표지의 저 우주인 캐릭터도 귀염뽀짝 😍

 

 

책 표지에서도 언급한 "데이터 분석 로드맵"

 

데이터 분석을 위해 어떤 공부를 해야하는지

전체적인 그림을 보면서 공부를 할 수 있어서 너무 좋을 것 같다.

 

데이터 분석 로드맵

 

개인적으로도 공부할 때,

전체적인 큰 흐름을 보면서 지금 어떤 부분을 하고 있는 것인지 확인하면서 공부하는 것을 너무 좋아한다!!!

 

 

이 책에서는 기본적인 개발 환경을 Google Colab으로 하고 있다.

 

"처음 공부하는 사람을 배려"했다는 저자의 말을 생각해보면,

가장 무난하고 개인 차이도 없을 것이라 괜찮긴 한데...

 

우리 회사같은 내부망 구성인 경우 Local 환경을 갖춰야 하는 경우도 있기에,

Mini-Conda 환경 구성 등을 소개해줬으면 더욱 더 좋았을거라 생각해본다 😎

 

 

실습에 필요한 CSV 파일 등은 아래와 같이 구글드라이브로 제공해준다.

GitHub Repository로 제공해주는 것이 더 편한데.... 🙄 (개인 취향)

 

데이터 파일

 

Notebook(Colab) 파일도 구글 드라이브로 제공해준다.

역시나, 개인적인 취향은 GitHub-Repository 인데.... 😥

 

Notebook 파일

 

Colab 파일 안에는 강의 슬라이드로 사용할 이미지도 들어가 있다.

 

강의 슬라이드

 

거기에다가 셀레나쌤의 직강 강의가 등록되어있는 유튜브 채널도 있다 !!!

- https://www.youtube.com/@SELENASSAM

 

youtube

 

셀레나쌤과 함께 스터디도 할 수 있고

질의 응답도 할 수 있는 카카오톡 오픈 채팅방도 있다.

 

 

 

그리고 파이썬 초보자를 위한 '파이썬 핸드북'도 PDF 파일로 제공해준다.

 

HANDBOOK

 

우와~

책 한 권 샀을 뿐인데, 뭔가 선물을 몽창 더 많이 받은 기분이다 😍 😍 😍

 

뭔가 몽창 받았으니, 열쒸미 공부해봐야겠다.

반응형

Pandas가 너무 유명하다보니

수 많은 alternative 라이브러리들이 쏟아지고 있으며 특히, 속도를 개선한 유형이 많다.

 

그러다가 Pandas 보다 100배 더 빠르다는 불오리를 발견하게 되었다.

- https://hwisnu.bearblog.dev/fireducks-pandas-but-100x-faster

 

 

응?! FireDocks가 대체 뭔데, 이런 성능을 보여준다는거지?!

- https://fireducks-dev.github.io/

 

 

성능이 너무 잘 나와서인지 최근 엄청난 뉴스들이 쏟아지고 있다.

성능도 성능이지만, 기존에 Pandas로 작성한 코드를 그대로 사용할 수 있다는 점도 또 하나의 매력이다.

 

실제 측정한 성능은 어떻게 될까?

- https://fireducks-dev.github.io/docs/benchmarks/

 

 

자기들이 측정한 것이라 믿지 못할 수도 있겠지만,

실험한 환경 및 코드를 모두 공개하고 있으니 거짓말은 아닐 것이다 ^^

 

직접 코드를 한 번 돌려봤다.

테스트 환경은 Google Colab을 사용했다.

 

 

현재 최신 버전은 v1.1.5 이다.

 

테스트를 하기 위한 데이터를 생성하고,

실제 groupby 및 mean 실행을 통해 연산을 하는 소요 시간 측정 코드를 작성했다.

 

 

Pandas로 실행을 했을 때엔 3초의 시간이 소요되었는데,

FireDucks는 눈 깜짝 할 사이에 실행이 되어버리는 것을 볼 수 있다.

 

 

라이브러리 호출 부분만 변경했을 뿐인데, 성능이 좋아진다면 사용하지 않을 이유가 없을 것 같다.

 

라이선스는 "the 3-Clause BSD License (the Modified BSD License)"이다.

- https://github.com/fireducks-dev/fireducks

 

 

이렇게 훌륭한 라이브러리를 누가 만들었을까!?

- https://www.nec.com/en/press/202310/global_20231019_01.html

 

 

응?! 여기에서 갑자기 NEC ?!

어쩐지 공식 홈페이지에서 지원하는 언어가 English 외에 Japanese가 있더라니...

 

한 때는 가전제품도 생산을 해서 가끔 눈에 띄이곤 했는데,

요즘은 B2B 사업이나 통신 설비 등에 주력해서인지 주변에서 잘 보이진 않는다.

하지만, 11만명 이상의 임직원이 있는 글로벌한 기업이다.

 

 AI 및 클라우드 사업도 한다고 하던데,

이런 훌륭한 라이브러리도 만들어서 공개하고.... 괜찮은데!?

반응형

안드레 카파시(Andrej Karpathy)와 더불어

초보 병아리들을 위한 강의에 정말 진심인 또 한 명의 명장, 앤드류 응(Andrew Ng) 아저씨 !!!

 

이번에는 파이썬 그것도 그냥 파이썬이 아니라 AI 파이썬 강의를 가지고 찾아오셨다.

- https://www.deeplearning.ai/short-courses/ai-python-for-beginners/

 

 

살짝 아쉬운 점은 한국어 더빙 또는 한글 자막이 있으면 좋았겠지만,

영어 자막 정도로 만족해야 한다. (훌륭한 무료 강의인데, 이것만으로도 감지덕지!)

 

 

출석부 도장 쾅!

 

 

동영상 녹화 강의 단점을 해소하기 위한 AI Chatbot을 제공해준다.

아쉽게도 한글은 안되고 영어로만 된단다.

 

Python 공부와 영어 공부를 한 번에 해결할 수 있다! (원영적 사고!)

 

 

강의를 꾸준하게 듣게 하기 위해 여러가지 수단을 동원하는 듯~ ^^

 

 

가장 멋진 부분 !!!

실습을 하는 환경도 하나의 화면에 같이 제공을 해준다 !!!

 

 

그냥 일반적은 그런 Python 초보 강의가 아니다.

"AI Python" 제목을 달고 있는 강의이다.

 

어떤 차이가 있냐고?

실습 프로젝트 자체가 다르다.

 

Custom Recipe Generator(맞춤형 레시피 생성기): Create an AI-powered tool that generates unique recipes based on available ingredients. You’ll use variables, f-strings, and AI prompts to craft personalized culinary creations.

 

- Smart To-Do List(스마트 할 일 목록): Build an intelligent task manager that not only stores your to-do items but also prioritizes them using AI. You’ll apply your knowledge of lists, dictionaries, and decision-making code to enhance productivity.

 

- Travel Blog Analyzer(여행 블로그 분석기): Develop a program that reads travel blog entries and uses AI to extract key information like restaurant names and popular dishes. This exercise showcases your ability to work with files and leverage AI for text analysis.

 

- Dream Vacation Planner(꿈의 여행 일정 설계자): Create a sophisticated itinerary generator that takes a multi-city trip plan and uses AI to suggest daily activities, including restaurant recommendations. You’ll work with CSV files, dictionaries, and AI prompts to build this comprehensive travel tool.

 

- Data Visualization Project(데이터 시각화 프로젝트): Using popular Python libraries like matplotlib, you’ll create visual representations of data. This could involve plotting price trends of used cars or visualizing travel statistics from your vacation planner.

 

- Web Data Extraction(웹 데이터 추출): Use the BeautifulSoup library to scrape web pages and extract useful information, opening up a world of data for your projects.

 

- Real-time Data Application(실시간 데이터 응용 프로그램): Build a program that interacts with web APIs to fetch and process real-time data, such as current weather information or live currency exchange rates.

 

 

AI와 Python에 관심이 있는 초보자들을 대상으로 하고 있는 훌륭한 강의이다.

이 모든 것이 무료로 제공되는데도 공부를 하지 않는 다면 .... 반성해야 한다!!!

 

반응형

간만에 VirtualBox 관련 포스팅을 해본다 ^^

 

Host OS: Windows 11

Guest OS: Ubuntu 20.04

VirtualBox: 버전 7.1.4 r165100 (Qt6.5.3)

 

부팅할 때의 화면이다.

사용에는 별다른 이슈는 없는 상태이다.

 

 

GuestOS 켤 때마다 나오는 마음에 들지 않는 메시지를 전부 없애고 싶다!!!

 

RDRAND gives funky smelling output, might consider not using it by booting with "nordrand"

 

AMD CPU 사용에 따른 문제인 것으로 보이는데, 아직 명확한 해결법을 찾지 못해서 지금은 Skip!!!

어짜피 사용에 있어서는 문제가 없는 것이기에...

 

 

그럼 다음 문제를 살펴보자.

 

VirtualBox Error 'drm:vmw_host_printf [vmwgfx]] *ERROR* Failed to send host log message'

 

 

이건 확실히 에러 메시지다!

디스플레이 설정을 바꿔주면 해결이 된단다.

 

 

"VBoxVGA"로 설정을 바꿔주면 된단다.

경고 메시지가 보이기는 하는데, 필요에 따라 사용할 수 있는 옵션이기에 그냥 선택하면 된다.

 

 

확실히 사라졌다!!!

 

반응형

개인적으로 뭘 해보고자 하는게 있어서 요즘 잠깐 잠깐 만들고 있는 프로젝트가 있다.

- NAVER API를 이용해서 블로그 검색하기 (with Python)

 

그런데, 검색된 블로그 포스팅들을 화면에 출력만 할 것이 아니라 저장을 해놓고 싶은데,

그냥 JSON 형태로 저장하거나 CSV 형태로 저장하기엔 싫어서 SQLite를 이용해보려고 한다.

 

SQLite에 대한 기본적인 사항은 다음 포스팅을 참고하기 바란다.

- SQLite에 대해서 알아보자

 

 

0. 개발 환경

- OS: Ubuntu 20.04

- Lang: Python 3.10.9

 

 

1. 기본 코드

블로그 포스팅을 검색하는 코드는 이미 아래와 같이 살펴봤다.

- NAVER API를 이용해서 블로그 검색하기 (with Python)

 

 

2. SQLite 활용

기본 작성한 코드에서 이것 저것 좀 많이 업그레이드 시켰다.

 

에러메시지는 log로 남기도록 했고,

태그를 지우는 것은 BeautifulSoup 패키지를 활용하도록 했다.

 

import requests
import os
import sqlite3
from bs4 import BeautifulSoup
import logging

# 로깅 설정
logging.basicConfig(level=logging.ERROR)

class BlogPost:
    def __init__(self, title, description, link, postdate):
        self.title = self.clean_html(title)
        self.description = self.clean_html(description)
        self.link = link
        self.postdate = postdate

    def clean_html(self, text):
        if text:
            return BeautifulSoup(text, "html.parser").get_text()
        return ""

    def __str__(self):
        return f"Title: {self.title}\nDescription: {self.description}\nURL: {self.link}\nPost Date: {self.postdate}\n"

class NaverBlogSearcher:
    def __init__(self):
        self.client_id = os.getenv("NAVER_CLIENT_ID")  # 환경변수에서 Client ID 읽어오기
        self.client_secret = os.getenv("NAVER_CLIENT_SECRET")  # 환경변수에서 Client Secret 읽어오기

        # 환경변수 값이 없을 때 예외 처리
        if not self.client_id or not self.client_secret:
            logging.error("NAVER_CLIENT_ID and NAVER_CLIENT_SECRET must be set as environment variables.")
            raise ValueError("NAVER_CLIENT_ID and NAVER_CLIENT_SECRET must be set as environment variables.")

    def get_blog_posts(self, query, display=10):
        # 요청 URL 및 헤더 구성
        url = f"https://openapi.naver.com/v1/search/blog.json?query={query}&display={display}&sort=date"
        headers = {
            "X-Naver-Client-Id": self.client_id,
            "X-Naver-Client-Secret": self.client_secret,
        }

        # 네이버 API에 요청 보내기
        try:
            response = requests.get(url, headers=headers)
            response.raise_for_status()
        except requests.exceptions.RequestException as e:
            logging.error(f"Network error occurred: {e}")
            return []
        
        if response.status_code == 200:
            return self.parse_response(response.json())
        else:
            print(f"Error: {response.status_code}, {response.text}")
            return []

    def parse_response(self, data):
        # 응답 데이터 파싱
        blogs = data.get("items", [])
        blog_posts = [BlogPost(blog.get("title"), blog.get("description"), blog.get("link"), blog.get("postdate")) for blog in blogs]
        return blog_posts

class BlogPostDBHandler:
    def __init__(self, db_name="blog_posts.db"):
        self.db_name = db_name
        self.create_table()

    def create_table(self):
        # SQLite 데이터베이스 연결
        with sqlite3.connect(self.db_name) as conn:
            cursor = conn.cursor()

            # 테이블 생성
            cursor.execute('''
                CREATE TABLE IF NOT EXISTS BlogPosts (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    title TEXT,
                    description TEXT,
                    link TEXT UNIQUE,
                    postdate TEXT
                )
            ''')

    def save_to_db(self, blog_posts):
        # SQLite 데이터베이스 연결
        with sqlite3.connect(self.db_name) as conn:
            cursor = conn.cursor()

            # 데이터 삽입 (중복 확인)
            for post in blog_posts:
                cursor.execute('''
                    SELECT COUNT(*) FROM BlogPosts WHERE link = ?
                ''', (post.link,))
                if cursor.fetchone()[0] == 0:
                    cursor.execute('''
                        INSERT INTO BlogPosts (title, description, link, postdate) 
                        VALUES (?, ?, ?, ?)
                    ''', (post.title, post.description, post.link, post.postdate))

    def get_all_posts(self):
        # SQLite 데이터베이스 연결
        with sqlite3.connect(self.db_name) as conn:
            cursor = conn.cursor()

            # 저장된 블로그 포스팅의 모든 필드 가져오기
            cursor.execute('''
                SELECT title, description, link, postdate FROM BlogPosts
            ''')
            rows = cursor.fetchall()

        # 필드명을 갖는 dict 형태로 변환
        posts = [
            {"title": row[0], "description": row[1], "link": row[2], "postdate": row[3]} 
            for row in rows
        ]
        return posts

if __name__ == "__main__":
    # "동탄" 검색어로 최신 블로그 정보 가져오기
    try:
        searcher = NaverBlogSearcher()
        blog_posts = searcher.get_blog_posts("동탄")
        
        # 검색 결과 출력
        # for post in blog_posts:
        #     print(post)
        
        # 검색 결과를 SQLite 데이터베이스에 저장
        db_handler = BlogPostDBHandler()
        db_handler.save_to_db(blog_posts)

        # 저장된 블로그 포스팅의 제목 출력
        posts = db_handler.get_all_posts()
        for post in posts:
            print(f"Title: {post['title']}")
    except ValueError as e:
        print(e)

 

TABLE이 존재하지 않으면 create 하도록 했으며,

블로그 포스팅을 insert 하기 전에 기존에 있는지 미리 확인한 후에 없을 때에만 insert 하도록 했다.

 

아직은 PoC 성격의 스크립트 이기에,

SQLite에 저장한 이후에 전체 포스팅 목록을 SQLite로부터 읽어와서 제목들을 출력하도록 했다.

 

그리고,

추가 설치해야할 패키지들이 있기에 requirements.txt 파일도 업데이트 되었다.

 

beautifulsoup4==4.12.3
requests==2.32.3

 

 

3. Execute

실행 결과도 확인 해보고, database 내용도 살펴보자.

 

> dotenvx run -f .env -- python main.py

 

 

이렇게 저장을 하면 database 파일이 하나 생성되는 것을 확인할 수 있다.

- blog_posts.db

 

 

 

4. Check

db 파일을 확인해보기 위해서 "DB Browser for SQLite"를 사용해보겠다.

 

 

설치는 그냥 패키지 설치하면 된다.

 

> sudo apt-get install sqlitebrowser

 

잘 설치되어 있는 것을 볼 수 있다.

 

 

실행하고, "데이터베이스 열기" 하고 db 파일을 선택해주면 된다.

 

 

"데이터 보기" 탭을 선택하면 저장된 내역을 볼 수 있다.

 

 

 

오늘은 여기까지~

반응형

내 블로그를 오랫동안 보셨던 분들이라면

내가 git을 상당히 오랫동안 다뤄왔다는 것을 아실 수 있을 것이다.

 

git 자체에 대한 것은 물론이고

호스팅을 위한 gitolite 부터 시작해서, Gerrit 이라던지 지금은 GitHub 까지 ...

 

그런데, 요즘은 워낙에 GitHub가 시장을 평정해버려서

git 관련한 대부분의 것들의 표준이 GitHub에서 어떻게 하는지...가 되어버렸다.

 

그리고 많은 분들이 GUI 기반의 git 도우미들을 사용하곤 한다.

 

하지만, git 초심자를 좀 벗어나게 되면

많은 분들이 CLI 방식으로 git을 사용하게 된다. (사실 이게 더 편한 것 같다!)

 

CLI 방식으로 git을 사용할 때 가장 아쉬운 것이 코드를 살펴볼 때인데...

이걸 해결해주는(?!) 재미있는 도구가 있어서 한 번 설치해봤다.

 

 

1. Delta

의외로 문서화가 잘되어 있어서 깜짝 놀랐다.

- https://dandavison.github.io/delta/

 

 

 

감사하게도 MIT 라이선스이다.

Star 갯수도 ... 우와 !!!

- https://github.com/dandavison/delta

 

 

 

 

2. Installation

지원해주는 설치 플랫폼을 보고선 또 한 번 깜짝 !!!!!

- https://dandavison.github.io/delta/installation.html

 

 

 

Debian 계열은 release 페이지에 가서 다운로드 받으라네...

- https://github.com/dandavison/delta/releases

 

 

 

잉?! 버전은 아직도 v0.18.2 ... 내 생에 v1.0을 보지는 못할 것 같네 ^^ ㅋㅋ

다운로드 받아서 설치하자.

> wget https://github.com/dandavison/delta/releases/download/0.18.2/git-delta_0.18.2_amd64.deb

> sudo dpkg --install ./git-delta_0.18.2_amd64.deb

 

금방 설치된다.

 

 

3. Environment

'.gitconfig' 파일에 설정을 해줘야 한다.

 

 > nano ~/.gitconfig

 

[core]
    pager = delta

[interactive]
    diffFilter = delta --color-only

[delta]
    navigate = true  # use n and N to move between diff sections
    dark = true      # or light = true, or omit for auto-detection
    line-numbers = true
    side-by-side = true
    
[merge]
    conflictstyle = zdiff3

 

 

 

4. Just Do It

간단히 살펴보기 위해서 commit 확인 후 'git show'를 해봤다.

 

❯ git log --oneline --graph

❯ git show 2a9249a

 

 

line number 뿐만 아니라 전체적으로 GUI 못지 않은 깔끔함 !!!

 

심지어 Syntax highlighting도 잘 해준다.

 

 

우왕~

내 기본 환경에 포함시켜놔야 할 유틸리티이다 !!!

 

자세한 사용법은 공식 사이트를 참고하세요~

 

반응형

여기에서 해보고 싶은 것은 "동탄" 키워드가 들어간 최근 블로그를 검색해서

그 제목과 본문 내용, 링크 값을 얻어오는 코드를 작성해보고자 한다.

 

0. 개발 환경

- OS: Ubuntu 20.04

- Lang: Python 3.10.9

 

 

1. 준비

① NAVER API를 사용하기 위해 API 키를 생성하자.

    - NAVER 서비스 API 사용 준비

 

② 환경변수를 다루기 위해서 dotenvx를 사용해보자.

    - 아는 사람만 쓴다는 Config 관리자 - dotenv, dotenvx

 

 

2. 코드 작성

일단 API 호출을 위해 requests 패키지를 사용하기로 했다.

 

[ requirements.txt ]

requests==2.32.3

 

가급적 클래스 구조로 작성해봤다.

[ main.py ]

import requests
import os

class BlogPost:
    def __init__(self, title, description, link):
        self.title = title.replace("<b>", "").replace("</b>", "")
        self.description = description.replace("<b>", "").replace("</b>", "")
        self.link = link

    def __str__(self):
        return f"Title: {self.title}\nDescription: {self.description}\nURL: {self.link}\n"

class NaverBlogSearcher:
    def __init__(self):
        self.client_id = os.getenv("NAVER_CLIENT_ID")  # 환경변수에서 Client ID 읽어오기
        self.client_secret = os.getenv("NAVER_CLIENT_SECRET")  # 환경변수에서 Client Secret 읽어오기

        # 환경변수 값이 없을 때 예외 처리
        if not self.client_id or not self.client_secret:
            raise ValueError("NAVER_CLIENT_ID and NAVER_CLIENT_SECRET must be set as environment variables.")

    def get_blog_posts(self, query, display=10):
        # 요청 URL 및 헤더 구성
        url = f"https://openapi.naver.com/v1/search/blog.json?query={query}&display={display}&sort=date"
        headers = {
            "X-Naver-Client-Id": self.client_id,
            "X-Naver-Client-Secret": self.client_secret,
        }

        # 네이버 API에 요청 보내기
        response = requests.get(url, headers=headers)
        
        if response.status_code == 200:
            return self.parse_response(response.json())
        else:
            print(f"Error: {response.status_code}, {response.text}")
            return []

    def parse_response(self, data):
        # 응답 데이터 파싱
        blogs = data.get("items", [])
        blog_posts = [BlogPost(blog.get("title"), blog.get("description"), blog.get("link")) for blog in blogs]
        return blog_posts

if __name__ == "__main__":
    # "동탄" 검색어로 최신 블로그 정보 가져오기
    try:
        searcher = NaverBlogSearcher()
        blog_posts = searcher.get_blog_posts("동탄", 3)
        for post in blog_posts:
            print(post)
    except ValueError as e:
        print(e)

 

환경 변수도 작성했다.

[ .env ]

NAVER_CLIENT_ID=""
NAVER_CLIENT_SECRET=""

 

 

3. 실행

dotenvx를 사용해서 실행했다.

> dotenvx run -f .env -- python main.py

 

나름 잘 진행되었다 !!! (스스로 뿌듯~)

반응형

+ Recent posts