지난 시간에는 argparse
모듈을 활용해 커맨드 라인 프로그램을 만드는 법에 대해 알아봤습니다. 이번에는 click
모듈을 사용하여 커맨드 라인 프로그램을 만드는 법에 대해 소개하겠습니다.
click
모듈
argparse
뿐만이 아니라 click
모듈도 많이 사용됩니다. click
모듈은 argparse
에서 제공하는 기능을 보다 쉽고, decorator
를 사용해 보다 깔끔하게 사용할 수 있게 해줍니다. Flask
에서 CLI(Command Line Interface)
를 구현하기 위해 사용한 모듈이기도 합니다.
click
을 사용하여 argparse
와 똑같은 코드를 작성해보겠습니다. 이번엔 프로젝트명을 hello
대신 cello
를 사용하겠습니다.
# cello/main.py
import click
import sys
def say_hello(name):
# print와 같지만, python2역시 지원하기 위해 사용하는 click.echo
click.echo("Hello, {}".format(name))
def say_goodbye(name):
click.echo('Good bye, {}'.format(name))
# click 데코레이터
@click.option('--bye', is_flag=True, help="say good bye.")
@click.option('--hello', is_flag=True, help="say hello.")
@click.option('-v', '--version', is_flag=True, help="Show version of this program.")
@click.argument('name')
@click.command()
def main(name, version, hello, bye):
if version:
print('1.0.0')
sys.exit()
# 함수명과 인자명을 구분하기 위해 say_hello / say_goodbye로 함수명을 바꿈
if bye:
say_goodbye(name)
else:
say_hello(name)
if __name__ == "__main__":
main()
제 기준으로는 argparse
보다 가독성이 좋은 거 같습니다. (개인차가 있으리라 생각됩니다.)
위의 프로그램은 다음과 같은 명령어로 실행할 수 있습니다.
$ python main.py --help
>>
Usage: main.py [OPTIONS] NAME
Options:
-v, --version Show version of this program.
--hello say hello.
--bye say good bye.
--help Show this message and exit.
$ python main.py sjquant --hello
>> Hello, sjquant
$ python main.py sjquant --bye
>> Good bye, sjquant
역시 setup.py를 정의해주면 cello
라는 명령어로 사용할 수 있습니다.
# setup.py
from setuptools import setup, find_packages
setup(
name='cello',
version='1.0.0',
author='SJQuant',
author_email='seonujang92@gmail.com',
description='Greet someone',
packages=find_packages(),
entry_points={
"console_scripts": [
"cello = cello.main:main"
]
},
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
],
)
$ python setup.py install
$ cello sjquant --bye
>> Good bye, sjquant
click.group
click.group
을 사용하면 main
함수 이외에도 cli
명령어를 정의해서 사용할 수 있습니다. 네이버 영어사전을 크롤링하는 간단한 프로그램을 만들어봤습니다. 코드가 좀 길게 느껴질 수도 있는데, 세부적인 내용은 스킵하고 click
데코레이터를 사용한 부분과 main
함수부분만 읽으셔도 무방합니다.
# ndict/main.py
import click
import requests
from bs4 import BeautifulSoup
# -h로도 help를 볼 수 있게 help option 재정의
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
# cli라는 group 생성
@click.group(context_settings=CONTEXT_SETTINGS)
def cli():
"""
Simple CLI for crawling Naver Dictionary
"""
pass
def search_meaining(word, url):
"""
search meaning from given url
Params
----------
word: str
url: str
"""
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')
try:
word_box = soup.select('.word_num .list_e2')[0]
except IndexError:
import sys
click.echo('"{}"에 대한 검색결과가 없습니다.'.format(word))
sys.exit()
info = word_box.find('dd').find('p')
if info.find('span')['class'][0] == 'fnt_k05':
# 한영
word_class = None
else:
# 영한
word_class = word_box.select('dd p .fnt_k09')[0].text
meaning = word_box.select('dd p .fnt_k05')[0].text
try:
example = word_box.select('dd p .fnt_e07._ttsText')[0].text
except IndexError:
example = None
click.echo('"{}"에 대한 검색결과'.format(word))
click.echo('='*80)
if word_class:
click.echo('품사: {}'.format(word_class))
click.echo('의미: {}'.format(meaning))
if example:
click.echo('예문: {}'.format(example))
def search_example(word, url):
"""
search example from given url
Params
----------
word: str
url: str
"""
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')
try:
word_box = soup.select('.word_num .list_a')[0]
except IndexError:
import sys
click.echo('"{}"에 대한 검색결과가 없습니다.'.format(word))
sys.exit()
examples_eng = word_box.select('.fnt_e09._ttsText')
examples_kr = word_box.select('div.fnt_k10')
click.echo('"{}"에 대한 검색결과'.format(word))
click.echo('='*80)
index = 1
for eng, kr in zip(examples_eng, examples_kr):
click.echo(index)
click.echo(eng.text)
click.echo(kr.text)
index += 1
@click.command(help="This searches and returns meaning of a word from Naver Dictionary")
@click.argument('word')
@click.option('-e', '--english-only', is_flag=True, help="Show english version of meaning")
def meaning(word, english_only):
"""
This searches and returns meaning of a word from Naver Dictionary
Params
----------
word: str
word to search
english_only: bool
if True, search only english version of meaning
"""
if english_only:
url = 'https://endic.naver.com/search.nhn?sLn=kr&query={}&searchOption=all&isOnlyViewEE=Y'.format(
word)
else:
url = "https://endic.naver.com/search.nhn?sLn=kr&searchOption=all&query={}".format(
word)
search_meaining(word, url)
@click.command(help="This searches and returns examples of a word from Naver Dictionary")
@click.argument('word')
def example(word):
"""
This searches and returns examples of a word from Naver Dictionary
Params
----------
word: str
word to search
"""
url = "https://endic.naver.com/search.nhn?sLn=kr&searchOption=all&query={}".format(
word)
search_example(word, url)
def main():
# cli 그룹에 meaning과 example 커맨드 추가
cli.add_command(meaning)
cli.add_command(example)
cli()
if __name__ == "__main__":
main()
setup.py
는 다음과 같이 정의되어 있습니다.
# setup.py
from setuptools import setup, find_packages
setup(
name='ndict',
version='1.0.0',
author='SJQuant',
author_email='seonujang92@gmail.com',
description='Simple CLI for crawling Naver Dictionary',
packages=find_packages(),
entry_points={
"console_scripts": [
"ndict = ndict.main:main"
]
},
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
],
)
설치한 프로그램은 다음과 같이 사용할 수 있습니다.
$ ndict --help
>>
Usage: ndict meaning [OPTIONS] WORD
This searches and returns meaning of a word from Naver Dictionary
Options:
-e, --english-only Show english version of meaning
-h, --help Show this message and exit.
E:\dev\click_tutorial\ndict>ndict --help
Usage: ndict [OPTIONS] COMMAND [ARGS]...
Simple CLI for crawling Naver Dictionary
Options:
-h, --help Show this message and exit.
Commands:
example This searches and returns examples of a word from Naver...
meaning This searches and returns meaning of a word from Naver Dictionary
$ ndict meaning --help
>>
Usage: ndict [OPTIONS] COMMAND [ARGS]...
Simple CLI for crawling Naver Dictionary
Options:
-h, --help Show this message and exit.
Commands:
example This searches and returns examples of a word from Naver...
meaning This searches and returns meaning of a word from Naver Dictionary
E:\dev\click_tutorial\ndict>ndict meaning --help
Usage: ndict meaning [OPTIONS] WORD
This searches and returns meaning of a word from Naver Dictionary
Options:
-e, --english-only Show english version of meaning
-h, --help Show this message and exit.
$ ndict meaning program
>>
"program"에 대한 검색결과
================================================================================
품사: [명사]
의미: 프로그램
예문: Load the program into the computer.
$ ndict example program
>>
"program"에 대한 검색결과
================================================================================
1
Displays program information , version number , and copyright .
프로그램 정보, 버전 번호, 저작권을 표시합니다.
2
Tom turned in to documentary program for his report .
탐은 그의 리포트를 위해서 다큐멘터리 프로그램에 채널을 맞추었다.
3
This program is allowed for children above 8 years old .
이 프로그램은 8세 이상의 어린이에게만 허용된다.
4
The news program was bitten off .
뉴스 프로그램은 잘렸다.
5
This program is sponsored by B publishing company .
이 프로그램은 B출판사 제공이었습니다
더 공부하기
click 문서를 살펴보시면 이번 튜토리얼에서 다루지 않은 다양한 사용법을 확인할 수 있습니다.
또한, click
을 커맨드 라인 툴로 사용하고 있는 가장 유명한 파이썬 웹 프레임워크 중 하나인 Flask
의 cli.py
(클릭)를 살펴보시는 것도 좋습니다.
나만을 위한 프로그램 / 나의 생산성을 위한 프로그램은 GUI(Graphical User Interface)보다 CLI(Command Line Interface)가 정답인 경우가 많습니다. 혹은 jupyter
처럼 CLI를 GUI를 실행하기 위한 툴로서 사용하는 것도 좋은 거 같습니다. 이번 튜토리얼이 여러분의 생산성 향상에 도움이 되었으면 좋겠습니다. 감사합니다.
'개발 > 파이썬' 카테고리의 다른 글
[TIL] JWT 토큰 쿠키에 저장하기 (Flask) (0) | 2019.05.05 |
---|---|
파이썬 크롤링 공부, 도움받은 자료 모음 (0) | 2019.03.21 |
파이썬으로 만드는 나만의 커맨드라인 프로그램 #1 - argparse (0) | 2019.03.10 |
파이썬과 비동기 프로그래밍 #3, 파이썬에서 비동기 프로그래밍 활용하기 (14) | 2019.03.01 |
파이썬과 비동기 프로그래밍 #2, 파이썬에서 비동기 프로그래밍 시작하기 (0) | 2019.03.01 |