ニジカのスカトロ,ニジカトロ. https://bsky.app/profile/deerjika-bot.bsky.social
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

nico.py 3.3 KiB

1 week ago
1 week ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. """
  2. ニコニコのニジカ動画取得モヂュール
  3. """
  4. from typing import TypedDict
  5. import requests
  6. from bs4 import BeautifulSoup
  7. from requests.exceptions import Timeout
  8. class VideoInfo (TypedDict):
  9. contentId: str
  10. title: str
  11. tags: list[str]
  12. description: str
  13. def get_nico_deerjika (
  14. ) -> list:
  15. URL = ('https://snapshot.search.nicovideo.jp/api/v2/snapshot/video'
  16. '/contents/search')
  17. now = datetime.now ()
  18. base = now - timedelta (hours = 24)
  19. params = { 'q': '伊地知ニジカ OR ぼざろクリーチャーシリーズ',
  20. 'targets': 'tags',
  21. '_sort': '-startTime',
  22. 'fields': 'contentId,title,description,tags,startTime',
  23. '_limit': 20,
  24. 'jsonFilter': json.dumps ({ 'type': 'or',
  25. 'filters': [{
  26. 'type': 'range',
  27. 'field': 'startTime',
  28. 'from': ('%04d-%02d-%02dT05:00:00+09:00'
  29. % (base.year, base.month, base.day,
  30. base.hour, base.minute)),
  31. 'to': ('%04d-%02d-%02dT05:00:00+09:00'
  32. % (now.year, now.month, now.day)),
  33. 'include_lower': True }] }) }
  34. try:
  35. res = requests.get (URL, params = params, timeout = 60).json ()
  36. except Timeout:
  37. return []
  38. data = []
  39. for datum in res['data']:
  40. datum['tags'] = datum['tags'].split ()
  41. data.append (datum)
  42. return data
  43. pass
  44. def get_latest_deerjika (
  45. ) -> VideoInfo | None:
  46. tag = '伊地知ニジカ'
  47. url = f"https://www.nicovideo.jp/tag/{ tag }"
  48. params = { 'sort': 'f',
  49. 'order': 'd' }
  50. video_info = { }
  51. bs = get_bs_from_url (url, params)
  52. if bs is None:
  53. return None
  54. try:
  55. video = (bs.find_all ('ul', class_ = 'videoListInner')[1]
  56. .find ('li', class_ = 'item'))
  57. video_info['contentId'] = video['data-video-id']
  58. except Exception:
  59. return None
  60. bs = get_bs_from_url ('https://www.nicovideo.jp/watch/'
  61. + video_info['contentId'])
  62. if bs is None:
  63. return None
  64. try:
  65. video_info['title'] = '-'.join (bs.find ('title').text.split ('-')[:(-1)])[:(-1)]
  66. tags = bs.find ('meta', attrs = { 'name': 'keywords' }).get ('content')
  67. video_info['tags'] = tags.split (',')
  68. video_info['description'] = bs.find ('meta', attrs = { 'name': 'description' }).get ('content')
  69. except Exception:
  70. return None
  71. return video_info
  72. def get_bs_from_url (
  73. url: str,
  74. params: dict = { },
  75. ) -> BeautifulSoup | None:
  76. """
  77. URL から BeautifulSoup インスタンス生成
  78. Parameters
  79. ----------
  80. url: str
  81. 捜査する URL
  82. params: dict
  83. パラメータ
  84. Return
  85. ------
  86. BeautifulSoup | None
  87. BeautifulSoup オブゼクト(失敗したら None)
  88. """
  89. try:
  90. req = requests.get (url, params = params, timeout = 60)
  91. except Timeout:
  92. return None
  93. if req.status_code != 200:
  94. return None
  95. req.encoding = req.apparent_encoding
  96. return BeautifulSoup (req.text, 'html.parser')