openpibo.collect의 소스 코드

"""
인터넷에서 **위키 검색 정보, 날씨 정보, 뉴스 정보** 를 가져올 수 있습니다.

Class:
:obj:`~openpibo.collect.Wikipedia`
:obj:`~openpibo.collect.Weather`
:obj:`~openpibo.collect.News`
:obj:`~openpibo.collect.ExchangeRate`
:obj:`~openpibo.collect.AirQuality`
:obj:`~openpibo.collect.Trivia`
:obj:`~openpibo.collect.Country`
:obj:`~openpibo.collect.OnThisDay`
"""

from urllib.parse import quote
from bs4 import BeautifulSoup
import requests


[문서] class Wikipedia: """ Functions: :meth:`~openpibo.collect.Wikipedia.search` :meth:`~openpibo.collect.Wikipedia.search_s` 위키백과에서 단어를 검색합니다. example:: from openpibo.collect import Wikipedia wiki = Wikipedia() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """
[문서] def search(self, search_text: str): """ 위키백과에서 ``search_text`` 를 검색합니다. example:: result = wiki.search('강아지') :param str search_text: 위키백과에서의 검색어 :returns: 내용을 dictionary 형태로 반환합니다. 대부분의 경우 '0'번 항목에 개요를 표시하고, 검색된 내용이 없을 경우 None을 반환합니다. example:: { '0': {'title': '개요', 'content': ['...', ...]}, '1': {'title': '역사', 'content': [...]}, '1.1': {'title': '초기 역사', 'content': [...]}, } or None """ url = 'https://ko.wikipedia.org/w/api.php' params = { 'action': 'query', 'prop': 'extracts', 'titles': search_text, 'format': 'json', 'explaintext': True, 'exsectionformat': 'wiki', 'redirects': True, } resp = requests.get(url, params=params, headers={'User-Agent': 'Mozilla/5.0'}) data = resp.json() pages = data.get('query', {}).get('pages', {}) if not pages: return None page = next(iter(pages.values())) if 'missing' in page: return None extract = page.get('extract', '') if not extract: return None _chapters = {'0': {'title': '개요', 'content': []}} current_idx = '0' h2_count = h3_count = h4_count = 0 for line in extract.split('\n'): if line.startswith('==== ') and line.endswith(' ===='): h4_count += 1 current_idx = f'{h2_count}.{h3_count}.{h4_count}' _chapters[current_idx] = {'title': line.strip('= ').strip(), 'content': []} elif line.startswith('=== ') and line.endswith(' ==='): h3_count += 1 h4_count = 0 current_idx = f'{h2_count}.{h3_count}' _chapters[current_idx] = {'title': line.strip('= ').strip(), 'content': []} elif line.startswith('== ') and line.endswith(' =='): h2_count += 1 h3_count = 0 h4_count = 0 current_idx = str(h2_count) _chapters[current_idx] = {'title': line.strip('= ').strip(), 'content': []} elif line.strip(): _chapters[current_idx]['content'].append(line.strip()) return _chapters
[문서] def search_s(self, search_text: str): """ 위키백과에서 ``search_text`` 를 검색합니다. (block 전용) example:: result = wiki.search_s('강아지') :param str search_text: 위키백과에서의 검색어 :returns: search 함수의 반환 값의 content만 추출한 리스트를 반환합니다. 대부분의 경우 '0'번 항목에 개요를 표시하고, 검색된 내용이 없을 경우 None을 반환합니다. example:: [ "한국어 '강아지'는 '개'에 어린 짐승을 뜻하는 '아지'가 붙은 말이다...", ... ] or None """ res = self.search(search_text) if res is None: return None return [item for _, v in res.items() for item in v['content'] if item]
[문서] class Weather: """ Functions: :meth:`~openpibo.collect.Weather.search` :meth:`~openpibo.collect.Weather.search_s` 종합 예보와 오늘/내일/모레의 날씨 정보를 검색합니다. example:: from openpibo.collect import Weather weather = Weather() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """ region_list = { '전국': 108, '서울': 109, '인천': 109, '경기': 109, '부산': 159, '울산': 159, '경남': 159, '대구': 143, '경북': 143, '광주': 156, '전남': 156, '전북': 146, '대전': 133, '세종': 133, '충남': 133, '충북': 131, '강원': 105, '제주': 184, } """ 날씨 정보를 검색할 수 있는 지역입니다. """
[문서] def search(self, search_region: str = '전국'): """ 해당 지역(```search_region```)의 날씨 정보(종합예보, 오늘/내일/모레 날씨)를 가져옵니다. example:: result = weather.search('서울') :param str search_region: 검색 가능한 지역 (default: 전국) 검색할 수 있는 지역은 다음과 같습니다:: '전국', '서울', '인천', '경기', '부산', '울산', '경남', '대구', '경북', '광주', '전남', '전북', '대전', '세종', '충남', '충북', '강원', '제주' :returns: 종합예보와 오늘/내일/모레의 날씨 및 최저/최고기온을 반환합니다. example:: { 'forecast': '내일 경기남부 가끔 비, 내일까지 바람 약간 강, 낮과 밤의 기온차 큼', 'today': {'weather': '...', 'minimum_temp': '...', 'highst_temp': '...'}, 'tomorrow': {'weather': '...', 'minimum_temp': '...', 'highst_temp': '...'}, 'after_tomorrow':{'weather': '...', 'minimum_temp': '...', 'highst_temp': '...'}, } or None """ region = Weather.region_list.get(search_region) if region is None: raise Exception(f'"{search_region}" not support') _forecast = '' _today = {} _tomorrow = {} _after_tomorrow = {} url = f'https://www.weather.go.kr/w/weather/forecast/short-term.do?stnId={region}' resp = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}) soup = BeautifulSoup(resp.content, 'html.parser') view_content = soup.find('div', {'class': 'cmp-view-content'}) if not view_content: return None forecasts = view_content.text.split('□')[1].split('○') for forecast in map(str.strip, forecasts): if ')' not in forecast: continue split_point = forecast.index(')') date = forecast[:split_point + 1] desc = forecast[split_point + 2:] if '종합' in date: _forecast = desc if '오늘' in date: _today['weather'] = desc if '내일' in date or '~' in date: _tomorrow['weather'] = desc if '모레' in date: _after_tomorrow['weather'] = desc temp_table = soup.find('tbody') if not temp_table: return None all_temps = list(map(lambda x: x.text.strip(), temp_table.select('td')[:10])) if len(all_temps) < 10: return None _today['minimum_temp'], _tomorrow['minimum_temp'], _after_tomorrow['minimum_temp'] = all_temps[2:5] _today['highst_temp'], _tomorrow['highst_temp'], _after_tomorrow['highst_temp'] = all_temps[7:10] return { 'forecast': _forecast, 'today': _today, 'tomorrow': _tomorrow, 'after_tomorrow': _after_tomorrow, }
[문서] def search_s(self, search_region: str = '전국', search_type: str = 'forecast', search_item: str = 'weather'): """ 해당 지역(```search_region```)의 날씨 정보를 간단하게 가져옵니다. (block 전용) example:: result = weather.search_s('서울') :param str search_region: 검색 가능한 지역 (default: 전국) :param str search_type: 'forecast' | 'today' | 'tomorrow' | 'after_tomorrow' (default: forecast) :param str search_item: 'weather' | 'minimum_temp' | 'highst_temp' (default: weather) search_type이 forecast일 경우 search_item은 무시합니다. :returns: 파라미터에 따라 종합예보 혹은 날씨/최저기온/최고기온 문자열을 반환합니다. None일 경우 None 반환. """ res = self.search(search_region) if res is None: return None if search_type == 'forecast': return res['forecast'].strip().replace('\n', ' ') else: if search_item == 'minimum_temp': return res[search_type][search_item].split(' ~ ')[0] elif search_item == 'highst_temp': return res[search_type][search_item].split(' ~ ')[1] else: return res[search_type][search_item].strip().replace('\n', ' ')
[문서] class News: """ Functions: :meth:`~openpibo.collect.News.search` :meth:`~openpibo.collect.News.search_s` JTBC 뉴스 RSS 서비스를 사용해 뉴스 자료를 가져옵니다. example:: from openpibo.collect import News news = News() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """ topic_list = { '속보': 'newsflash', '정치': 'politics', '경제': 'economy', '사회': 'society', '국제': 'international', '문화': 'culture', '연예': 'entertainment', '스포츠': 'sports', '풀영상': 'fullvideo', '뉴스랭킹': 'newsrank', '뉴스룸': 'newsroom', '아침&': 'morningand', '썰전 라이브': 'ssulzunlive', '정치부회의': 'politicaldesk', } """ 뉴스 정보를 검색할 수 있는 주제입니다. """
[문서] def search(self, search_topic: str = '뉴스랭킹'): """ 해당 주제(```search_topic```)에 맞는 뉴스를 가져옵니다. example:: result = news.search('속보') :param str search_topic: 검색 가능한 뉴스 주제 (default: 뉴스랭킹) 검색할 수 있는 주제는 다음과 같습니다:: '속보', '정치', '경제', '사회', '국제', '문화', '연예', '스포츠', '풀영상', '뉴스랭킹', '뉴스룸', '아침&', '썰전 라이브', '정치부회의' :returns: title, link, description, pubDate 요소가 있는 dictionary 배열입니다. example:: [ { 'title': '소방차 막은 불법주차, 이번엔 가차없이 밀어버렸다', 'link': 'https://news.jtbc.joins.com/article/...', 'description': '2019년 4월 소방당국의 불법주정차 강경대응 훈련 모습...', 'pubDate': '2021.09.03' }, ... ] or None """ topic = News.topic_list.get(search_topic) if topic is None: raise Exception(f'"{search_topic}" not support') _articles = [] url = f'https://fs.jtbc.joins.com//RSS/{topic}.xml' res = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}) if res.status_code != 200: return None soup = BeautifulSoup(res.content, 'xml') items = soup.findAll('item') if not items: return None for item in items: title_tag = item.find('title') link_tag = item.find('link') description_tag = item.find('description') pubdate_tag = item.find('pubDate') _articles.append({ 'title': title_tag.text if title_tag else '', 'link': link_tag.text if link_tag else '', 'description': description_tag.text if description_tag else '', 'pubDate': pubdate_tag.text if pubdate_tag else '', }) return _articles
[문서] def search_s(self, search_topic: str = '뉴스랭킹', search_type: str = 'title'): """ 해당 주제(```search_topic```)에 맞는 뉴스를 간단하게 가져옵니다. (block 전용) example:: result = news.search_s('속보') :param str search_topic: 검색 가능한 뉴스 주제 (default: 뉴스랭킹) :param str search_type: 'title' | 'link' | 'description' (default: title) :returns: 선택한 요소의 리스트, None일 경우 None 반환. example:: ['소방차 막은 불법주차, 이번엔 가차없이 밀어버렸다', ...] or None """ res = self.search(search_topic) if res is None: return None return [v[search_type] for v in res if '다시보기' not in v.get(search_type, '')]
[문서] class ExchangeRate: """ Functions: :meth:`~openpibo.collect.ExchangeRate.search` :meth:`~openpibo.collect.ExchangeRate.search_s` 실시간 환율 정보를 가져옵니다. (API 키 불필요) example:: from openpibo.collect import ExchangeRate er = ExchangeRate() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """ currency_name = { 'KRW': '한국 원', 'USD': '미국 달러', 'EUR': '유로', 'JPY': '일본 엔', 'CNY': '중국 위안', 'GBP': '영국 파운드', 'AUD': '호주 달러', 'CAD': '캐나다 달러', 'CHF': '스위스 프랑', 'HKD': '홍콩 달러', 'SGD': '싱가포르 달러', 'THB': '태국 바트', 'VND': '베트남 동', } """ 주요 통화 코드와 이름입니다. """
[문서] def search(self, base: str = 'USD'): """ 기준 통화(``base``)에 대한 실시간 환율 정보를 가져옵니다. example:: result = er.search('USD') :param str base: 기준 통화 코드 (default: USD) 주요 통화 코드:: 'USD'(미국 달러), 'KRW'(한국 원), 'EUR'(유로), 'JPY'(일본 엔), 'CNY'(중국 위안) 등 ISO 4217 코드 :returns: 기준 통화 대비 각 통화의 환율 dictionary를 반환합니다. 실패 시 None을 반환합니다. example:: { 'base': 'USD', 'date': '2024-03-13', 'rates': {'KRW': 1340.5, 'JPY': 149.2, 'EUR': 0.92, ...} } or None """ url = f'https://open.er-api.com/v6/latest/{base.upper()}' resp = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}) if resp.status_code != 200: return None data = resp.json() if data.get('result') != 'success': return None return { 'base': data.get('base_code', base), 'date': data.get('time_last_update_utc', ''), 'rates': data.get('rates', {}), }
[문서] def search_s(self, base: str = 'USD', target: str = 'KRW'): """ 기준 통화(``base``) 대비 대상 통화(``target``)의 환율을 반환합니다. (block 전용) example:: result = er.search_s('USD', 'KRW') :param str base: 기준 통화 코드 (default: USD) :param str target: 대상 통화 코드 (default: KRW) :returns: 환율 float 값, 실패 시 None example:: 1340.5 or None """ res = self.search(base) if res is None: return None return res['rates'].get(target.upper())
[문서] class AirQuality: """ Functions: :meth:`~openpibo.collect.AirQuality.search` :meth:`~openpibo.collect.AirQuality.search_s` 네이버 날씨 검색을 통해 실시간 미세먼지 정보를 가져옵니다. (API 키 불필요) example:: from openpibo.collect import AirQuality aq = AirQuality() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """ region_list = [ '서울', '부산', '대구', '인천', '광주', '대전', '울산', '경기', '강원', '충북', '충남', '전북', '전남', '경북', '경남', '제주', '세종', ] """ 미세먼지 정보를 검색할 수 있는 지역입니다. """ _headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Accept-Language': 'ko-KR,ko;q=0.9', }
[문서] def search(self, search_region: str = '서울'): """ 해당 지역(``search_region``)의 실시간 미세먼지 정보를 가져옵니다. example:: result = aq.search('서울') :param str search_region: 검색할 지역명 (default: 서울) 검색할 수 있는 지역:: '서울', '부산', '대구', '인천', '광주', '대전', '울산', '경기', '강원', '충북', '충남', '전북', '전남', '경북', '경남', '제주', '세종' :returns: 미세먼지 정보 dictionary를 반환합니다. 실패 시 None. example:: { 'pm10': '좋음', # 미세먼지 등급 'pm25': '보통', # 초미세먼지 등급 } or None """ if search_region not in self.region_list: raise Exception(f'"{search_region}" not support') url = f'https://search.naver.com/search.naver?query={quote(search_region + " 날씨")}' resp = requests.get(url, headers=self._headers) if resp.status_code != 200: return None soup = BeautifulSoup(resp.text, 'html.parser') result = {'pm10': None, 'pm25': None} # 구조: <a class="box"><strong class="title">미세먼지</strong><span class="txt">좋음</span></a> label_map = {'미세먼지': 'pm10', '초미세먼지': 'pm25'} for box in soup.select('a.box'): title_tag = box.find('strong', class_='title') txt_tag = box.find('span', class_='txt') if not title_tag or not txt_tag: continue title = title_tag.get_text(strip=True) if title in label_map and result[label_map[title]] is None: result[label_map[title]] = txt_tag.get_text(strip=True) if all(v is None for v in result.values()): return None return result
[문서] def search_s(self, search_region: str = '서울', search_item: str = 'pm10'): """ 해당 지역의 미세먼지 정보를 단일 값으로 반환합니다. (block 전용) example:: result = aq.search_s('서울', 'pm10') :param str search_region: 검색할 지역명 (default: 서울) :param str search_item: 조회 항목 (default: pm10) 조회 가능한 항목:: 'pm10' 미세먼지 등급 (좋음/보통/나쁨/매우나쁨) 'pm25' 초미세먼지 등급 :returns: 해당 항목의 값 문자열, 실패 시 None example:: '45' '보통' or None """ res = self.search(search_region) if res is None: return None return res.get(search_item)
[문서] class Trivia: """ Functions: :meth:`~openpibo.collect.Trivia.search` :meth:`~openpibo.collect.Trivia.search_s` Open Trivia DB에서 퀴즈 문제를 가져옵니다. (API 키 불필요) example:: from openpibo.collect import Trivia trivia = Trivia() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """ category_list = { '일반': 9, '책': 10, '영화': 11, '음악': 12, '게임': 15, '과학': 17, '컴퓨터': 18, '수학': 19, '스포츠': 21, '지리': 22, '역사': 23, '정치': 24, '동물': 27, } """ 퀴즈 카테고리 목록입니다. """ difficulty_list = ['easy', 'medium', 'hard'] """ 퀴즈 난이도입니다. """
[문서] def search(self, category: str = '일반', difficulty: str = 'easy', count: int = 1): """ 퀴즈 문제를 가져옵니다. (영어) example:: result = trivia.search('과학', 'easy', 3) :param str category: 카테고리 (default: 일반) 카테고리 목록:: '일반', '책', '영화', '음악', '게임', '과학', '컴퓨터', '수학', '스포츠', '지리', '역사', '정치', '동물' :param str difficulty: 난이도 (default: easy) 난이도 목록:: 'easy', 'medium', 'hard' :param int count: 문제 수 (default: 1, 최대 50) :returns: 퀴즈 문제 리스트를 반환합니다. 실패 시 None. example:: [ { 'question': 'What is the chemical symbol for water?', 'answer': 'H2O', 'options': ['H2O', 'CO2', 'NaCl', 'O2'], # 정답 포함 4지선다 (섞인 순서) 'category': '과학', 'difficulty': 'easy', 'type': 'multiple', # 'multiple' or 'boolean' }, ... ] or None """ import html as html_lib import random if category not in self.category_list: raise Exception(f'"{category}" not support') if difficulty not in self.difficulty_list: raise Exception(f'"{difficulty}" not support') params = { 'amount': min(max(1, count), 50), 'category': self.category_list[category], 'difficulty': difficulty, 'type': 'multiple', 'encode': 'url3986', } resp = requests.get('https://opentdb.com/api.php', params=params, headers={'User-Agent': 'Mozilla/5.0'}) if resp.status_code != 200: return None data = resp.json() if data.get('response_code') != 0: return None result = [] for item in data.get('results', []): question = html_lib.unescape(requests.utils.unquote(item.get('question', ''))) answer = html_lib.unescape(requests.utils.unquote(item.get('correct_answer', ''))) incorrects = [html_lib.unescape(requests.utils.unquote(o)) for o in item.get('incorrect_answers', [])] options = incorrects + [answer] random.shuffle(options) result.append({ 'question': question, 'answer': answer, 'options': options, 'category': category, 'difficulty': difficulty, 'type': item.get('type', 'multiple'), }) return result if result else None
[문서] def search_s(self, category: str = '일반', difficulty: str = 'easy'): """ 퀴즈 문제 1개를 간단하게 반환합니다. (block 전용) example:: result = trivia.search_s('과학', 'easy') :param str category: 카테고리 (default: 일반) :param str difficulty: 난이도 (default: easy) :returns: 퀴즈 1개의 dictionary, 실패 시 None example:: { 'question': 'What is the chemical symbol for water?', 'answer': 'H2O', 'options': ['H2O', 'CO2', 'NaCl', 'O2'], ... } or None """ res = self.search(category, difficulty, 1) if res is None: return None return res[0]
[문서] class Country: """ Functions: :meth:`~openpibo.collect.Country.search` :meth:`~openpibo.collect.Country.search_s` restcountries.com에서 국가 정보를 가져옵니다. (API 키 불필요) example:: from openpibo.collect import Country country = Country() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """ info_list = [ 'name', 'capital', 'region', 'subregion', 'population', 'area', 'languages', 'currencies', 'flag', 'borders', 'timezones', 'tld', 'car_side', 'landlocked', 'latlng', ] """ 조회 가능한 항목 목록입니다. """
[문서] def search(self, search_name: str): """ 국가명으로 국가 정보를 검색합니다. (영어 국가명) example:: result = country.search('korea') result = country.search('france') :param str search_name: 검색할 국가명 (영어) :returns: 국가 정보 dictionary를 반환합니다. 실패 시 None. example:: { 'name': 'South Korea', # 국가명 'official': 'Republic of Korea', # 공식 국가명 'capital': '서울특별시', # 수도 (해당 언어로 제공 시) 'region': 'Asia', # 대륙 'subregion': 'Eastern Asia', # 소지역 'population': 51744876, # 인구 'area': 100210.0, # 면적 (km²) 'languages': ['Korean'], # 공용어 'currencies': [{'name': 'South Korean won', 'symbol': '₩'}], 'flag': '🇰🇷', # 국기 이모지 'flag_url': 'https://flagcdn.com/kr.png', 'borders': ['PRK'], # 인접국 코드 'timezones': ['UTC+09:00'], 'tld': ['.kr'], # 국가 도메인 'car_side': 'right', # 운전석 방향 'landlocked': False, # 내륙국 여부 'latlng': [37.0, 127.5], # 위경도 } or None """ resp = requests.get( f'https://restcountries.com/v3.1/name/{requests.utils.quote(search_name)}', headers={'User-Agent': 'Mozilla/5.0'}, timeout=10, ) if resp.status_code != 200: return None data = resp.json() if not data: return None # 검색 결과 중 공식명/일반명이 가장 근접한 항목 선택 item = data[0] for d in data: n = d.get('name', {}) if search_name.lower() in (n.get('common', '').lower(), n.get('official', '').lower()): item = d break name_obj = item.get('name', {}) currencies = item.get('currencies', {}) langs = item.get('languages', {}) flags = item.get('flags', {}) return { 'name': name_obj.get('common', ''), 'official': name_obj.get('official', ''), 'capital': (item.get('capital') or [''])[0], 'region': item.get('region', ''), 'subregion': item.get('subregion', ''), 'population': item.get('population', 0), 'area': item.get('area', 0.0), 'languages': list(langs.values()), 'currencies': [ {'name': v.get('name', ''), 'symbol': v.get('symbol', '')} for v in currencies.values() ], 'flag': item.get('flag', ''), 'flag_url': flags.get('png', ''), 'borders': item.get('borders', []), 'timezones': item.get('timezones', []), 'tld': item.get('tld', []), 'car_side': item.get('car', {}).get('side', ''), 'landlocked': item.get('landlocked', False), 'latlng': item.get('latlng', []), }
[문서] def search_s(self, search_name: str, search_item: str = 'capital'): """ 국가 정보 중 특정 항목만 반환합니다. (block 전용) example:: result = country.search_s('korea', 'capital') result = country.search_s('france', 'population') :param str search_name: 검색할 국가명 (영어) :param str search_item: 조회 항목 (default: capital) 조회 가능한 항목:: 'name' 국가명 'capital' 수도 'region' 대륙 'subregion' 소지역 'population' 인구 'area' 면적 (km²) 'languages' 공용어 'currencies' 화폐 'flag' 국기 이모지 'borders' 인접국 코드 목록 'car_side' 운전석 방향 (left/right) 'landlocked' 내륙국 여부 'latlng' 위경도 :returns: 해당 항목의 값, 실패 시 None example:: 'Seoul' 51744876 ['Korean'] or None """ res = self.search(search_name) if res is None: return None return res.get(search_item)
[문서] class OnThisDay: """ Functions: :meth:`~openpibo.collect.OnThisDay.search` :meth:`~openpibo.collect.OnThisDay.search_s` Wikipedia REST API를 사용해 특정 날짜에 일어난 역사적 사건을 가져옵니다. (API 키 불필요, 영어) example:: from openpibo.collect import OnThisDay otd = OnThisDay() # 아래의 모든 예제 이전에 위 코드를 먼저 사용합니다. """ type_list = ['events', 'births', 'deaths', 'holidays', 'selected'] """ 조회 가능한 유형입니다. - ``events`` : 역사적 사건 - ``births`` : 이날 태어난 인물 - ``deaths`` : 이날 사망한 인물 - ``holidays`` : 공휴일/기념일 - ``selected`` : Wikipedia 편집자 선정 주요 사건 """
[문서] def search(self, month: int, day: int, event_type: str = 'events', count: int = 5): """ 특정 날짜(``month``/``day``)의 역사적 사건을 가져옵니다. example:: result = otd.search(3, 1) # 3월 1일 사건 result = otd.search(8, 15, 'births', 3) # 8월 15일 태어난 인물 3명 :param int month: 월 (1~12) :param int day: 일 (1~31) :param str event_type: 조회 유형 (default: events) 조회 가능한 유형:: 'events' 역사적 사건 'births' 이날 태어난 인물 'deaths' 이날 사망한 인물 'holidays' 공휴일/기념일 'selected' Wikipedia 선정 주요 사건 :param int count: 반환 건수 (default: 5) :returns: 사건 리스트를 반환합니다. 실패 시 None. example:: [ { 'year': 1919, 'text': 'The March 1st Movement begins in Korea...', 'pages': ['March 1st Movement', 'Korea'], # 관련 Wikipedia 문서 }, ... ] or None """ if event_type not in self.type_list: raise Exception(f'"{event_type}" not support') url = f'https://en.wikipedia.org/api/rest_v1/feed/onthisday/{event_type}/{month}/{day}' resp = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}, timeout=10) if resp.status_code != 200: return None data = resp.json() items = data.get(event_type, []) if not items: return None result = [] for item in items[:count]: pages = [p.get('title', '') for p in item.get('pages', [])] result.append({ 'year': item.get('year', ''), 'text': item.get('text', ''), 'pages': pages, }) return result if result else None
[문서] def search_s(self, month: int, day: int, event_type: str = 'events'): """ 특정 날짜의 역사적 사건 1개를 반환합니다. (block 전용) Wikipedia 선정 주요 사건(selected) 중 첫 번째 항목을 반환합니다. example:: result = otd.search_s(3, 1) result = otd.search_s(8, 15, 'births') :param int month: 월 (1~12) :param int day: 일 (1~31) :param str event_type: 조회 유형 (default: events) :returns: ``'[연도] 사건 내용'`` 형식의 문자열, 실패 시 None example:: '[1919] The March 1st Movement begins in Korea...' or None """ res = self.search(month, day, event_type, 1) if not res: return None item = res[0] return f"[{item['year']}] {item['text']}"
if __name__ == "__main__": wiki = Wikipedia() weather = Weather() news = News() er = ExchangeRate() aq = AirQuality() trivia = Trivia() country = Country() otd = OnThisDay() print('wiki:', wiki.search_s('로봇')) print('weather:', weather.search_s('서울', 'today', 'weather')) print('news:', news.search_s('속보', 'title')) print('exchange:', er.search_s('USD', 'KRW')) print('air:', aq.search_s('서울', 'pm10_grade')) print('trivia:', trivia.search_s('과학', 'easy')) print('country:', country.search_s('korea', 'capital')) print('onthisday:', otd.search_s(3, 1, 'events'))