Notice
Recent Posts
Recent Comments
250x250
Creative Code
Lunar-(13)날씨(실시간 재난문자, 전세계 지역 현재 날씨 검색, 기상관련 사이트 링크) 본문
728x90
화면 왼쪽에는 실시간 재난 문자 정보를 받아오는 기능,
화면 중앙에는 전세계의 지역명을 검색하면 해당 지역의 현재 날씨 정보를 받아와 아이콘으로 표시하는 기능,
화면 오른쪽에는 각종 기상관련 사이트로 이동할 수 있는 링크를 삽입해두었다.
※pages/weather.py 코드
# lunar.state.home 모듈에서 필요한 State 및 HomeState를 가져옵니다.
import reflex as rx
from lunar.state.base import State
from lunar.state.home import HomeState
from PIL import Image
# 컴포넌트를 가져옵니다.
from ..components import container
color = "rgb(107,99,246)"
# 탭 버튼을 생성하는 함수
def tab_button(imagepath, href):
"""A tab switcher button."""
return rx.link(
rx.image(
src=imagepath,
height='40px',
width='40px',
),
display="inline-flex",
align_items="center",
py=3,
px=2,
href=href, # 버튼 클릭 시 이동할 경로
)
def message(message):
return rx.box(
rx.button(
rx.vstack(
rx.box(
rx.text(
message['date'],
style={'white-space': 'normal'},
font_Size = '15px',
font_weight= 'bolder',
),
bg = '#dec445',
),
rx.text(),
rx.text(
message['area'],
style={'white-space': 'normal'},
font_Size = '13px',
font_weight='bold',
),
rx.divider(variant="dashed", border_color="black"),
rx.text(
message['text'],
style={'white-space': 'normal'},
font_size = '15px',
),
width = '100%',
),
height='auto',
width='90%',
),
rx.container(height='5px'),
align='start',
padding='5px', # 테두리와 내용 사이의 여백 지정
)
# 왼쪽에 표시되는 탭 스위처
def tabs():
"""The tab switcher displayed on the left."""
return rx.box(
rx.vstack(
rx.container(
rx.hstack(
rx.image(
src='/moon.png',
height='60px',
width='60px',
),
rx.text(
"Lunar",
style={
"fontSize": "40px",
"fontWeight": "bolder",
"fontFamily": "Calibri, Calibri",
"background": "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
"-webkit-background-clip": "text",
"color": "transparent",
},
center_content=True,
), # 앱 이름
),
),
rx.vstack(
rx.hstack(
rx.container(width='5px'),
rx.vstack(
rx.container(height='10px'),
rx.vstack(
rx.button('Disaster',Font_size = '20px',on_click = HomeState.climate_message,bg = '#eb7373'),
),
rx.container(height='5px'),
rx.foreach(
HomeState.weather_message_result,
message,
),
rx.container(height='4px'),
align_items='start',
width ='100%',
),
),
align_items = 'start',
margin_left = '20px',
border = '3px solid #000000',
border_radius = '30px',
box_Shadow = '10px 10px 5px #d61c4e',
width = '90%',
),
align_items="start",
gap=4,
),
py=4,
overflow='auto',
)
# 오른쪽에 표시되는 사이드바
def sidebar(HomeState):
"""The sidebar displayed on the right."""
return rx.vstack(
rx.container(height='10px'),
rx.heading(
'Weather sites',
font_Size = '30px',
font_weight='bolder',
bg = 'blue.400',
),
rx.hstack(
rx.container(width='1px'),
rx.vstack(
rx.link(
rx.button("대한민국 기상청"),
href="https://www.weather.go.kr/w/index.do",
color="rgb(107,99,246)",
button=True,
),
rx.link(
rx.button("일본 기상청"),
href="https://www.data.jma.go.jp/multi/index.html?lang=kr",
color="rgb(107,99,246)",
button=True,
),
rx.link(
rx.button("미국 기상청"),
href="https://worldweather.wmo.int/kr/country.html?countryCode=93",
color="rgb(107,99,246)",
button=True,
),
rx.link(
rx.button("Windy"),
href="https://www.windy.com/?36.342,127.389,5",
color="rgb(107,99,246)",
button=True,
),
rx.link(
rx.button("AccuWeather"),
href="https://www.accuweather.com/",
color="rgb(107,99,246)",
button=True,
),
align_items='start',
width ='100%',
),
border = '2px solid #000000',
border_radius = '30px',
box_Shadow = '10px 10px 5px #307849',
width='80%',
),
align_items="start",
gap=4,
height='100%',
width = '100%',
py=4,
overflow='auto',
)
# 피드의 헤더
def feed_header(HomeState):
"""The header of the feed."""
return rx.hstack(
rx.image(src='/find1.png',height='35px',width='35px'),
rx.input(on_change=HomeState.set_weather_search, placeholder="Search place..!"),
rx.button('search', on_click = HomeState.climate_websearch),
justify="space-between",
p=4,
border_bottom="3px solid #000000",
)
# 피드 영역
def feed(HomeState):
"""The feed."""
return rx.box(
feed_header(HomeState),
rx.container(height='10px'),
rx.vstack(
rx.cond(
HomeState.weather_search_show,
rx.vstack(
rx.hstack(
rx.heading(
HomeState.weather_search,
as_='mark',
font_Size = '50px',
),
margin_left = '5%',
),
rx.hstack(
rx.vstack(
rx.text(
f"현재 기온 : {HomeState.status_temperature}'C",
font_Size = '25px',
font_weight='bold',
),
rx.text(
f'현재 날씨 : {HomeState.status_climate}',
font_Size = '25px',
font_weight='bolder',
),
rx.text(
f"체감 온도 : {HomeState.status_feel_temperature}'C",
font_Size = '25px',
font_weight='bolder',
),
rx.text(
f"최저 온도 : {HomeState.today_min_temperature}'C",
font_Size = '25px',
font_weight='bolder',
color = 'blue',
),
rx.text(
f"최고 온도 : {HomeState.today_max_temperature}'C",
font_Size = '25px',
font_weight='bolder',
color = 'red',
),
rx.text(
f'현재 습도 : {HomeState.status_humidity}%',
font_Size = '25px',
font_weight='bolder',
),
rx.text(
f'현재 기압 : {HomeState.status_atmospheric_pressure}hpa',
font_Size = '25px',
font_weight='bolder',
),
rx.text(
f'풍속 : {HomeState.status_wind_speed}m/s',
font_Size = '25px',
font_weight='bolder',
),
align_items='start',
margin_left = '5%',
),
rx.container(width='5%'),
rx.vstack(
rx.image(
src = HomeState.image,
height='400px',
width = 'auto',
)
)
),
width = '90%',
margin_left = '5%',
align_items='start',
border = '2px solid #000000',
border_radius = '30px',
box_Shadow = '10px 10px 10px #575050',
),
rx.vstack(
rx.heading(
'Enter the area where you want to search for weather.',
font_Size = '40px',
font_weight='border',
),
align_items='start',
width = '100%',
)
)
),
rx.container(height='20px'),
overflow='auto',
)
# 홈 페이지
def weather():
State.check_login
return rx.vstack(
rx.grid(
tabs(),
feed(HomeState),
sidebar(HomeState),
grid_template_columns="2fr 5fr 2fr",
width='97%',
h="90vh",
gap=4,
),
rx.grid(
rx.vstack(
rx.container(height='5px'),
rx.button(
rx.icon(tag="moon"),
on_click=rx.toggle_color_mode,
width = '80%',
_hover={"bg": "orange.400"},
),
width = '100%',
),
rx.vstack(
rx.hstack(
tab_button('/Home.png','/'),
tab_button('/profile.png','/profile'),
tab_button('/map.png','/map'),
tab_button('/chat.png','/chat'),
tab_button('/Aichat.png','/aichat'),
tab_button('/diary.png','/diary'),
tab_button('/video.png','/video'),
tab_button('/game.png','/game'),
tab_button('/music.png','/music'),
tab_button('/weather.png','/weather'),
tab_button('/setting.png','/setting'),
margin_right='5px',
border="1px solid #000000",
border_radius="full",
box_Shadow = '10px 10px 5px #3083f0',
),
width = '100%',
),
rx.vstack(
rx.container(height='5px'),
rx.button(
"Sign out",
on_click=State.logout,
bg="#212963",
color="white",
_hover={"bg": "blue.600"},
width = '80%',
),
width = '100%',
),
width='97%',
grid_template_columns="2fr 5fr 2fr",
),
)
※ state/home.py의 기상관련 함수를 담당하는 코드
# 재난문자 웹 크롤링
def climate_message(self):
url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EC%9E%AC%EB%82%9C%EB%AC%B8%EC%9E%90"
response = requests.get(url)
html = response.text
soup = bs(html, 'html.parser')
areas = soup.select(".area")
disaster_texts = soup.select(".disaster_text")
dates = soup.select(".date")
self.weather_message_result = []
# 결과 출력
for area, disaster_text, date in zip(areas, disaster_texts, dates):
data = {'area' : area.get_text(strip=True), 'date' : date.get_text(strip=True), 'text':disaster_text.get_text(strip = True) }
self.weather_message_result.append(data)
# 날씨 웹 크롤링
def climate_websearch(self):
key=''
with open('weatherapikey.json','r')as f:
key = json.load(f)
weather_api_key = key['key']
url = f"http://api.openweathermap.org/data/2.5/weather?q={self.weather_search}&appid={weather_api_key}&lang=kr&units=metric"
result = requests.get(url)
data = json.loads(result.text)
self.status_climate = data['weather'][0]['description']
self.status_temperature = data['main']['temp']
self.status_feel_temperature = data['main']['feels_like']
self.today_min_temperature = data['main']['temp_min']
self.today_max_temperature = data['main']['temp_max']
self.status_humidity = data['main']['humidity']
self.status_atmospheric_pressure = data['main']['pressure']
self.status_wind_direction = data['wind']['deg']
self.status_wind_speed = data['wind']['speed']
self.status_climate_icon_url= f"https://openweathermap.org/img/wn/{data['weather'][0]['icon']}@2x.png"
self.image = Image.open((requests.get(self.status_climate_icon_url, stream=True).raw))
self.weather_search_show=True
728x90
'Projects' 카테고리의 다른 글
Lunar-(15)전체코드 중간정리2(함수 부분) (0) | 2024.01.08 |
---|---|
Lunar-(14)전체코드 중간 정리1(프론트엔드 부분) (3) | 2024.01.08 |
Lunar-(12)멜론 차트 top100 가져오기, 가수 크롤링 검색결과 (1) | 2024.01.03 |
Lunar-(11)현재 수정중인 작업, 기능추가예정작업 (0) | 2024.01.01 |
Lunar-(10)비디오 기능추가(구글 웹 크롤링-Selenium) (0) | 2023.12.24 |