python - 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 "> </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="添加到播放列表" 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 添加的附加内容的网页的完整源代码,而不是只有原始源代码而没有附加内容,所以我不'每次都需要手动导出元素吗?
解决方案
最简单的答案是,您必须在打开页面后添加一些延迟,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')
推荐阅读
- exoplayer - ExoPlayer seekto函数不寻找到指定点而是从0开始
- css - Firefox 不会在 flexbox 内缩放图像
- javascript - div中的进度条
- c# - 键盘上的返回键就像手机的返回键,如何区分它们?
- json - 在使用 reex 解析以下内容时需要帮助
- yii2 - 如何检查登录用户是否在 Yii2 中具有特定角色
- google-maps-api-3 - geojson多个多边形数据的中心和拟合边界
- javascript - 加载资源失败:服务器响应状态为 500 (Internal Server Error) mvc
- opc-ua - 节点 Opcua / QtOpcUa - 方法调用
- javascript - 通过共享键获取与 Google Photos api 共享的相册