Browse Source

#1

pull/5/head
みてるぞ 4 months ago
parent
commit
9cadadaae3
2 changed files with 81 additions and 77 deletions
  1. +4
    -1
      __init__.py
  2. +77
    -76
      module.py

+ 4
- 1
__init__.py View File

@@ -1,5 +1,8 @@
"""
ニコニコ動画から情報取得するためのユーティリティ
"""

from .module import (VideoInfo, from .module import (VideoInfo,
fetch_comments,
fetch_embed_info, fetch_embed_info,
fetch_latest_video, fetch_latest_video,
fetch_video_info) fetch_video_info)

+ 77
- 76
module.py View File

@@ -1,10 +1,10 @@
"""
ニコニコ動画から動画情報を取得するためのヘルパ集
"""

from __future__ import annotations from __future__ import annotations


import json
import random
import string
import time
from typing import Any, TypedDict
from typing import TypedDict


import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
@@ -14,6 +14,20 @@ from requests.exceptions import Timeout
def fetch_video_info ( def fetch_video_info (
video_code: str, video_code: str,
) -> VideoInfo | None: ) -> VideoInfo | None:
"""
動画コードからタイトル、タグ、説明を取得して返す.

Parameters
----------
video_code: str
動画コード

Return
------
VideoInfo | None
動画情報
"""

bs = _create_bs_from_url (f"https://www.nicovideo.jp/watch/{ video_code }") bs = _create_bs_from_url (f"https://www.nicovideo.jp/watch/{ video_code }")
if bs is None: if bs is None:
return None return None
@@ -24,10 +38,12 @@ def fetch_video_info (
return None return None
title = '-'.join (title_tag.text.split ('-')[:(-1)]).strip () 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 (',') 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): except (AttributeError, TypeError):
return None return None


@@ -37,59 +53,26 @@ def fetch_video_info (
'description': str (description) } '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 ( def fetch_embed_info (
url: str, url: str,
) -> tuple[str, str, 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) bs = _create_bs_from_url (url)
if bs is None: if bs is None:
@@ -103,14 +86,14 @@ def fetch_embed_info (
if tmp is not None and hasattr (tmp, 'get'): if tmp is not None and hasattr (tmp, 'get'):
try: try:
description = str (tmp.get ('content')) description = str (tmp.get ('content'))
except Exception:
except (AttributeError, TypeError):
pass pass


tmp = bs.find ('meta', attrs = { 'name': 'thumbnail' }) tmp = bs.find ('meta', attrs = { 'name': 'thumbnail' })
if tmp is not None and hasattr (tmp, 'get'): if tmp is not None and hasattr (tmp, 'get'):
try: try:
thumbnail = str (tmp.get ('content')) thumbnail = str (tmp.get ('content'))
except Exception:
except (AttributeError, TypeError):
pass pass


return (title, description, thumbnail) return (title, description, thumbnail)
@@ -119,6 +102,20 @@ def fetch_embed_info (
def fetch_latest_video ( def fetch_latest_video (
tags: list[str], tags: list[str],
) -> VideoInfo | None: ) -> VideoInfo | None:
"""
ニコニコから指定したタグが含まれる動画を検索し,最新のものを返す.

Parameters
----------
tags: list[str]
タグ・リスト

Return
------
VideoInfo | None
動画情報
"""

tag = ' OR '.join (tags) tag = ' OR '.join (tags)
url = f"https://www.nicovideo.jp/tag/{ tag }" url = f"https://www.nicovideo.jp/tag/{ tag }"


@@ -136,7 +133,7 @@ def fetch_latest_video (
.find ('li', class_ = 'item')) .find ('li', class_ = 'item'))


video_info['contentId'] = video['data-video-id'] video_info['contentId'] = video['data-video-id']
except Exception:
except (AttributeError, IndexError, KeyError, TypeError):
return None return None


return fetch_video_info (video_info['contentId']) return fetch_video_info (video_info['contentId'])
@@ -146,6 +143,22 @@ def _create_bs_from_url (
url: str, url: str,
params: dict | None = None, params: dict | None = None,
) -> BeautifulSoup | None: ) -> BeautifulSoup | None:
"""
URL から BeautifulSoup オブゼクトを作成する.

Parameters
----------
url: str
URL
params: dict | None
パラメータ

Return
------
BeautifulSoup | None
BeautifulSoup オブゼクト
"""

if params is None: if params is None:
params = { } params = { }


@@ -163,23 +176,11 @@ def _create_bs_from_url (




class VideoInfo (TypedDict): class VideoInfo (TypedDict):
"""
動画情報
"""

contentId: str contentId: str
title: str title: str
tags: list[str] tags: list[str]
description: 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

Loading…
Cancel
Save