我想从 http://www.youtube-mp3.org/ 下载几首歌曲。我正在使用 urllib2 和 BeautifulSoup。
问题是,当我 urllib2 打开插入了我的视频 ID 的网站时,http://www.youtube-mp3.org/?c#v=lV7r8PiuecQ,我得到了该网站,但他们对此很棘手,并且在初始页面加载后使用一些 js ajax 内容加载信息。因此,当我尝试抓取下载链接的 url 时,实际上它并不在页面上,因为它尚未加载。
有人知道我如何在我的 python 脚本中触发这个 js 加载器吗?
这是在加载我想要的内容之前相关的空html。
<div id="link_box" style="display:none">
<div id="link_box_title" style="font-weight:bold; text-decoration:underline">
</div>
<div class="row">
<div id="link_box_bb_code_title" style="font-weight:bold">
</div>
<input type="text" id="BBCodeLink" onclick="sAll(this)" />
</div>
<div class="row">
<div id="link_box_html_code_title" style="font-weight:bold">
</div>
<input type="text" id="HTMLLink" onclick="sAll(this)" />
</div>
<div class="row">
<div id="link_box_direct_code_title" style="font-weight:bold">
</div>
<input type="text" id="DirectLink" onclick="sAll(this)" />
</div>
</div>
<div id="v-ads">
</div>
<div id="dl_link">
</div>
<div id="progress">
</div>
<div id="loader">
<img src="ajax-loader-b.gif" alt="loading.." width="16" height="11" />
</div>
</div>
<div class="clear">
</div>
</div>
API 基于 JSON,因此 html 文件的内容不会为您提供任何有关在哪里查找文件的线索。在探索此类 Web 服务时,一个好主意是打开 Chrome 开发人员工具中的“网络”选项卡,然后查看与页面交互时加载的页面。该练习向我展示了两个特别有趣的网址:
第一个 URL 似乎正在排队文件进行处理,第二个 URL 则用于获取处理作业的状态。
第二个 url 采用 video_id GET 参数,该参数是 youtube 上视频的 id (http://www.youtube.com/watch?v=KMU0tzLwhbE) 并返回解码作业的状态。第二个和第三个似乎与此目的无关,您可以通过测试加载带有或不带有额外参数的 url 来验证。
页面内容为:
info = { "title" : "Developers",
"image" : "http://i4.ytimg.com/vi/KMU0tzLwhbE/default.jpg",
"length" : "3", "status" : "serving", "progress_speed" : "",
"progress" : "", "ads" : "",
"h" : "a0aa17294103c638fa7f5e0606f839d3" };
这恰好是 JSON 数据。其中有趣的一点是“a0aa17294103c638fa7f5e0606f839d3”,它看起来像是 Web 服务用来引用解码后的 mp3 文件的哈希值。另请查看首页上的下载链接:
http://www.youtube-mp3.org/get?video_id=KMU0tzLwhbE&h=a0aa17294103c638fa7f5e0606f839d3
现在我们已经把拼图中所有缺失的部分拼凑在一起了。首先,我们获取 YouTube 视频的 url (http://www.youtube.com/watch?v=iKP7DZmqdbU) 引用它并使用以下 url 将其提供给 api:
然后,稍等片刻,直到解码工作完成:
http://www.youtube-mp3.org/api/itemInfo/?video_id=iKP7DZmqdbU
使用信息 url 中找到的哈希来构建下载 url:
http://www.youtube-mp3.org/get?video_id=iKP7DZmqdbU&h=2e4b61b6ddc8bf83f5a0e4e4ee0635bb
请注意,该网站的网站管理员可能不希望被抓取,并且如果人们开始(在网站管理员眼中)滥用该网站,他们将采取反制措施。例如,它似乎使用引用保护,因此单击本文中的链接将不起作用,您必须复制它们并将它们加载到新的浏览器窗口中。
测试代码:
from re import findall
from time import sleep
from urllib import urlopen, quote
yt_code = 'gijypDkEqUA'
yt_url = 'http://www.youtube.com/watch?v=%s' % yt_code
push_url_fmt = 'http://www.youtube-mp3.org/api/pushItem/?item=%s&xy=trve'
info_url_fmt = 'http://www.youtube-mp3.org/api/itemInfo/?video_id=%s'
download_url_fmt = 'http://www.youtube-mp3.org/get?video_id=%s&h=%s'
push_url = push_url_fmt % quote(yt_url)
data = urlopen(push_url).read()
sleep(10)
info_url = info_url_fmt % yt_code
data = urlopen(info_url).read()
res = findall('"h" : "([^"]*)"', data)
download_url = download_url_fmt % (yt_code, res[0])
print 'Download here:', download_url
您可以使用 selenium 与 js 内容进行交互,然后将其与 BeautifulSoup 结合使用,或者按照您的喜好使用 selenium 完成所有操作。
Selenium 是一个用于浏览器自动化的工具,并且绑定了包括 Python 在内的几种语言。它需要一个正在运行的 Firefox/IE/Chrome 实例,然后让您编写脚本(我建议使用 selenium webdriver 来解决这个简单的问题,而不是整个 selenium 服务器)。
您必须通过 http://www.youtube-mp3.org/client.js 并找出正在传递的确切信息,这可以允许您发布请求,解析响应并从正确的抓取网址下载。