์ƒˆ์†Œ์‹

๐Ÿ’ก Projects/ํ† ์ด ํ”„๋กœ์ ํŠธ

[Python] ์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค ๋งŒ๋“ค๊ธฐ

2022. 9. 22. 22:39

  • -

๊ฐœ์š”

 

  • ํ”„๋กœ์ ํŠธ๋ช…: ์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค ๋งŒ๋“ค๊ธฐ
  • ์ œ์ž‘ ๊ธฐ๊ฐ„: 2022.09.19 ~ 2022.09.22
  • ๋ชฉํ‘œ: ์Œ์„ฑ์ธ์‹ ๊ธฐ์ˆ (STT, TTS) ๊ตฌํ˜„, ์›น ์Šคํฌ๋ž˜ํ•‘ ์ตํžˆ๊ธฐ
  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
    • OS: MacOS M1
    • IDE: VSCode



๋งŒ๋“  ๊ณ„๊ธฐ

 

์œ ํŠœ๋ธŒ๋ฅผ ๋ณด๋‹ค๊ฐ€ ๋‚˜๋„์ฝ”๋”ฉ๋‹˜์˜ ์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค ๋งŒ๋“ค๊ธฐ ใ€ํŒŒ์ด์ฌใ€‘ ์˜์ƒ์„ ๋ดค๋Š”๋ฐ ์ธํŠธ๋กœ 20์ดˆ ๋ณด๊ณ  ๋ฐ”๋กœ ๋‚˜๋„ ๋งŒ๋“ค์–ด ๋ณด๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ์Œ์„ฑ์ธ์‹ ์„ฑ๋Šฅ์ด ๊ต‰์žฅํžˆ ์ž˜ ๋‚˜์™€์„œ ์•ˆ ๋”ฐ๋ผ ํ•ด ๋ณผ ์ˆ˜๊ฐ€ ์—†์—ˆ์Œ!
๊ทธ๋ฆฌ๊ณ  ์ง€๋‚œ ๋‹ฌ์— ์ง€์›ํ–ˆ์—ˆ๋˜ <2022 ํ•œ๊ตญ์–ด AI ๊ฒฝ์ง„๋Œ€ํšŒ> ์‚ฌ์ „๊ณผ์ œ๋กœ wav ํŒŒ์ผ์„ ๋‹ค๋ค„ ๋ณผ ์ผ์ด ์žˆ์—ˆ๋Š”๋ฐ ๋‹น์‹œ ์Œ์„ฑ ๋ฐ์ดํ„ฐ๋Š” ์ฒ˜์Œ ๋‹ค๋ค„๋ณด๋Š” ๊ฑฐ๋ผ ๋„ˆ๋ฌด ์–ด๋ ต๊ฒŒ ๋Š๊ปด์กŒ์—ˆ๋‹ค. ๊ทธ๋•Œ ์•„์‰ฌ์›€์ด ์ข€ ๋‚จ์•„์„œ ์ด๋ฒˆ์— ์˜์ƒ์„ ๋”ฐ๋ผ ํ•˜๋ฉด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ฉด ์ข€ ๋” ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„ ๋„์ „ํ–ˆ๋‹ค.



์‚ฌ์šฉ ๊ธฐ์ˆ 

 

TTS(Text To Speech)

  • gTTS
  • playsound
  • PyObjC

STT(Speech To Text)

  • SpeechRecognition
  • PyAudio

์›น ์Šคํฌ๋ž˜ํ•‘

  • beautifulsoup4



๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

 

๐Ÿ“ฆAI_Speaker
 โ”ฃ ๐Ÿ“‚myenv
 โ”ƒ โ”ฃ ๐Ÿ“‚bin
 โ”ƒ โ”ฃ ๐Ÿ“‚include
 โ”ƒ โ”ฃ ๐Ÿ“‚lib
 โ”ฃ ๐Ÿ“‚scrape
 โ”ƒ โ”ฃ ๐Ÿ“‚__pycache__
 โ”ƒ โ”ฃ ๐Ÿ“œnaver_exchange_rate.py
 โ”ƒ โ”— ๐Ÿ“œnaver_weather.py
 โ”ฃ ๐Ÿ“‚TTS_STT
 โ”ƒ โ”ฃ ๐Ÿ“œsample.txt
 โ”ƒ โ”ฃ ๐Ÿ“œsample_fr.txt
 โ”ƒ โ”ฃ ๐Ÿ“œspeech_to_text.py
 โ”ƒ โ”— ๐Ÿ“œtext_to_speech.py
 โ”ฃ ๐Ÿ“œreqirements.txt
 โ”— ๐Ÿ“œspeaker.py



์ฐธ๊ณ 

 

์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค ๋งŒ๋“ค๊ธฐ ใ€ํŒŒ์ด์ฌใ€‘

ํŒŒ์ด์ฌ ๊ฐ€์ƒํ™˜๊ฒฝ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• | venv

ํŒŒ์ด์ฌ ์ฝ”๋”ฉ ๋ฌด๋ฃŒ ๊ฐ•์˜ (ํ™œ์šฉํŽธ3) - ์›น ํฌ๋กค๋ง/์›น ์Šคํฌ๋ž˜ํ•‘

34.2 ํด๋ž˜์Šค ์†์„ฑ ์‚ฌ์šฉํ•˜๊ธฐ



์ œ์ž‘ ๊ณผ์ •

 

TTS ์‹ค์Šต

 

TTS ์‹ค์Šต์€ ์•„์ฃผ ์Šค๋ฌด์Šคํ•˜๊ฒŒ ์ง„ํ–‰๋๋‹ค.
์งง์€ ๋ฌธ์žฅ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ 3์ค„ ์ด์ƒ์˜ ๊ธด ๋ฌธ์žฅ๋“ค๋„ ์Œ์„ฑ์œผ๋กœ ์ž˜ ์žฌ์ƒ๋๋‹ค.

from gtts import gTTS
from playsound import playsound

# ํ•œ๊ตญ์–ด ์งง์€ ๋ฌธ์žฅ ํ…Œ์ŠคํŠธ
text = '์ €๋Š” ๊ธฐ๊ณ„์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ดœ์ฐฎ์•„ ๋ณด์ด์ฃ ?'
file_name = 'sample.mp3'
tts_ko = gTTS(text=text, lang='ko') # gTTS(text=, lang=) -> text: gTTSํ•  ํ…์ŠคํŠธ, lang: ์–ธ์–ด (ํ•œ๊ธ€ = 'ko')
tts_ko.save(file_name) 
playsound(file_name) # .mp3 ํŒŒ์ผ ์žฌ์ƒ


# ํ•œ๊ตญ์–ด ๊ธด ๋ฌธ์žฅ ํ…Œ์ŠคํŠธ (ํŒŒ์ผ ๋ถˆ๋Ÿฌ์™€์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ)
# sample.txt -> ํ•œ๊ตญ์–ด ๋ฌธ์žฅ์ด ๋“ค์–ด์žˆ๋Š” ํ…์ŠคํŠธ ํŒŒ์ผ
with open('TTS_STT/sample.txt', 'r', encoding='utf8') as f: # ํŒŒ์ผ์„ ํ•œ๊ธ€๋กœ ์ฝ์–ด์˜ฌ ๊ฑฐ๋‹ˆ๊นŒ encoding='utf8'
    text = f.read()

file_name = 'sample.mp3'
tts_ko = gTTS(text=text, lang='ko') 
tts_ko.save(file_name) 
playsound(file_name) 
  • gTTS()์—์„œ๋Š” ์–ธ์–ด๋ฅผ ์ž…๋ ฅํ•  ๋•Œ 'lang'์œผ๋กœ ์ž‘์„ฑ

 

โ—๏ธ์—๋Ÿฌ 

 

์‹ค์Šตํ•  ๋•Œ๋Š” text_to_speech.py ํŒŒ์ผ ์ž์ฒด๋ฅผ ๋”ฐ๋กœ ํด๋”์— ๋„ฃ์ง€ ์•Š์•„์„œ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๋Š”๋ฐ
๋‹ค ๋งŒ๋“ค๊ณ  ๋‚œ ํ›„์— ์‹ค์Šตํ–ˆ๋˜ ํŒŒ์ผ๋“ค์„ TTS_STT ํด๋”๋กœ ์ด๋™ํ•˜๋ฉด์„œ sample.txt ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ๋‹ค์‹œ ์„ค์ •ํ•ด์ค˜์•ผ ํ–ˆ๋‹ค.

 

sample.txt ํŒŒ์ผ์ด๋ž‘ text_to_speech.py ํŒŒ์ผ์„ ๊ฐ™์€ ํด๋”์— ์žˆ์–ด์„œ

๊ทธ๋ƒฅ '/'๋งŒ ์ถ”๊ฐ€ํ•ด์„œ with open('/sample.txt',์ด๋ผ๊ณ  ํ–ˆ๋”๋‹ˆ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๊ณ  ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค.

 

์ฐพ์•„๋ณด๋‹ˆ ๊ทธ๋ƒฅ ํด๋” ์ด๋ฆ„์„ ์จ์ฃผ๋ฉด ํ•ด๊ฒฐ๋˜๋Š” ๊ฐ„๋‹จํ•œ ์—๋Ÿฌ์˜€์Œ. with open('TTS_STT/sample.txt',๋ผ๊ณ  ํ•ด์ฃผ๋ฉด ํ•ด๊ฒฐ!

 

์ „์—๋„ ์ด ์—๋Ÿฌ๋ฅผ ์ž์ฃผ ๋งŒ๋‚ฌ์—ˆ๋Š”๋ฐ ํ”„๋กœ์ ํŠธ๋ฅผ ์˜ค๋žœ๋งŒ์— ํ•ด์„œ ๊ทธ๋Ÿฐ์ง€ ๊ธฐ์–ต์ด ์ž˜ ์•ˆ ๋‚ฌ๋‹ค...

์ด์ œ ๋ฐฉ๋ฒ•์„ ์•Œ์•˜์œผ๋‹ˆ๊นŒ ์•ž์œผ๋กœ๋Š” ์•ˆ ๊นŒ๋จน์„ ๊ฒƒ์ด๋‹ค!



STT ์‹ค์Šต

 

๋ชจ๋“  ๊ณผ์ •์ด ๋‹ค ์Šค๋ฌด์Šคํ•˜๊ฒŒ ์ž˜ ์ง„ํ–‰๋ผ์„œ ๊ธฐ๋ปํ•˜๋˜ ์ค‘, ๋“œ๋””์–ด ๊ณ ๋‚œ์ด ์‹œ์ž‘๋๋‹ค.

STT๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ชจ๋“ˆ์ธ PyAudio๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค.

 

โ—๏ธ์—๋Ÿฌ 

 

์ฐพ์•„๋ณด๋‹ˆ ํŒŒ์ด์ฌ ์ž์ฒด๋ฅผ ์žฌ์„ค์น˜ํ•ด๋ณด๋ผ๋Š” ์ด์•ผ๊ธฐ๊ฐ€ ๋งŽ์•˜๋Š”๋ฐ ์ž˜๋ชป ๊ฑด๋“œ๋ ธ๋‹ค๊ฐ€๋Š” ๋˜๋Œ๋ฆด ์ˆ˜ ์—†์„ ๊ฒƒ ๊ฐ™์•„์„œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด๋˜ ์ค‘

๋‚˜๋„์ฝ”๋”ฉ๋‹˜ ์˜์ƒ ๋Œ“๊ธ€์— ๋‚˜๋ž‘ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋‚˜์…จ๋‹ค๋Š” ๋ถ„์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

 

๊ทธ๋ถ„๋„ ๊ฒฐ๊ตญ brew install python3๋กœ ํŒŒ์ด์ฌ ์ž์ฒด๋ฅผ ์žฌ์„ค์น˜ํ•˜์‹  ๋‹ค์Œ์— venv ๊ฐ€์ƒํ™˜๊ฒฝ๋„ ๋‹ค์‹œ ์„ธํŒ…ํ•˜์…”์„œ ํ•ด๊ฒฐํ•˜์…จ๋‹ค๊ณ  ํ–ˆ๋‹ค...

 

๋‚˜๋Š” python์ด anaconda์— ์„ค์น˜๋˜์–ด ์žˆ์–ด์„œ ์‚ญ์ œํ•˜์ง€๋Š” ๋ชปํ–ˆ๊ณ  ๊ทธ๋ƒฅ brew install python3๋กœ ํŒŒ์ด์ฌ์„ ์„ค์น˜ํ•œ ๋‹ค์Œ์— ๊ฐ€์ƒํ™˜๊ฒฝ์„ ๋‹ค์‹œ ์„ธํŒ…ํ•˜๊ณ  ๋‚˜๋‹ˆ PyAudio๊ฐ€ ์ œ๋Œ€๋กœ ์„ค์น˜๋๋‹ค!

 

์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐ๋ผ์„œ ๋‹คํ–‰์ด์—ˆ๋‹ค.

 

 

์—๋Ÿฌ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ๋“œ๋””์–ด ๋งˆ์ดํฌ๋กœ ์Œ์„ฑ์ธ์‹์„ ์ง์ ‘ ์‹œ๋„ํ–ˆ๋‹ค!

import speech_recognition as sr

# ๋งˆ์ดํฌ๋กœ๋ถ€ํ„ฐ ์Œ์„ฑ ๋“ฃ๊ธฐ
r = sr.Recognizer()

with sr.Microphone() as source:
    print('๋“ฃ๊ณ  ์žˆ์–ด์š”') # ์ด ๋ฌธ์žฅ์ด ๋œจ๊ณ  ๋‚˜๋ฉด ๊ทธ๋•Œ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด ๋จ 
    audio = r.listen(source) # ๋งˆ์ดํฌ๋กœ๋ถ€ํ„ฐ ์Œ์„ฑ ๋“ฃ๊ธฐ

# ์˜ˆ์™ธ์ฒ˜๋ฆฌ
try:
    # ๊ตฌ๊ธ€ API๋กœ ์ธ์‹ (ํ•˜๋ฃจ 50ํšŒ ๊นŒ์ง€๋กœ ์ œํ•œ)

    # ์˜์–ด ๋ฌธ์žฅ ํ…Œ์ŠคํŠธ
    text = r.recognize_google(audio, language='en-US')
    print(text)

except sr.UnknownValueError:
    print('์ธ์‹ ์‹คํŒจ') # ์Œ์„ฑ ์ธ์‹์— ์‹คํŒจํ•œ ๊ฒฝ์šฐ

except sr.RequestError as e:
    print('์š”์ฒญ ์‹คํŒจ : {0}'.format(e)) # ์š”์ฒญ ์‹คํŒจํ•œ ์ด์œ  ๊ฐ™์ด ์ถœ๋ ฅ -> API key ์˜ค๋ฅ˜, ๋„คํŠธ์›Œํฌ ๋‹จ์ ˆ ๋“ฑ
  • sr.Recognizer()์—์„œ๋Š” ์–ธ์–ด๋ฅผ ์ž…๋ ฅํ•  ๋•Œ 'language'๋กœ ์ž‘์„ฑ

 

๋จผ์ € ์˜์–ด๋กœ ํ•ด๋ดค๋‹ค.

๋นจ๊ฐ„์ƒ‰ ํ™”์‚ดํ‘œ ๋ถ€๋ถ„์ด ๋‚ด๊ฐ€ ๋งํ•œ ๋‚ด์šฉ์ด ํ…์ŠคํŠธ๋กœ ๋ณ€ํ™˜๋ผ์„œ ์ถœ๋ ฅ๋œ ๋ถ€๋ถ„!

 

ํ•œ๊ตญ์–ด๋„ ๊ต‰์žฅํžˆ ์ž˜ ์ธ์‹ํ•œ๋‹ค.

 

ํ•˜์ง€๋งŒ ์‚ฌํˆฌ๋ฆฌ๋Š” ์ด์ƒํ•˜๊ฒŒ ์ธ์‹ํ–ˆ๋‹ค. (๋‚ด ๋ฐœ์Œ์ด ์•ˆ ์ข‹์•˜๋˜ ๊ฒƒ์ผ ์ˆ˜๋„...)

 

๊ถ๊ธˆํ•ด์„œ ํ”„๋ž‘์Šค์–ด๋กœ๋„ ํ•ด๋ดค๋Š”๋ฐ ์ธ์‹์ด ์ž˜ ๋ผ์„œ ๋˜ ๋†€๋ž๋‹ค!
์—ฌ์„ฑํ˜•, ๋‚จ์„ฑํ˜•๋„ ๋ฐœ์Œ์œผ๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ํ…์ŠคํŠธ๋กœ ์ž˜ ๋‚˜์˜จ๋‹ค. ์—ญ์‹œ ๊ตฌ๊ธ€ ๐Ÿ‘
์ด๊ฑธ๋กœ ๋‚ด ๋ถˆ์–ด ๋ฐœ์Œ์„ ์ธ์ •๋ฐ›์€ ๊ฒƒ ๊ฐ™์•„์„œ ์ข€ ๋” ๊ธฐ๋ปค๋‹ค 



์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค ๊ตฌํ˜„

 

์œ„์—์„œ ์‹ค์Šตํ•œ TTS, STT๋ฅผ ๊ฐ€์ง€๊ณ  ์ด์ œ ๋Œ€๋ง์˜ ์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๊ฐ๊ฒฉ์Šค๋Ÿฌ์šด ์ฒซ ๋Œ€ํ™”..!

 

์ž‘๋™ ํ”Œ๋กœ์šฐ๋Š”

1) TTS๋ฅผ ์ด์šฉํ•ด์„œ ์ธ๊ณต์ง€๋Šฅ์ด '๋ฌด์—‡์„ ๋„์™€๋“œ๋ฆด๊นŒ์š”?'๋ฅผ ๋งํ•œ๋‹ค.
2) ์‚ฌ๋žŒ์ด ๋ง์„ ํ•˜๋ฉด STT๋กœ ๋งํ•œ ๋‚ด์šฉ์„ ํ…์ŠคํŠธ๋กœ ๋ณด์—ฌ์ค€๋‹ค.
3) ์‚ฌ๋žŒ์ด ๋งํ•œ ๋‚ด์šฉ ์ค‘์— answer()ํ•จ์ˆ˜์—์„œ ์ •์˜ํ•ด๋‘” ๋‹จ์–ด๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด ์ธ๊ณต์ง€๋Šฅ์ด ๊ทธ์— ๋งž๋Š” ๋Œ€๋‹ต์„ ๋‹ค์‹œ TTS๋กœ ๋งํ•ด์ฃผ๋Š” ํ˜•์‹.

 

์ด๋•Œ๋Š” ๋‚˜๋„์ฝ”๋”ฉ๋‹˜์˜ ์˜์ƒ์— ๋‚˜์˜จ ๋Œ€๋กœ ์ธ๊ณต์ง€๋Šฅ์ด ๋‹ตํ•  ๋‚ด์šฉ์„ ์ง์ ‘ str์œผ๋กœ ๋ฏธ๋ฆฌ ์ง€์ •ํ•ด๋’€๋‹ค.

๋งŒ๋“ค๋‹ค ๋ณด๋‹ˆ ์ธ๊ณต์ง€๋Šฅ์ด ๋Œ€๋‹ตํ•  ๋‚ด์šฉ์„ ์ด๋ ‡๊ฒŒ ์ง์ ‘ ์ง€์ •ํ•ด๋‘๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ API๋‚˜ ํฌ๋กค๋ง์„ ์‚ฌ์šฉํ•ด์„œ ์ง„์งœ ์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค์ฒ˜๋Ÿผ ์‹ค์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ๋‹ตํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ ๋‚ ์”จ์™€ ํ™˜์œจ์— ๋Œ€ํ•œ ๋‹ต์„ ๋„ค์ด๋ฒ„ ์Šคํฌ๋ž˜ํ•‘์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค!



๋„ค์ด๋ฒ„ ๋‚ ์”จ, ํ™˜์œจ ์ •๋ณด ์›น ์Šคํฌ๋ž˜ํ•‘

 

์ฒ˜์Œ์—” ์Šคํฌ๋ž˜ํ•‘ํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ•จ์ˆ˜ ํ˜•ํƒœ๋กœ ๋ฐ›์•„์™€์„œ answer()ํ•จ์ˆ˜ ๋‚ด answer_text์— ๋„ฃ์—ˆ๋Š”๋ฐ

์ด๋ ‡๊ฒŒ ํ•˜๋‹ˆ answer_text์— TTS๊ฐ€ ์ ์šฉ๋˜์ง€ ๋ชปํ–ˆ๋‹ค.

 

์ธ๊ณต์ง€๋Šฅ์ด ๋‹ตํ•˜๋Š” ๊ฒŒ ํ…์ŠคํŠธ๋กœ๋Š” ์ถœ๋ ฅ๋˜์ง€๋งŒ ์†Œ๋ฆฌ ๋‚ด์„œ ์ฝ๋Š” ๊ฒƒ์— ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค.

 

๊ทธ๋ž˜์„œ class์˜ ์†์„ฑ์œผ๋กœ ๋ฐ›์•„์˜ค๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.

 

# ๋„ค์ด๋ฒ„ ํ™˜์œจ ์Šคํฌ๋ž˜ํ•‘
import requests
from bs4 import BeautifulSoup

# ์›๋‹ฌ๋Ÿฌ ํ™˜์œจ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
class Exchange:
    def __init__(self, url=None, res=None, soup=None):
        self.url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%ED%99%98%EC%9C%A8"
        self.res = requests.get(self.url)
        self.soup = BeautifulSoup(self.res.text, "lxml")
        # ํ˜„์žฌ ์›๋‹ฌ๋Ÿฌ ํ™˜์œจ
        self.curr_exchange = self.soup.find("span", attrs={"class":"recite _recite result"}).get_text()
        # ๋“ฑ๋ฝ๋ฅ 
        self.ex_rate = self.soup.find("td", attrs={"class":"flu_pct"}).get_text()

 

# ๋„ค์ด๋ฒ„ ์„œ์šธ ๋‚ ์”จ ์Šคํฌ๋ž˜ํ•‘
import requests
from bs4 import BeautifulSoup

# ์˜ค๋Š˜์˜ ์„œ์šธ ๋‚ ์”จ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
class Weather:
    def __init__(self, url=None, res=None, soup=None):
        self.url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%84%9C%EC%9A%B8+%EB%82%A0%EC%94%A8"
        self.res = requests.get(self.url)
        self.soup = BeautifulSoup(self.res.text, "lxml")
        # ํ˜„์žฌ ์˜จ๋„
        self.curr_temp = self.soup.find("div", attrs={"class":"temperature_text"}).get_text().replace("ํ˜„์žฌ ์˜จ๋„", "ํ˜„์žฌ ์„œ์šธ์˜ ์˜จ๋„๋Š” ").strip() # ๊ณต๋ฐฑ ์ œ๊ฑฐ
        # ๋‚ ์”จ ์ƒํƒœ
        self.weather_con = self.soup.find("span", attrs={"class":"weather before_slash"}).get_text() 
        # ์–ด์ œ๋ณด๋‹ค
        self.yester_temp = self.soup.find("p", attrs={"class":"summary"}).get_text().split('์•„์š”')[0] # ์ถœ๋ ฅ ์‹œ ๋’ค์— '์Šต๋‹ˆ๋‹ค.' ๋ถ™์ด๊ธฐ
        # ์ตœ์ €๊ธฐ์˜จ
        self.min_temp = self.soup.find("span", attrs={"class":"lowest"}).get_text().replace("์ตœ์ €๊ธฐ์˜จ", "์ตœ์ €๊ธฐ์˜จ์€ ")
        # ์ตœ๊ณ ๊ธฐ์˜จ
        self.max_temp = self.soup.find("span", attrs={"class":"highest"}).get_text().replace("์ตœ๊ณ ๊ธฐ์˜จ", "์ตœ๊ณ ๊ธฐ์˜จ์€ ")

 

โ—๏ธ์—๋Ÿฌ 

 

์ด ๊ธ€์„ ์ž‘์„ฑํ•˜๋ฉด์„œ ๋‹ค์‹œ ์‹คํ–‰์‹œ์ผœ๋ณด๋‹ˆ ์œ„ ์ฝ”๋“œ์˜ yester_temp๊ฐ€ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค.

  • ์ˆ˜์ •ํ•˜๊ธฐ ์ „ ์ฝ”๋“œ
    • self.yester_temp = self.soup.find("span", attrs={"class":"temperature down"}).get_text()

๋ถ„๋ช… ๊ทธ์ €๊ป˜ ์‹คํ–‰ํ–ˆ์„ ๋•Œ๋Š” ์ž˜ ์ž‘๋™ํ–ˆ๋Š”๋ฐ ๊ฐ‘์ž๊ธฐ ์™œ ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š”์ง€ ์‚ดํŽด๋ณด๋‹ˆ "temperature down" ๋•Œ๋ฌธ์ด์—ˆ๋‹ค.

 

 

๋‚ด๊ฐ€ ์ฒ˜์Œ์— ์ฝ”๋“œ๋ฅผ ์งค ๋•Œ๋Š” ๋ฌผ๊ฒฐ ํ‘œ์‹œ๋œ ์ € ๋ถ€๋ถ„์ด "temperature down"์ด๋ผ๊ณ  ๋˜์–ด ์žˆ์—ˆ๋Š”๋ฐ ์˜ค๋Š˜์€ ์–ด์ œ๋ณด๋‹ค ๊ธฐ์˜จ์ด ์˜ฌ๋ผ์„œ "temperature up"์œผ๋กœ ๋ฐ”๋€ ๊ฒƒ.

 

์ˆ˜์ • ์ „ ์ฝ”๋“œ๋Š” '์–ด์ œ๋ณด๋‹ค' ๋’ค์˜ ์˜จ๋„๋งŒ ๊ฐ€์ ธ์™”์—ˆ๋Š”๋ฐ ์˜จ๋„๊ฐ€ ๋†’์•„์ง€๊ณ  ๋‚ฎ์•„์ง€๋Š” ๊ฒƒ์— ๋”ฐ๋ผ ๊ณ„์† ๋ฐ”๋€Œ๋‹ˆ๊นŒ
์•„์˜ˆ ๊ทธ ์œ„์˜ <p class="summary"> ๋ถ€๋ถ„์„ ๋‹ค ๋ฐ›์•„์™€์„œ '์–ด์ œ๋ณด๋‹ค 00° ๋†’/๋‚ฎ'๊นŒ์ง€๋งŒ ๋ฐ›์•„์˜ค๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.

  • ์ˆ˜์ •ํ•œ ์ฝ”๋“œ
    • self.yester_temp = self.soup.find("p", attrs={"class":"summary"}).get_text().split('์•„์š”')[0]

 

 

 

# ์Šคํฌ๋ž˜ํ•‘ ํด๋ž˜์Šค ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
import scrape.naver_exchange_rate as nex
import scrape.naver_weather as nwh

# (๋‚ ์”จ)
# ์ธ์Šคํ„ด์Šค ์„ ์–ธ
wh = nwh.Weather()
# ์†์„ฑ ๋ฐ›๊ธฐ
wh.curr_temp # ํ˜„์žฌ ์„œ์šธ์˜ ์˜จ๋„
wh.weather_con # ๋‚ ์”จ ์ƒํƒœ (ex. ๋ง‘์Œ, ํ๋ฆผ, ...)


# (ํ™˜์œจ)
# ์ธ์Šคํ„ด์Šค ์„ ์–ธ
ex = nex.Exchange() 
# ์†์„ฑ ๋ฐ›๊ธฐ
ex.curr_exchange # ํ˜„์žฌ ์›๋‹ฌ๋Ÿฌ ํ™˜์œจ
ex.ex_rate # ๋“ฑ๋ฝ๋ฅ 



๊ฒฐ๊ณผ ์‹œ์—ฐ

 

  • 9์›” 20์ผ

 

  • 9์›” 22์ผ

 

์›น ์Šคํฌ๋ž˜ํ•‘์œผ๋กœ ์‹ค์‹œ๊ฐ„ ๋‚ ์”จ, ํ™˜์œจ ์ •๋ณด๋ฅผ ๋ฐ›์•„์„œ ๋งค๋ฒˆ ๋‹ค๋ฅด๊ฒŒ ์ž˜ ๋Œ€๋‹ตํ•œ๋‹ค.

9์›” 22์ผ ๋Œ€ํ™”์—์„œ ๋งˆ์ง€๋ง‰์— "์ด์ œ ์ข…๋ฃŒํ•˜๋‹ค"๋Š” ์‚ฌ์‹ค "์ด์ œ ์ข…๋ฃŒํ•˜์ž"๋ผ๊ณ  ๋งํ•œ ๊ฑฐ์˜€๋Š”๋ฐ '์ž'๋ฅผ '๋‹ค'๋ผ๊ณ  ์ž˜๋ชป ์ธ์‹๋œ ๋ชจ์Šต๋„ ๋ณด์ธ๋‹ค.



์—๋Ÿฌ ๋ชจ์Œ์ง‘

 

1) [bs4 ์—๋Ÿฌ] ImportError: cannot import name 'BeautifulSoup'

 

2) [bs4 lxml ์—๋Ÿฌ] bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml.

 

3) [git ์—๋Ÿฌ] ! [rejected] main -> main (fetch first)

  • ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ํ˜„์žฌ ์ž‘์—… ์ค‘์ธ ๋กœ์ปฌ ์ €์žฅ์†Œ๊ฐ€ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์•„์„œ ๋ฐœ์ƒ
  • ๋™๊ธฐํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋‹ค์‹œ push ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์†Œ์‹ค๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฒฝ๊ณ 
  • ๋™๊ธฐํ™”๋ฅผ ์œ„ํ•ด pull ํ•œ ํ›„ push ํ•˜๋ฉด ํ•ด๊ฒฐ
  • -> git pull --rebase origin main



๋Š๋‚€ ์  ๋ฐ ํ–ฅํ›„ ๊ฐœ์„  ๋ฐฉ์•ˆ

 

  • ๋Š๋‚€ ์ 

๊ฐ„๋‹จํ•˜๊ฒŒ ๋”ฐ๋ผ ํ•ด๋ณด๋Š” ๋ฏธ๋‹ˆ ํ† ์ด ํ”„๋กœ์ ํŠธ์˜€์ง€๋งŒ ์ฝ”๋“œ๋ฅผ ์งœ์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๋Š” ๊ฒŒ ์ •๋ง ์˜ค๋žœ๋งŒ์ด๋ผ ๋งŒ๋“ค๋ฉด์„œ ๋„ˆ๋ฌด ๊ธฐ๋ปค๋‹ค.

๊ตฌ๊ธ€ API๋ฅผ ์ด์šฉํ•ด์„œ ์ธ๊ณต์ง€๋Šฅ ์Šคํ”ผ์ปค๋ฅผ ์ •๋ง ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์— ๋†€๋ž๊ณ , ์ƒ๊ฐ๋ณด๋‹ค ์Œ์„ฑ์„ ๊ต‰์žฅํžˆ ์ž˜ ์ธ์‹ํ•ด์„œ ํ•œ๋ฒˆ ๋” ๋†€๋ž๋‹ค. (๊ฐ“ ๊ตฌ๊ธ€!)

 

  • ํ–ฅํ›„ ๊ฐœ์„  ๋ฐฉ์•ˆ

๋‹ค์Œ์—๋Š” ๊ตฌ๊ธ€ API๊ฐ€ ์•„๋‹ˆ๋ผ ๋„ค์ด๋ฒ„ ๋ฒˆ์—ญ API๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋‹ค์‹œ ํ•œ๋ฒˆ ๋งŒ๋“ค์–ด ๋ณผ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  API๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  TTS์™€ STT๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์—๋„ ๋„์ „ํ•  ๊ฒƒ์ด๋‹ค.

Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค!