コミットを比較

...

7 コミット

作成者 SHA1 メッセージ 日付
みてるぞ f290e64a4e feat: 旧検索ページから最新取得(暫定)(#2) (#6)
#2

Co-authored-by: miteruzo <miteruzo@naver.com>
Reviewed-on: #6
2026-01-09 04:15:51 +09:00
みてるぞ 76e41ad78d feat: 例外出力(#3) (#5)
#3

Co-authored-by: miteruzo <miteruzo@naver.com>
Reviewed-on: #5
2026-01-09 03:48:50 +09:00
みてるぞ 85670982f0 gitignore 追加 2025-10-23 00:03:00 +09:00
みてるぞ 32ecf2d00f #1 2025-08-17 03:08:45 +09:00
みてるぞ 9cadadaae3 #1 2025-08-17 00:52:16 +09:00
みてるぞ 9fec1cf5f9 #1 2025-08-16 18:46:53 +09:00
みてるぞ cf6391d15c #1 2025-08-16 18:45:03 +09:00
3個のファイルの変更119行の追加80行の削除
+1
ファイルの表示
@@ -0,0 +1 @@
__pycache__
+8 -1
ファイルの表示
@@ -1 +1,8 @@
from .module import VideoInfo, fetch_comments, fetch_embed_info, fetch_video_info
"""
ニコニコ動画から情報取得するためのユーティリティ
"""
from .module import (VideoInfo,
fetch_embed_info,
fetch_latest_video,
fetch_video_info)
+110 -79
ファイルの表示
@@ -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,11 +38,14 @@ 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
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):
description = (bs.find ('meta', attrs = { 'name': 'description' })
.get ('content')) # type: ignore
except (AttributeError, TypeError) as ex:
print (ex)
return None
return { 'contentId': video_code,
@@ -37,59 +54,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,29 +87,88 @@ def fetch_embed_info (
if tmp is not None and hasattr (tmp, 'get'):
try:
description = str (tmp.get ('content'))
except Exception:
pass
except (AttributeError, TypeError) as ex:
print (ex)
tmp = bs.find ('meta', attrs = { 'name': 'thumbnail' })
if tmp is not None and hasattr (tmp, 'get'):
try:
thumbnail = str (tmp.get ('content'))
except Exception:
pass
except (AttributeError, TypeError) as ex:
print (ex)
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 = { 'new_search': 'false',
'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) as ex:
print (ex)
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:
except Timeout as ex:
print (ex)
return None
if req.status_code != 200:
@@ -137,23 +180,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