はじめに
前回(https://qiita.com/kerobot/items/6009cb0db643bceaf4e9)は、ホロライブの配信予定や動画情報をホロジュールと Youtube から収集するプログラムを作成しました。
今回は、収集した情報を MongoDB に登録するようにしてみます。
前回のプログラムをもとに MongoDB の処理を追加するだけですが、Poetry と pyenv を利用するため、プロジェクトの構成やプログラムの内容も全体的に変更します。
Azure Cosmos DB (Mongo API) も調べ始めたりしたのですが、価格モデルがいまいち理解できず、意図しない課金を避けるために断念しました。Azure 仮想マシンの Debian に MongoDB を導入すればいいか。という程度で考えています。
最終的にやりたいこと
ここ最近、毎日のように閲覧している バーチャル YouTuber プロダクション「ホロライブ」などの、動画配信予定を定期的にデータベースに格納し、それを Web API で参照して閲覧する Android アプリを作りたい。
- 動画配信予定を収集するためのプログラムの作成(前回)
- 収集した動画配信予定を格納するためのデータベースの作成と収集の自動化(今回)
- 格納した動画配信予定を参照するための Web API の作成
- Web API を参照して動画配信予定を閲覧する Android アプリの作成
やったこと
今回は、やりたいこと 2 の「収集した動画配信予定を格納するためのデータベースの作成と収集の自動化」のうち、データベースの作成までを行いました。
収集の自動化は、近いうちにあらためて Debian + Python3 + MongoDB で構築します。
-
開発環境の準備
- Python のバージョン管理やパッケージ管理のための Poetry と pyenv の導入
- MongoDB のインストールと設定
- MongoDB の接続確認
-
プロジェクトの準備
- Poetry を利用してプロジェクトの作成とパッケージのインストール
- pyenv を 利用して Python のバージョンをセット
- git の初期化
- .gitignore の作成
- Web スクレイピングのための geckodriver のダウンロード
- YouTube 動画情報を取得するための YouTube Data API v3 の有効化
- .env の作成
-
プログラムの作成(前回のプログラムをもとに修正)
- .env からの設定情報の取得
- プログラム実行時のコマンドライン引数の取得
- ホロライブプロダクション配信予定スケジュール『ホロジュール』の情報を取得
- YouTube から動画の情報を取得
- CSV ファイルの出力
-
プログラムの実行
- lounch.json の作成
- プログラムのデバッグ実行
- 実行結果(MongoDB に登録されたドキュメント)
- 実行結果(出力したCSVファイル)
- ファイル構成
開発環境の準備
下記構成の環境を用意しました。
- Windows 10 Pro 1909 x64
- Python 3.8.5 x64
- PowerShell 7.0 x64
- Visual Studio Code 1.50.0 x64
- Git for Windows 2.27.0 x64
- MongoDB 4.4.1 x64
Poetry と pyenv の導入
参考:Windows 10 で Python のインストールから Poetry と pyenv の利用
> poetry --version
Poetry version 1.1.0
> pyenv --version
pyenv 2.64.2
MongoDB のインストールと設定
参考:Windows 10 に MongoDB をインストールして Python から利用する
> mongo --version
MongoDB shell version v4.4.1
Build Info: {
"version": "4.4.1",
"gitVersion": "ad91a93a5a31e175f5cbf8c69561e788bbc55ce1",
"modules": [
"enterprise"
],
"allocator": "tcmalloc",
"environment": {
"distmod": "windows",
"distarch": "x86_64",
"target_arch": "x86_64"
}
}
MongoDB の接続確認とデータベースの作成
MongoDB に接続できることを確認します。
> mongo localhost:27017/admin -u admin -p
MongoDB shell version v4.4.1
データベースを作成してロール(今回は dbOwner )を設定しておきます。
MongoDB > use holoduledb
MongoDB > db.createUser( { user:"owner", pwd:"password", roles:[{ "role" : "dbOwner", "db" : "holoduledb" }] } );
接続できることを確認したら、MongoDB のシェルを終了します。
MongoDB > exit
プロジェクトの準備
poetry と pyenv
poetry を利用してプロジェクトを作成します。
> poetry new holocrawler --name app
プロジェクトのディレクトリに移動します。
> cd holocrawler
念のため、pyenv をアップデートしておきます。
> pyenv update
pyenv でインストール可能な Python のバージョンを確認します。
> pyenv install -l
ローカル(プロジェクトディレクトリ内)で利用する Python をセットします。
> pyenv local 3.8.5
切り替わったかを確認します。
> python -V
Python 3.8.5
セットした Python に切り替わらない場合は、rehash で shim コマンドを更新します。
> pyenv rehash
これにより、$HOME/.pyenv/shims/ 配下のコマンドが更新され、セットした Python に切り替わります。
poetry を利用してパッケージを pyproject.toml に追加しインストールします。
> poetry add pylint
> poetry add beautifulsoup4
> poetry add requests
> poetry add selenium
> poetry add lxml
> poetry add google-api-python-client
> poetry add python-dotenv
> poetry add pymongo
パッケージがインストールされるとともに、pyproject.toml が下記のように更新されます。
pyproject.toml にパッケージを記述したうえで poetry install を実行しても良いです。
[tool.poetry.dependencies]
python = "^3.8"
pylint = "^2.6.0"
beautifulsoup4 = "^4.9.3"
requests = "^2.24.0"
selenium = "^3.141.0"
lxml = "^4.5.2"
google-api-python-client = "^1.12.3"
python-dotenv = "^0.14.0"
pymongo = "^3.11.0"
poetry を利用して Python のバージョンを確認してみます。
> poetry run python -V
Python 3.8.5
git の初期化
git を初期化しておきます。
> git init
.gitignore の作成
.gitignore ファイルを作成し、除外対象を設定しておきます。
> ni .gitignore
__pycache__/
*.egg-info/
*.egg
.env
.venv
env/
venv/
.python-version
/geckodriver.log
/geckodriver.exe
Web スクレイピングのための geckodriver のダウンロード
Selenium で Firefox を利用するための geckodriver をダウンロードします。
- geckodriver (geckodriver-v0.27.0-win64.zip) をダウンロードします。
- geckodriver-v0.27.0-win64.zip を解凍し、geckodriver.exe を任意の場所に配置して PATH を通しておきます。
YouTube 動画情報を取得するための YouTube Data API v3 の有効化
Google Developer Console でプロジェクトを作成し、YouTube Data API v3 を有効化します。
- Google Developer Console にログイン
- ダッシュボードでプロジェクトを作成
- ライブラリで YouTube Data API v3 を有効化
- 認証情報で認証情報を作成して APIキー を取得
.env の作成
YouTube Data API v3 の APIキーや、MongoDB の接続情報などを設定しておくためのファイルを作成します。
> ni .env
HOLODULE_URL = "<Holodule URL>"
API_KEY = "<Youtube Data API Key>"
API_SERVICE_NAME = "youtube"
API_VERSION = "v3"
MONGODB_USER = "<user>"
MONGODB_PASSWORD = "<password>"
MONGODB_HOST = "<localhost:27017>"
プログラムの作成
.env から取得した設定情報を保持するクラス
app/settings.py ファイルを作成します。
import os
import urllib.request
from dotenv import load_dotenv
class Settings:
def __init__(self, envpath):
# .env ファイルを明示的に指定して環境変数として読み込む
self.__dotenv_path = envpath
load_dotenv(self.__dotenv_path)
# 環境変数から設定値を取得
self.__holodule_url = os.environ.get("HOLODULE_URL")
if self.__check_url(self.__holodule_url) == False:
raise ValueError("指定したURLにアクセスできません。")
self.__api_key = os.environ.get("API_KEY")
self.__api_service_name = os.environ.get("API_SERVICE_NAME")
self.__api_version = os.environ.get("API_VERSION")
self.__mongodb_user = os.environ.get("MONGODB_USER")
self.__mongodb_password = os.environ.get("MONGODB_PASSWORD")
self.__mongodb_host = os.environ.get("MONGODB_HOST")
# ホロジュールのURL
@property
def holodule_url(self):
return self.__holodule_url
# Youtube Data API v3 の APIキー
@property
def api_key(self):
return self.__api_key
# Youtube Data API v3 の APIサービス名
@property
def api_service_name(self):
return self.__api_service_name
# Youtube Data API v3 の APIバージョン
@property
def api_version(self):
return self.__api_version
# mongodb の ユーザー
@property
def mongodb_user(self):
return self.__mongodb_user
# mongodb の パスワード
@property
def mongodb_password(self):
return self.__mongodb_password
# mongodb の ホスト:ポート
@property
def mongodb_host(self):
return self.__mongodb_host
# 指定したURLにアクセスできるかをチェック
def __check_url(self, url):
try:
with urllib.request.urlopen(url):
return True
except urllib.request.HTTPError:
return False
ホロジュールから取得した情報を保持するクラス
app/holodule.py ファイルを作成します。
"""
ホロジュールの配信情報+Youtubeの動画情報含む
"""
class Holodule:
codes = {
"ときのそら" : "HL0001",
"ロボ子さん" : "HL0002",
"さくらみこ" : "HL0003",
"星街すいせい" : "HL0004",
"夜空メル" : "HL0101",
"アキ・ローゼンタール" : "HL0102",
"赤井はあと" : "HL0103",
"白上フブキ" : "HL0104",
"夏色まつり" : "HL0105",
"湊あくあ" : "HL0201",
"紫咲シオン" : "HL0202",
"百鬼あやめ" : "HL0203",
"癒月ちょこ" : "HL0204",
"大空スバル" : "HL0205",
"大神ミオ" : "HL0G02",
"猫又おかゆ" : "HL0G03",
"戌神ころね" : "HL0G04",
"兎田ぺこら" : "HL0301",
"潤羽るしあ" : "HL0302",
"不知火フレア" : "HL0303",
"白銀ノエル" : "HL0304",
"宝鐘マリン" : "HL0305",
"天音かなた" : "HL0401",
"桐生ココ" : "HL0402",
"角巻わため" : "HL0403",
"常闇トワ" : "HL0404",
"姫森ルーナ" : "HL0405",
"獅白ぼたん" : "HL0501",
"雪花ラミィ" : "HL0502",
"尾丸ポルカ" : "HL0503",
"桃鈴ねね" : "HL0504",
"魔乃アロエ" : "HL0505"
}
def __init__(self):
self.__video_id = ""
self.__datetime = None
self.__name = ""
self.__title = ""
self.__url = ""
self.__description = ""
# キー
@property
def key(self):
_code = Holodule.codes[self.name] if self.name in Holodule.codes else ""
_dttm = self.datetime.strftime("%Y%m%d_%H%M%S") if self.datetime is not None else ""
return _code + "_" + _dttm if ( len(_code) > 0 and len(_dttm) > 0 ) else ""
# video_id
@property
def video_id(self):
return self.__video_id
@video_id.setter
def video_id(self, video_id):
self.__video_id = video_id
# 日時
@property
def datetime(self):
return self.__datetime
@datetime.setter
def datetime(self, datetime):
self.__datetime = datetime
# 名前
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
self.__name = name
# タイトル(Youtubeから取得)
@property
def title(self):
return self.__title
@title.setter
def title(self, title):
self.__title = title
# URL
@property
def url(self):
return self.__url
@url.setter
def url(self, url):
self.__url = url
# 説明(Youtubeから取得)
@property
def description(self):
return self.__description
@description.setter
def description(self, description):
self.__description = description
# ドキュメントへ変換
def to_doc(self):
doc = { 'key': str(self.key),
'video_id': str(self.video_id),
'datetime' : str(self.datetime.strftime("%Y%m%d %H%M%S")),
'name' : str(self.name),
'title' : str(self.title),
'url' : str(self.url),
'description' : str(self.description) }
return doc
ホロジュールと youtube の動画情報を取得して MongoDB へ登録するクラス
app/holocrawler.py ファイルを作成します。
"""
【ホロライブ】ホロジュールと Youtube の動画情報を取得して MongoDB へ登録する
1. 事前に geckodriver をダウンロードして配置し PATH を設定しておく
geckodriver https://github.com/mozilla/geckodriver/releases
2. Google の YouTube Data API v3 を有効化して API キーを取得しておく
Google Developer Console https://console.developers.google.com/?hl=JA
3. .envファイルを作成し、URLやAPIキーを設定しておく
参考 : .env.sample
4. pyproject.toml を利用して Python のパッケージを一括インストールしておく
参考 : pyproject.toml
"""
import sys
import os
import csv
import re
import datetime
import time
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from apiclient.discovery import build #pylint: disable=import-error
from apiclient.errors import HttpError #pylint: disable=import-error
from pymongo import MongoClient
from urllib.parse import quote_plus
from bson.objectid import ObjectId
from app.settings import Settings
from app.holodule import Holodule
class HoloCrawler:
def __init__(self, settings):
self.__driver = None
self.__wait = None
# ホロジュールの URL
self.__holodule_url = settings.holodule_url
# YouTube Data API v3 を利用するための準備
self.__youtube = build(settings.api_service_name, settings.api_version, developerKey=settings.api_key, cache_discovery=False)
# mongodbのユーザー
self.__mongodb_user = quote_plus(settings.mongodb_user)
# mongodbのパスワード
self.__mongodb_password = quote_plus(settings.mongodb_password)
# mongodbの接続情報
self.__mongodb_host = "mongodb://%s/" % (settings.mongodb_host)
# Firefoxプロファイルの設定
def __setup_profile(self):
profile = webdriver.FirefoxProfile()
# その他(参考)
# profile.set_preference("browser.download.folderList", 1)
# profile.set_preference("browser.download.dir", "********")
# profile.set_preference("browser.download.manager.showWhenStarting", False)
# profile.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream-dummy")
# profile.set_preference("browser.helperApps.alwaysAsk.force", False)
# profile.set_preference("browser.download.manager.alertOnEXEOpen", False)
# profile.set_preference("browser.download.manager.focusWhenStarting", False)
# profile.set_preference("browser.download.manager.useWindow", False)
# profile.set_preference("browser.download.manager.showAlertOnComplete", False)
# profile.set_preference("browser.download.manager.closeWhenDone", False)
return profile
# Firefoxオプションの設定
def __setup_options(self):
options = Options()
# ヘッドレスモードとする
options.add_argument("--headless")
return options
# ホロジュールの取得
def __get_holodule(self):
# 取得対象の URL に遷移
self.__driver.get(self.__holodule_url)
# <div class="holodule" style="margin-top:10px;">が表示されるまで待機する
self.__wait.until(EC.presence_of_element_located((By.CLASS_NAME, "holodule")))
# ページソースの取得
html = self.__driver.page_source.encode("utf-8")
# ページソースの解析(パーサとして lxml を指定)
soup = BeautifulSoup(html, "lxml")
# タイトルの取得(確認用)
head = soup.find("head")
title = head.find("title").text
print(title)
# TODO : ここからはページの構成に合わせて決め打ち = ページの構成が変わったら動かない
# スケジュールの取得
holodule_list = []
date_string = ""
today = datetime.date.today()
tab_pane = soup.find("div", class_="tab-pane show active")
containers = tab_pane.find_all("div", class_="container")
for container in containers:
# 日付のみ取得
div_date = container.find("div", class_="holodule navbar-text")
if div_date is not None:
date_text = div_date.text.strip()
match_date = re.search(r"[0-9]{1,2}/[0-9]{1,2}", date_text)
dates = match_date.group(0).split("/")
month = int(dates[0])
day = int(dates[1])
year = today.year
if month < today.month or ( month == 12 and today.month == 1 ):
year = year - 1
elif month > today.month or ( month == 1 and today.month == 12 ):
year = year + 1
date_string = f"{year}/{month}/{day}"
# print(date_string)
# ライバー毎のスケジュール
thumbnails = container.find_all("a", class_="thumbnail")
if thumbnails is not None:
for thumbnail in thumbnails:
holodule = Holodule()
# Youtube URL
youtube_url = thumbnail.get("href")
if youtube_url is not None:
holodule.url = youtube_url
# print(holodule.url)
# 時刻(先に取得しておいた日付と合体)
div_time = thumbnail.find("div", class_="col-5 col-sm-5 col-md-5 text-left datetime")
if div_time is not None:
time_text = div_time.text.strip()
match_time = re.search(r"[0-9]{1,2}:[0-9]{1,2}", time_text)
times = match_time.group(0).split(":")
hour = int(times[0])
minute = int(times[1])
datetime_string = f"{date_string} {hour}:{minute}"
holodule.datetime = datetime.datetime.strptime(datetime_string, "%Y/%m/%d %H:%M")
# print(holodule.datetime)
# ライバーの名前
div_name = thumbnail.find("div", class_="col text-right name")
if div_name is not None:
holodule.name = div_name.text.strip()
# print(holodule.name)
# リストに追加
if len(holodule.key) > 0:
holodule_list.append(holodule)
return holodule_list
# Youtube 動画情報の取得
def __get_youtube_video_info(self, youtube_url):
# Youtube の URL から ID を取得
match_video = re.search(r"^[^v]+v=(.{11}).*", youtube_url)
video_id = match_video.group(1)
# Youtube はスクレイピングを禁止しているので YouTube Data API (v3) で情報を取得
search_response = self.__youtube.videos().list(
# 結果として snippet のみを取得
part="snippet",
# 検索条件は id
id=video_id,
# 1件のみ取得
maxResults=1
).execute()
# 検索結果から情報を取得
for search_result in search_response.get("items", []):
# id
vid = search_result["id"]
# タイトル
title = search_result["snippet"]["title"]
# 説明
description = search_result["snippet"]["description"]
# IDとタイトルと説明を返却
return (vid, title, description)
return ("","","")
# ホロジュールのスクレイピングと Youtube 動画情報から、配信情報リストの取得
def get_holodule_list(self):
try:
# プロファイルのセットアップ
profile = self.__setup_profile()
# オプションのセットアップ
options = self.__setup_options()
# ドライバの初期化(オプション(ヘッドレスモード)とプロファイルを指定)
self.__driver = webdriver.Firefox(options=options, firefox_profile=profile)
# 指定したドライバに対して最大で10秒間待つように設定する
self.__wait = WebDriverWait(self.__driver, 10)
# ホロジュールの取得
holodule_list = self.__get_holodule()
# Youtube情報の取得
for holodule in holodule_list:
# video情報
video_info = self.__get_youtube_video_info(holodule.url)
# video_id
holodule.video_id = video_info[0]
# タイトル
holodule.title = video_info[1]
# 説明文(長いので100文字で切っている)
holodule.description = video_info[2].replace("\r","").replace("\n","").replace("\"","").replace("\'","")[:100]
# 生成したリストを返す
return holodule_list
except OSError as err:
print("OS error: {0}".format(err))
except:
print("Unexpected error:", sys.exc_info()[0])
raise
finally:
# ドライバを閉じる
self.__driver.close()
# 配信情報リストのCSV出力
def output_holodule_list(self, holodule_list, filepath):
try:
# CSV出力(BOM付きUTF-8)
with open(filepath, "w", newline="", encoding="utf_8_sig") as csvfile:
csvwriter = csv.writer(csvfile, delimiter=",")
csvwriter.writerow(["key", "video_id", "datetime", "name", "title", "url", "description"])
for holodule in holodule_list:
csvwriter.writerow([holodule.key, holodule.video_id, holodule.datetime, holodule.name, holodule.title, holodule.url, holodule.description])
except OSError as err:
print("OS error: {0}".format(err))
except:
print("Unexpected error:", sys.exc_info()[0])
raise
finally:
pass
# 配信情報リストのDB登録
def register_holodule_list(self, holodule_list):
try:
# MongoDB のコレクションからの削除と挿入
client = MongoClient(self.__mongodb_host)
db = client.holoduledb
db.authenticate(name=self.__mongodb_user,password=self.__mongodb_password)
collection = db.holodules
for holodule in holodule_list:
# video_id を条件としたドキュメントの削除
video_id = holodule.video_id
collection.delete_one( {"video_id":video_id} )
# ドキュメントの挿入
doc = holodule.to_doc()
collection.insert_one(doc)
except OSError as err:
print("OS error: {0}".format(err))
except:
print("Unexpected error:", sys.exc_info()[0])
raise
finally:
pass
__init__.py ファイルを作成
app/__init__.py ファイルを作成し、main.py からディレクトリ名と同じ名前空間のモジュールを参照できるようにします。
from . import settings
from . import holodule
from . import holocrawler
__version__ = '0.1.0'
main モジュールを作成
main.py ファイルを作成します。
import sys
import os
import argparse
from os.path import join, dirname
from app.settings import Settings
from app.holocrawler import HoloCrawler
RETURN_SUCCESS = 0
RETURN_FAILURE = -1
def main():
# parser を作る(説明を指定できる)
parser = argparse.ArgumentParser(description="ホロジュールのHTMLをSelenium + BeautifulSoup4 + Youtube API で解析して MongoDB へ登録")
# コマンドライン引数を設定する(説明を指定できる)
parser.add_argument("--csvpath", help="出力するCSVファイルのパス(任意)")
# コマンドライン引数を解析する
args = parser.parse_args()
# ファイルパスの取得
is_output = False
csvpath = args.csvpath
if csvpath is not None:
# ディレクトリパスの取得と存在確認
dirpath = os.path.dirname(csvpath)
print(f"出力ディレクトリパス : {dirpath}")
if os.path.exists(dirpath) == False:
print("エラー : 出力するCSVファイルのディレクトリパスが存在しません。")
return RETURN_FAILURE
is_output = True
try:
# Settings インスタンス
settings = Settings(join(dirname(__file__), '.env'))
# HoloCrawler インスタンス
holocrawler = HoloCrawler(settings)
# ホロジュールの取得
holodule_list = holocrawler.get_holodule_list()
# ホロジュールの登録
holocrawler.register_holodule_list(holodule_list)
# ホロジュールの出力
if is_output == True:
holocrawler.output_holodule_list(holodule_list, csvpath)
return RETURN_SUCCESS
except:
info = sys.exc_info()
print(info[1])
return RETURN_FAILURE
if __name__ == "__main__":
sys.exit(main())
GitHub に登録
GitHub にリポジトリを作成して登録しておきます。
> git status
> git add .
> git commit -m "first commit."
> git remote add origin https://github.com/********/********.git
> git push -u origin main
プログラムの実行
lounch.json の作成
Visual Studio Code で launch.json を作成して出力ファイルパスを設定しておきます。
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": ["--csvpath","c:\\temp\\holodule.csv"]
}
]
}
プログラムのデバッグ実行
Visual Studio Code でデバッグ実行します。
コマンドラインから実行する場合は、下記のように実行します。
> poetry run python main.py --csvpath c:\temp\test.csv
実行結果(MongoDB に登録されたドキュメント)
MongoDB のコレクションに下記のようなドキュメントが登録されます。
{ "_id" : ObjectId("5f843cc5c87f84988a7972c4"), "key" : "HL0403_20201011_000000", "video_id" : "y3WPN1uBusg", "datetime" : "20201011 000000", "name" : "角巻わため", "title" : "【マインクラフト】ついにこの時が来た。チェスト整理回!!!【角巻わため/ホロライブ4期生】", "url" : "https://www.youtube.com/watch?v=y3WPN1uBusg", "description" : "チェストォーーー!!!(チェストだけにね本日遊ばせていただいているゲーム(Minecraft)https://www.minecraft.net/ja-jp/※本ゲームは Mojang に確 認を得た上" }
{ "_id" : ObjectId("5f843cc6c87f84988a7972c5"), "key" : "HL0502_20201011_001400", "video_id" : "EgLwctUuu6M", "datetime" : "20201011 001400", "name" : "雪花ラミィ", "title" : "【Dead by Daylight】今日から始めるDBD生活【雪花ラミィ/ホロライブ】", "url" : "https://www.youtube.com/watch?v=EgLwctUuu6M", "description" : "ホロライブ5期生の雪花ラミィ(Yukihana Lamy )です!怖い人からたくさん逃げて脱出するゲームしていきます。感想などは #らみらいぶ #雪花ラミィ で呟いて頂けたら嬉しいです!୨୧┈┈┈┈┈┈" }
{ "_id" : ObjectId("5f843cc7c87f84988a7972c6"), "key" : "HL0G03_20201011_015800", "video_id" : "2Nsp0z1AmV8", "datetime" : "20201011 015800", "name" : "猫又おかゆ", "title" : "【雑談】ゲリラ!新居ではじめての夜更かし【ホロライブ/猫又おかゆ 】", "url" : "https://www.youtube.com/watch?v=2Nsp0z1AmV8", "description" : "ノープランだらだら雑談!🌠_____________________________________________________________________________ ※僕とみんなのお約" }
実行結果(出力したCSVファイル)
コマンドライン引数を指定して実行すると、下記のような CSV ファイルが出力されます。
HL0501_20201013_195900,jPP8y696Vkc,2020-10-13 19:59:00,獅白ぼたん,【Far Cry 5】信じて崇めて服従してくれるよねぇ?:#02【ホロライブ/獅白ぼたん】,https://www.youtube.com/watch?v=jPP8y696Vkc,今日はフォールズエンドの攻略とドラブマン砦を攻略してハークを仲間にしたい感じ!本ゲームは Ubisoft に確認を得た上、Ubisoft Video Policy (https://www.ubiso
HL0305_20201013_195900,mEsDSRfV95U,2020-10-13 19:59:00,宝鐘マリン,【歌ってみた】青春を感じる!!古めの歌枠/Boomer Song【ホロライブ/宝鐘マリン】,https://www.youtube.com/watch?v=mEsDSRfV95U,サムネイラスト…火ノ❅ホロケット ホ18 @soraneko_hinoお借りしている音源↓・一味の有志の方の製作カラオケ・カラオケ歌っちゃ王 様▷https://www.youtube.com/cha
HL0504_20201013_200000,MJt3YMbAxkM,2020-10-13 20:00:00,桃鈴ねね,【making】✨お礼イラストメイキング✨【ホロライブ/桃鈴ねね】,https://www.youtube.com/watch?v=MJt3YMbAxkM,「せんちょーおすみつきねねは天才神!!!!」お名前呼ばれんかった!!!!って人はねねのリプ欄にアピールしにきてね(;_;)ごめんね(;_;)いつも応援ありが🍑※日本語以外の言語だと大いに読み間違えてい
...
ファイル構成
holocrawler
├ .venv
├ .vscode
| └ launch.json
├ app
| ├ __init__.py
| ├ holocrawler.py
| ├ holodule.py
| └ settings.py
├ .env
├ .gitignore
├ .python-version
├ geckodriver.exe
├ geckodriver.log
├ main.py
├ poetry.lock
├ pyproject.toml
└ README.md
おわりに
やりたいこと 2 の「収集した動画配信予定を格納するためのデータベースの作成と収集の自動化」のうち、データベースの作成までを行いました。
前回からの変化はあまりありませんでしたが、個人的には Poetry と pyenv を利用できたことが成果です。
次回は Azure 仮想マシン上での定期実行環境の構築や、MongoDB のドキュメントを参照するための Web API を作ってみようと思います。