""" ニコニコ動画から動画情報を取得するためのヘルパ集 """ from __future__ import annotations from typing import TypedDict import requests from bs4 import BeautifulSoup from requests.exceptions import Timeout def fetch_video_info ( video_code: str, ) -> VideoInfo | None: """ 動画コードからタイトル、タグ、説明を取得して返す. Parameters ---------- video_code: str 動画コード Return ------ VideoInfo | None 動画情報 """ bs = _create_bs_from_url (f"https://www.nicovideo.jp/watch/{ video_code }") if bs is None: return None try: title_tag = bs.find ('title') if title_tag is None: return None title = '-'.join (title_tag.text.split ('-')[:(-1)]).strip () tags_str: str = (bs.find ('meta', attrs = { 'name': 'keywords' }) .get ('content')) # type: ignore tags = tags_str.split (',') description = (bs.find ('meta', attrs = { 'name': 'description' }) .get ('content')) # type: ignore except (AttributeError, TypeError): return None return { 'contentId': video_code, 'title': title, 'tags': tags, 'description': str (description) } def fetch_embed_info ( url: str, ) -> tuple[str, str, str]: """ ニコニコ動画の URL からタイトル、詳細、サムネールを取得して返す. Parameters ---------- url: str 動画 URL Return ------ tuple[str, str, str] タイトル、詳細、サムネールからなるタプル """ title = '' description = '' thumbnail = '' bs = _create_bs_from_url (url) if bs is None: return ('', '', '') tmp = bs.find ('title') if tmp is not None: title = tmp.text tmp = bs.find ('meta', attrs = { 'name': 'description' }) if tmp is not None and hasattr (tmp, 'get'): try: description = str (tmp.get ('content')) except (AttributeError, TypeError): pass tmp = bs.find ('meta', attrs = { 'name': 'thumbnail' }) if tmp is not None and hasattr (tmp, 'get'): try: thumbnail = str (tmp.get ('content')) except (AttributeError, TypeError): pass return (title, description, thumbnail) def fetch_latest_video ( tags: list[str], ) -> VideoInfo | None: """ ニコニコから指定したタグが含まれる動画を検索し,最新のものを返す. Parameters ---------- tags: list[str] タグ・リスト Return ------ VideoInfo | None 動画情報 """ tag = ' OR '.join (tags) url = f"https://www.nicovideo.jp/tag/{ tag }" params = { 'sort': 'f', 'order': 'd' } video_info = { } bs = _create_bs_from_url (url, params) if bs is None: return None try: video = (bs.find_all ('ul', class_ = 'videoListInner')[1] .find ('li', class_ = 'item')) video_info['contentId'] = video['data-video-id'] except (AttributeError, IndexError, KeyError, TypeError): return None return fetch_video_info (video_info['contentId']) def _create_bs_from_url ( url: str, params: dict | None = None, ) -> BeautifulSoup | None: """ URL から BeautifulSoup オブゼクトを作成する. Parameters ---------- url: str URL params: dict | None パラメータ Return ------ BeautifulSoup | None BeautifulSoup オブゼクト """ if params is None: params = { } try: req = requests.get (url, params = params, timeout = 60) except Timeout: return None if req.status_code != 200: return None req.encoding = req.apparent_encoding return BeautifulSoup (req.text, 'html.parser') class VideoInfo (TypedDict): """ 動画情報 """ contentId: str title: str tags: list[str] description: str