繁体   English   中英

Python selenium 获取“开发者工具”→网络→媒体日志

[英]Python selenium get "Developer Tools" →Network→Media logs

我正在尝试以编程方式做一些必然涉及获取“开发人员工具”→网络→媒体日志的事情。

我将不告诉你细节,长话短说,我需要访问数千个这样的页面: https://music.163.com/#/song?id=ID ,其中等号后面的ID是一个数字。

如果打开这样的页面,会有一个播放按钮,该按钮触发一个javascript,加载一个在整个页面中没有被引用的音乐文件,并播放该文件。 (注:听一些歌曲可能需要中文IP,听一些其他歌曲需要VIP账号。)

例如这个页面: https://music.163.com/#/song?id=32477986 ,它应该是这样的:

在此处输入图像描述

如果点击蓝色按钮,则触发 javascript,音乐文件将由 javascript 加载并播放。 此音乐文件不会成为网页中的元素,因此无法通过find_element*方法直接抓取。

但是我找到了一种找到音乐文件地址的方法。

在 Firefox 中,按 F12 调出检查器/“开发者工具”,点击网络,然后点击媒体。 点击蓝色按钮,会出现多个文件名相同的请求,文件名匹配^[0-9a-f]+\.m4a ,域可能不同。

像这样:

在此处输入图像描述

单击任何记录,您将找到它的地址,其中任何一个都可以,如下所示:

在此处输入图像描述

我目前正试图弄清楚如何以编程方式模拟这个过程。

我用谷歌搜索了这个: python selenium 开发人员工具网络选项卡,并没有找到我想要的东西,这正是我的预期。 我发布了链接以显示我的研究工作,以及 Google 如何不理解您正在尝试搜索的内容的含义。

无论如何,我偶然发现了这个: https://www.rkengler.com/how-to-capture-network-traffic-when-scraping-with-selenium-and-python/

并用这些测试:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
capabilities = DesiredCapabilities.CHROME
capabilities["goog:loggingPrefs"] = {'performance': "ALL"}
driver = webdriver.Chrome(desired_capabilities=capabilities)
wait = WebDriverWait(driver, 15)
driver.get('https://music.163.com/#/song?id=32477986')
iframe = driver.find_element_by_xpath('//iframe[@id="g_iframe"]')
driver.switch_to.frame(iframe)
wait.until(EC.visibility_of_element_located((By.XPATH, '//div[2]/div/a[1]')))
play = driver.find_element_by_xpath('//div[2]/div/a[1]')
play.click()
time.sleep(10)
driver.get_log('performance')

它起作用了,但是 output 太宽泛了,我更喜欢使用 Firefox。

然后,我尝试使用 Google 查找所有有效loggingPrefs选项: chrome all "loggingPrefs" options ,不幸的是,但不出所料,我什么也找不到,除了browser:ALLdriver:ALL

而且我找不到任何指定所有可能开关的文档。

但我想也许我找到了一种模式,性能是检查器/开发工具中的一个选项卡,而网络是另一个选项卡。

所以我用'network'替换了两次出现的'performance'并再次运行代码:

InvalidArgumentException: Message: invalid argument: log type 'network' not found
  (Session info: chrome=89.0.4389.90)

这就是我得到的。

无论如何,这是我整理的:

import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = Options()
options.headless = True
path = (os.environ['APPDATA'] + '\Mozilla\Firefox\Profiles\Selenium').replace('\\', '/')
profile = webdriver.FirefoxProfile(path)
profile.set_preference("media.volume_scale", "0.0")

capabilities = DesiredCapabilities.FIREFOX
capabilities["loggingPrefs"] = {'performance': 'ALL'}

Firefox = webdriver.Firefox(firefox_profile=profile, desired_capabilities=capabilities, options=options)
wait = WebDriverWait(Firefox, 15)
Firefox.get('https://music.163.com/#/song?id=32477986')
iframe = Firefox.find_element_by_xpath('//iframe[@id="g_iframe"]')
Firefox.switch_to.frame(iframe)
wait.until(EC.visibility_of_element_located((By.XPATH, '//div[2]/div/a[1]')))
play = Firefox.find_element_by_xpath('//div[2]/div/a[1]')
play.click()
time.sleep(10)
Firefox.get_log('performance')

这就是它失败的原因:

WebDriverException: Message: HTTP method not allowed

我怎么能得到网络→使用 Python selenium 的媒体日志? 我什至无法使日志记录首选项起作用。 我发现的所有东西都在使用“loggingPrefs”键,如您所见,它不起作用。 我似乎隐约记得gecko:loggingPrefs但我无法通过谷歌搜索"gecko:loggingPrefs"找到任何东西。

这条评论: Getting console.log output from Firefox with Selenium提到 driver.get_log('browser') 将不再起作用。 但尚不清楚它是否仅适用于browser或所有日志。

如何获取 Firefox 检查器日志,之后如何将其缩小到网络→媒体选项卡?

如果我没有表现出足够的研究努力,我真的很抱歉,我到底要如何在不使用 Google 的情况下进行在线研究? 而且,您是否从自己使用 Google 的经验中知道,Google 永远不会理解您的搜索词的含义,它只会找到包含关键字的文档,其中关键字随机散布在文档周围,结果甚至不必包含所有关键词!

谷歌真的是一个糟糕的研究工具,我真的没有比谷歌更好的东西了。 因此,如果这还不够研究努力,那么我不知道有什么东西可以算作足够的研究努力。

那么如何使用 Python 3.9.5 selenium 在 Firefox 中获取检查器→网络→媒体日志?


谷歌把我带到了这里,坦率地说,现场搜索引擎甚至比谷歌还要糟糕。 我找不到我正在寻找的答案,这正是我在这里提问的原因。


经过更多研究,我终于找到了一些东西: https://stackoverflow.com/a/65538568/15290516

这个答案让我离目标更近了一步,但我对 javascript 一无所知,并且测试返回:

JavascriptException: Message: Cyclic object value

但它确实指向了正确的方向,解决方案应该涉及.execute_script()来完成工作,但我不知道确切的命令应该是什么,我尝试谷歌搜索: javascript get "devtools" "network" " media" "logs" ,自己看看它返回了什么。


嗯,我设法使用 Chrome 获取性能日志并将其重定向到文本文件,然后将其上传到Google Drive

我在文件中找到了地址(Notepad++ 搜索.m4a ),但我不知道如何以编程方式将结果过滤到与音乐文件相关的请求。

我想,现在我会被 Chrome 和性能日志困住。

但我真的不知道如何过滤请求以仅获取相关请求。 怎么可能呢?

最后我自己完成了,没有任何人的帮助。

诀窍很简单,一旦你知道该怎么做,实现起来并不难。

响应采用 json 格式,因此我们需要json模块。

json 的结构各不相同,但是第一层的key是固定的,总是有3个key: levelmessagetimestamp

我们需要message键,它的值是一个 json object 打包成一个字符串,所以我们需要json.loads来解包。

这些打包的 json 对象的结构变化很大,但在message密钥内部总是有一个message密钥和一个method密钥。

在这里,我们正在尝试抓取接收到的媒体文件地址,长话短说, messagemessagemethod键应该等于'Network.responseReceived'

如果messagemessagemethod key 等于'Network.responseReceived' ,那么总会有messagemessageparamsresponsemimeType key。

该密钥存储资源的文件类型,我将不详述,我知道.mp4代表Motion Picture Expert Group-4并且是一种视频格式,但这里的媒体类型应该是'audio/mp4'

如果满足所有关于条件,则媒体文件的地址是messagemessageparamsresponseurl key 的值。

这是最终代码:

import json
import os
import random
import sys
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

path = (os.environ['LOCALAPPDATA'] + '\\Google\\Chrome\\User Data')

options = webdriver.ChromeOptions()
options.add_argument('--disable-gpu')
options.add_argument('--headless')
options.add_argument('--log-level=3')
options.add_argument('--mute-audio')
options.add_argument(f'--user-data-dir={path}')

capabilities = DesiredCapabilities.CHROME
capabilities["goog:loggingPrefs"] = {'performance': 'ALL'}

Chrome = webdriver.Chrome(options=options, desired_capabilities=capabilities)
wait = WebDriverWait(Chrome, 5)

def getlink(addr):
    Chrome.get(addr)
    iframe = Chrome.find_element_by_xpath('//iframe[@id="g_iframe"]')
    Chrome.switch_to.frame(iframe)
    wait.until(EC.visibility_of_element_located((By.XPATH, '//div[2]/div/a[1]')))
    play = Chrome.find_element_by_xpath('//div[2]/div/a[1]')
    play.click()
    time.sleep(5)
    logs = Chrome.get_log('performance')
    addresses = []
    for i in logs:
        log = json.loads(i['message'])
        if log['message']['method'] == 'Network.responseReceived':
            if log['message']['params']['response']['mimeType'] == 'audio/mp4':
                addresses.append(log['message']['params']['response']['url'])
    check = set([i.split('/')[-1] for i in addresses])
    if len(check) == 1:
        return random.choice(addresses)

if __name__ == '__main__':
    print(getlink(sys.argv[1]))

很棒的代码,当你还期望'audio/mpeg'时,你会得到更好的结果

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM