首页 > 解决方案 > Python selenium 获取由 javascript 添加的网页内容

问题描述

我使用一个名为“网易云音乐”的在线音乐播放器,我的帐户中有多个播放列表,它们包含数千个曲目,并且组织和分类非常差,并且存在重复条目,所以我想将它们导出到 SQL 表中组织他们。

我找到了一种不使用客户端软件查看播放列表的方法,即单击播放列表页面顶部的共享按钮,然后单击“复制链接”。

但是在客户端以外的任何浏览器中打开链接,播放列表将被限制为 1000 首曲目。

但是我找到了克服它的方法,我安装了Tampermonkey,然后安装了这个脚本

现在我可以在浏览器中查看完整的播放列表。

这是一个示例播放列表

播放列表如下所示:

在此处输入图像描述

第一列包含歌曲标题,第二列包含持续时间,第三列包含艺术家,最后一列包含专辑。

第一、三、四栏的文字分别是歌曲页面、艺术家页面和专辑页面的超链接。

我对html一无所知,但我设法获得了它的数据结构。

我们需要的是位于 xpath 的表//table/tbody,每一行都是名为 tr(xpath //table/tbody/tr) 的表的子节点。

这是一个示例行:

<td class="left">
    <div class="hd "><span data-res-id="5221710" data-res-type="18" data-res-action="play" data-res-from="13" data-res-data="158624364" class="ply ">&nbsp;</span><span class="num">1</span></div>
</td>
<td>
    <div class="f-cb">
        <div class="tt">
            <div class="ttc">
                <span class="txt">
                    <a href="#/song?id=5221710"><b title="Axel F">Axel F</b></a>
                    
                    
                </span>
            </div>
        </div>
    </div>
</td>
<td class=" s-fc3">
    <span class="u-dur candel">03:00</span>
    <div class="opt hshow">
        <a class="u-icn u-icn-81 icn-add" href="javascript:;" title="添加到播放列表&quot; hidefocus="true" data-res-type="18" data-res-id="5221710" data-res-action="addto" data-res-from="13" data-res-data="158624364"></a>
        <span data-res-id="5221710" data-res-type="18" data-res-action="fav" class="icn icn-fav" title="收藏"></span>
        <span data-res-id="5221710" data-res-type="18" data-res-action="share" data-res-name="Greatest Hits Of The Millennium 80's Vol.2" data-res-author="Harold Faltermeyer" data-res-pic="https://p2.music.126.net/tOa6Tizqy755OZE7ITsw_g==/775155697626111.jpg" class="icn icn-share" title="分享">分享</span>
        <span data-res-id="5221710" data-res-type="18" data-res-action="download" class="icn icn-dl" title="下载"></span>
        <span data-res-id="5221710" data-res-type="18" data-res-from="13" data-res-data="158624364" data-res-action="delete" class="icn icn-del" title="删除">删除</span>
    </div>
</td>
<td>
    <div class="text" title="Harold Faltermeyer">
        <span title="Harold Faltermeyer">
            <a href="#/artist?id=34854" hidefocus="true">Harold Faltermeyer</a>
        </span>
    </div>
</td>
<td>
    <div class="text">
        <a href="#/album?id=509819" title="Greatest Hits Of The Millennium 80's Vol.2">Greatest Hits Of The Millennium 80's Vol.2</a>
    </div>
</td>

列是元素的子节点。

我设法获得了与列对应的 xpath:

/td[2]/div/div/div/span/a/b -->  title
/td[2]/div/div/div/span/a -->  song link
/td[3]/span -->  duration
/td[4]/div/span/a -->  artist
/td[4]/div/span/a['href'] -->  artist link
/td[5]/div/a -->  album
/td[5]/div/a['href'] -->  album link

我们应该music.163.com/在链接前面添加地址以获得完整地址。

我正在考虑使用 selenium 来获取元素,更具体地说是通过 xpath 查找行,然后遍历行并通过行内的 xpath 获取列,然后将值添加到命名元组列表中。

从这里将元素添加到 SQL 表是微不足道的。

但我就是无法让它工作。

我设法打开一个 Firefox selenium 窗口,安装 tampermonkey 和脚本以访问完整的播放列表(这两个安装是手动完成的),然后进入播放列表页面并尝试获取元素:

from selenium import webdriver
Firefox = webdriver.Firefox()
Firefox.get('https://music.163.com/#/playlist?id=158624364&userid=126762751')
Firefox.find_elements_by_xpath('//table/tbody/tr')

结果是一个空列表。

不知道是哪里出了问题,我在开发者工具中查看表格元素就好了,后来我查看了它的源代码,发现表格不在它的源代码中。

我什至设法使用开发人员工具获得了完整的表格,并在此处上传了它。

但它对硒是不可见的。显然,浏览器有办法显示不在原始 html 源代码中的内容,而 selenium 不能。这时候我才意识到浏览器可以执行javascript,而原始源代码中没有的附加内容可能是由某个地方的javascript添加的,而我使用的代码不涉及javascript,只能获取原始源代码而没有附加内容。

我试过谷歌搜索python selenium 获取由 javascript 添加的网页的内容,但它没有帮助。

所以我有两个问题,第一,短期内,如何使用一些html解析库来解析本地存储在txt文件中的一段html代码?

其次,从长远来看,我如何使用 selenium 或任何其他 Python html 库来获取带有 javascript 添加的附加内容的网页的完整源代码,而不是只有原始源代码而没有附加内容,所以我不'每次都需要手动导出元素吗?

标签: pythonhtmlpython-3.xseleniumiframe

解决方案


最简单的答案是,您必须在打开页面后添加一些延迟,Firefox.get('https://music.163.com/#/playlist?id=158624364&userid=126762751')然后再获取元素以Firefox.find_elements_by_xpath('//table/tbody/tr')加载页面上的元素。这需要一些时间。
所以,你可以简单地在那里添加一种time.sleep(5)
更好的方法是使用预期条件。
像这样的东西:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
Firefox = webdriver.Firefox()

# Wait for initialize, in seconds
wait = WebDriverWait(Firefox, 20)

Firefox.get('https://music.163.com/#/playlist?id=158624364&userid=126762751')

wait.until(EC.visibility_of_element_located((By.XPATH, '//table/tbody/tr')))

Firefox.find_elements_by_xpath('//table/tbody/tr')

UPD
那里有一个 iframe,因此您需要切换到该 iframe,如下所示:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
Firefox = webdriver.Firefox()

# Wait for initialize, in seconds
wait = WebDriverWait(Firefox, 20)

Firefox.get('https://music.163.com/#/playlist?id=158624364&userid=126762751')

iframe = driver.find_element_by_xpath('//iframe[@id="g_iframe"]')
driver.switch_to.frame(iframe)

wait.until(EC.visibility_of_element_located((By.XPATH, '//table/tbody/tr')))

Firefox.find_elements_by_xpath('//table/tbody/tr')

推荐阅读