diff --git a/__init__.py b/__init__.py index 661898f..1bdbcfb 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,8 @@ +""" +ニコニコ動画から情報取得するためのユーティリティ +""" + from .module import (VideoInfo, - fetch_comments, fetch_embed_info, fetch_latest_video, fetch_video_info) diff --git a/module.py b/module.py index d52e481..a25fe64 100644 --- a/module.py +++ b/module.py @@ -1,10 +1,10 @@ +""" +ニコニコ動画から動画情報を取得するためのヘルパ集 +""" + from __future__ import annotations -import json -import random -import string -import time -from typing import Any, TypedDict +from typing import TypedDict import requests from bs4 import BeautifulSoup @@ -14,6 +14,20 @@ 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 @@ -24,10 +38,12 @@ def fetch_video_info ( return None title = '-'.join (title_tag.text.split ('-')[:(-1)]).strip () - tags_str: str = bs.find ('meta', attrs = { 'name': 'keywords' }).get ('content') # type: ignore + # type: ignore + tags_str: str = bs.find ('meta', attrs = { 'name': 'keywords' }).get ('content') tags = tags_str.split (',') - description = bs.find ('meta', attrs = { 'name': 'description' }).get ('content') # type: ignore + # type: ignore + description = bs.find ('meta', attrs = { 'name': 'description' }).get ('content') except (AttributeError, TypeError): return None @@ -37,59 +53,26 @@ def fetch_video_info ( 'description': str (description) } -def fetch_comments ( - video_code: str, -) -> list[Comment]: - time.sleep (1.2) - - headers = { 'X-Frontend-Id': '6', - 'X-Frontend-Version': '0' } - - action_track_id = ( - ''.join (random.choice (string.ascii_letters + string.digits) - for _ in range (10)) - + '_' - + str (random.randrange (10 ** 12, 10 ** 13))) - - url = (f"https://www.nicovideo.jp/api/watch/v3_guest/{ video_code }" - + f"?actionTrackId={ action_track_id }") - - res = requests.post (url, headers = headers, timeout = 60).json () - - try: - nv_comment = res['data']['comment']['nvComment'] - except KeyError: - return [] - if nv_comment is None: - return [] - - headers = { 'X-Frontend-Id': '6', - 'X-Frontend-Version': '0', - 'Content-Type': 'application/json' } - - params = { 'params': nv_comment['params'], - 'additionals': { }, - 'threadKey': nv_comment['threadKey'] } - - url = nv_comment['server'] + '/v1/threads' - - res = (requests.post (url, json.dumps (params), - headers = headers, - timeout = 60) - .json ()) - - try: - return res['data']['threads'][1]['comments'] - except (IndexError, KeyError): - return [] - - def fetch_embed_info ( url: str, ) -> tuple[str, str, str]: - title: str = '' - description: str = '' - thumbnail: str = '' + """ + ニコニコ動画の URL からタイトル、詳細、サムネールを取得して返す. + + Parameters + ---------- + url: str + 動画 URL + + Return + ------ + tuple[str, str, str] + タイトル、詳細、サムネールからなるタプル + """ + + title = '' + description = '' + thumbnail = '' bs = _create_bs_from_url (url) if bs is None: @@ -103,14 +86,14 @@ def fetch_embed_info ( if tmp is not None and hasattr (tmp, 'get'): try: description = str (tmp.get ('content')) - except Exception: + 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 Exception: + except (AttributeError, TypeError): pass return (title, description, thumbnail) @@ -119,6 +102,20 @@ def fetch_embed_info ( 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 }" @@ -136,7 +133,7 @@ def fetch_latest_video ( .find ('li', class_ = 'item')) video_info['contentId'] = video['data-video-id'] - except Exception: + except (AttributeError, IndexError, KeyError, TypeError): return None return fetch_video_info (video_info['contentId']) @@ -146,6 +143,22 @@ 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 = { } @@ -163,23 +176,11 @@ def _create_bs_from_url ( class VideoInfo (TypedDict): + """ + 動画情報 + """ + contentId: str title: str tags: list[str] description: str - - -class Comment (TypedDict): - id: str - no: int - vposMs: int - body: str - commands: list[str] - userId: str - isPremium: bool - score: int - postedAt: str - nicoruCount: int - nicoruId: Any - source: str - isMyPost: bool