Ich bin ein VTuber Limit Nerd. Im Dezember fand in Ryogoku Kokugikan "Virtual to Live" statt, das auch von Nico Nama vertrieben wurde. Der Verlierer konnte nicht auf die Website gehen und sie sogar in Echtzeit sehen, aber er konnte nicht warten, bis die CD herauskam. Deshalb habe ich ein Online-Ticket gekauft und die Zeitverschiebung gesehen. Nun, lass uns sterben. Ich wollte es speichern, bevor ich die Zeitverschiebung sehen konnte, also begann ich, Nikosei mit Python in der Hand zu analysieren.
Meine Stärke liegt übrigens in "Was ist Web Socket?", "Hls?", "Selen?".
** * Hinweis: Informationen zum 17. Dezember 2019. Die Spezifikationen von Nico Nama können sich in Zukunft ändern. ** **.
Die Analyse nutzte die DevTools von Chrome. Sie können es anzeigen, indem Sie in Chrome "F12" drücken. Öffnen wir zunächst eine geeignete Distribution. Wenn Sie nach dem Öffnen der Distribution F12 drücken, laden Sie sie einmal neu.
HLS
Auf der Registerkarte "Netzwerk" von DevTools können Sie die Kommunikationsprotokolle für diese Website anzeigen. (Wenn Sie "Cache deaktivieren" aktivieren, wird das Protokoll auch dann nicht ausgeblendet, wenn die Seite verschoben wird.)
Für die Videoverteilung suchte ich nach der Kommunikation mit der größten "Größe".
Dann
https: // {???} .dmc.nico / hlsarchive / ht2_nicolive / nicolive-hamster- {Verteilungs-ID} main {16 hexadezimale Zahl} / 4 / ts / {numerischer Wert} .ts? Ich habe eine große Datenmenge von einer solchen URL heruntergeladen. Die
{number}scheint in der Reihenfolge zuzunehmen. Und von einer ähnlichen URL
https: // {???} .dmc.nico / hlsarchive / ht2_nicolive / nicolive-hamster- {Verteilungs-ID} main {16 hexadezimale Zahl} / 4 / ts / playlist.m3u8?`
Mit der Antwort von
playlist
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
(Unterlassung)
Daten wie diese wurden gesendet. Als ich mit ".m3u8" und ".ts" nachgesehen habe, scheint es sich um eine Datei zu handeln, die vom Protokoll "HLS (HTTP Live Streaming)" verwendet wird. Dieses "HLS" scheint mit "ffmpeg" einfach zu DL zu sein. Sie müssen also nur die URL abrufen.
Woher hast du diese URL?
Drücken Sie "Strg + F" auf der Registerkarte "Netzwerk" von DevTools. Dort fand ich "https: // {???}. Dmc.nico/hlsarchive/ht2_nicolive/nicolive-hamster-{Distribution ID} main {16 hexadezimale Zahl}" Lassen Sie uns durch Eingabe suchen. Anscheinend kommt "Kommunikation mit URL" heraus und "Kommunikation mit URL" wird nicht gefunden.
Aufgrund verschiedener Versuche wie "Was meinst du?" Scheint die Kommunikation im Web-Socket nicht durchsucht werden zu können.
Suchen Sie also mit wss:
.
Dann finden Sie 3 Web-Sockets.
4012 /
scheint Binärdaten aneinander zu senden. Lass es vorerst.
websocket
empfängt Chat-Informationen vom Server im JSON-Format. Sie können dies auch verlassen.
Der verbleibende Web-Socket (hier "Timeshift") ist auf einen Blick nicht ersichtlich. Lassen Sie uns nach der URL suchen, nach der Sie suchen. Dann gab es eine Hit-Kommunikation. Es scheint, dass diese Kommunikation JSON empfängt. Ich habe die gesuchte URL in "uri" in diesem JSON gefunden.
Are you still watching? Nun, das ist natürlich zu sagen, aber es scheint, dass die URL ungültig wird, wenn der Server beurteilt, dass "ich diesen Kerl nicht mehr gesehen habe". Daher ist es nicht möglich zu sagen "Holen Sie sich die URL und lassen Sie es in Ruhe".
Was soll ich dann tun? Ich kam auf die Idee Es war eine Methode, "es Nico Nico zu überlassen". Wenn Sie die Verteilungs-URL in Selenium offen lassen, sendet der Client automatisch "Ich schaue noch" an den Server. In der Zwischenzeit wird "ffmpeg" DL, was eine einfache Geschichte ist. Diese Methode ist jedoch in Ordnung, wenn Sie sie nur herunterladen. Ich denke jedoch, dass sie nicht verwendet werden kann, wenn es um "Ich möchte sie mit meiner eigenen Anwendung spielen!" Geht. In diesem Fall müssen Sie "Ich schaue immer noch" selbst senden Es gibt. Außerdem kann Nico Nico die Lieferung jeweils nur in einem Fenster sehen (ich bin mit Nico Nico nicht vertraut, daher kenne ich die Details nicht). Bitte beachten Sie, dass DL beendet wird, wenn Sie die Distribution während DL öffnen.
shell
python dl.py {live_id} {id} {pass}
Sie können es mit tun.
dl.py
from selenium import webdriver
import chromedriver_binary
import json
import time
import sys
import subprocess
lid = sys.argv[1]
id = sys.argv[2]
pa = sys.argv[3]
options = webdriver.ChromeOptions()
options.add_argument('--headless')
caps = webdriver.DesiredCapabilities.CHROME
caps['goog:loggingPrefs'] = {'performance': 'ALL'}
driver = webdriver.Chrome(
options=options, desired_capabilities=caps, service_log_path='NUL')
driver.get('https://account.nicovideo.jp/login')
fid = driver.find_element_by_xpath('//*[@id="input__mailtel"]')
fpa = driver.find_element_by_xpath('//*[@id="input__password"]')
fid.clear()
fid.send_keys(id)
fpa.clear()
fpa.send_keys(pa)
fpa.submit()
driver.get('https://live2.nicovideo.jp/watch/' + lid)
# setting_button = driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/div[3]/button[4]').click()
# time.sleep(1)
# driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/div[4]/div/div/div[2]').click()
# time.sleep(1)
# driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/div[4]/section[2]/ul/div[2]').click()
# time.sleep(3)
# driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/button').click()
time.sleep(3)
log = [json.loads(i['message']) for i in driver.get_log(
'performance') if json.loads(i['message'])['message']['method'] == 'Network.webSocketFrameReceived']
log = [json.loads(i['message']['params']['response']['payloadData'])
for i in log if i['message']['params']['response']['payloadData'][0] == '{']
log = [i['body'] for i in log if 'body' in i.keys()]
uri = ''
quality = 6
for i in log:
if 'command' in i.keys():
if i['command'] == 'currentstream':
if 0 != i['currentStream']['qualityTypes'].index(i['currentStream']['quality']) < quality:
uri = i['currentStream']['uri']
quality = i['currentStream']['qualityTypes'].index(
i['currentStream']['quality'])
if quality == 0:
break
subprocess.run(['ffmpeg', '-i', uri, '-c', 'copy', 'output.mp4'])
driver.quit()
options = webdriver.ChromeOptions()
options.add_argument('--headless')
caps = webdriver.DesiredCapabilities.CHROME
caps['goog:loggingPrefs'] = {'performance': 'ALL'}
driver = webdriver.Chrome(
options=options, desired_capabilities=caps, service_log_path='NUL')
Sie können es ausführen, ohne das Fenster anzuzeigen, indem Sie die Option "--headless" hinzufügen.
caps ['goog: loggingPrefs'] = {'performance': 'ALL'}
ist die Einstellung zum Anzeigen des Kommunikationsprotokolls.
Ich bin mir über die Details nicht sicher.
driver.get('https://account.nicovideo.jp/login')
fid = driver.find_element_by_xpath('//*[@id="input__mailtel"]')
fpa = driver.find_element_by_xpath('//*[@id="input__password"]')
fid.clear()
fid.send_keys(id)
fpa.clear()
fpa.send_keys(pa)
fpa.submit()
Nico-Schüler können nicht gesehen werden, ohne sich anzumelden. Melden Sie sich daher hier einmal an.
driver.get('https://live2.nicovideo.jp/watch/' + lid)
# setting_button = driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/div[3]/button[4]').click()
# time.sleep(1)
# driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/div[4]/div/div/div[2]').click()
# time.sleep(1)
# driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/div[4]/section[2]/ul/div[2]').click()
# time.sleep(3)
# driver.find_element_by_xpath(
# '/html/body/div/div/div[4]/div[3]/div/div/div[1]/div[3]/div[1]/div[2]/button').click()
time.sleep(3)
log = [json.loads(i['message']) for i in driver.get_log(
'performance') if json.loads(i['message'])['message']['method'] == 'Network.webSocketFrameReceived']
log = [json.loads(i['message']['params']['response']['payloadData'])
for i in log if i['message']['params']['response']['payloadData'][0] == '{']
log = [i['body'] for i in log if 'body' in i.keys()]
uri = ''
quality = 6
for i in log:
if 'command' in i.keys():
if i['command'] == 'currentstream':
if i['currentStream']['qualityTypes'].index(i['currentStream']['quality']) < quality:
uri = i['currentStream']['uri']
quality = i['currentStream']['qualityTypes'].index(
i['currentStream']['quality'])
if quality == 0:
break
Sie können das Leistungsprotokoll mit "driver.get_log (" Leistung ")" abrufen.
if json.loads (i ['message']) ['message'] ['method'] == 'Network.webSocketFrameReceived'
extrahiert nur den Empfang von Websocket.
Von dort werden wir nur diejenigen belassen, die "JSON-Format haben und einen" Körper "haben.
Die URL wird mit "uri = i ['currentStream'] ['uri']" gespeichert.
Hier versuche ich, die "beste URL" aus der Kommunikation zu erhalten.
Im Kommentarbereich wählen wir das Video mit der höchsten Qualität aus und stoppen das Video.
Ich habe dies auskommentiert, da es sich sehr wahrscheinlich in zukünftigen Updates ändern wird.
Wir empfehlen Ihnen, die Verwendung von Selen zu untersuchen und selbst zu schreiben.
subprocess.run(['ffmpeg', '-i', uri, '-c', 'copy', 'output.mp4'])
driver.quit()
Ich führe ffmpeg
mit subprocess.run aus (['ffmpeg', '- i', uri, '- c', 'copy', 'output.mp4'])
.
ffmpeg
muss bereits installiert sein.
Schließen Sie Chrome mit 'driver.quit ()'.
Selbst wenn Sie einen Webdienst analysieren und weltweit veröffentlichen, wird er häufig aufgrund von Änderungen in den Dienstspezifikationen unbrauchbar. Dieses Mal wollte ich nicht die "aktuellen Spezifikationen" teilen, sondern "Ist es nicht möglich, die Spezifikationen auf diese Weise zu analysieren?". Also wurde dieser Artikel so geschrieben. Wie ich am Anfang sagte, teile ich es, ohne etwas zu wissen. Wenn Sie denken "ist es hier seltsam?", Weisen Sie bitte darauf hin.
Recommended Posts