可以生成外链播放器
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=298 height=52 src="//music.163.com/outchain/player?type=2&id=151646&auto=0&height=32"></iframe>
需要保存的项有:
m_name :歌名
m_singer:歌手
vote 评论数
url : 链接
播放功能
通过相似歌曲查找其它歌,
歌名
//*[@id="auto-id-xRQFDgyFzdwbznWT"]/div[3]/div[1]/div/div/div[1]/div[1]/div[2]/div[1]/div/em
//*[@id="auto-id-sQbhxsxtnM7vJTti"]/div[3]/div[1]/div/div/div[1]/div[1]/div[2]/div[1]/div/em
//*[@id="auto-id-koka4uE8EU8gmROm"]/div[3]/div[1]/div/div/div[1]/div[1]/div[2]/div[1]/div/em
/song?id=29431270
相似歌曲是相对路径:
豆瓣查看网页源代码有xpath,但是云音乐没有
爬取的是框架外的代码。
不是iframe里面的代码
https://stackoverflow.com/questions/24301376/can-scrapy-scrape-contents-of-iframe-using-scrapy-alone
<iframe name="contentFrame" id="g_iframe" class="g-iframe" scrolling="auto" frameborder="0" src="about:blank"></iframe>
注意有2个iframe
先下载网页源代码,注意不是框架源代码。
分析:
js
selenium和 phantomjs
iframe content is not returned as a part of html.
The problem is that iframe content is not returned as a part of html. You can either try to fetch iframe content directly (by its src), or use render.json endpoint with iframes=1 option:
import parsel
# ... yield SplashRequest(url, self.parse_result, endpoint='render.json', args={'html': 1, 'iframes': 1}) def parse_result(self, response): iframe_html = response.data['childFrames'][0]['html'] sel = parsel.Selector(iframe_html) item = { 'my_field': sel.xpath(...), # ... }
/execute endpoint doesn't support fetching iframes content as of Splash 2.3.3.
note that xpath shouldn't include anything outside iframe - process iframe content as a separate document
Also, you may need to take a different iframe; I wrote ['childFrames'][0] as an example - index could be different.
If the web page has mutiple iframes, and iframe you're interested in is not the first, you'll have to use an appropriate index instead of 0
注意
title=[u'u6545u4e61u7684u539fu98ceu666f']是一个元组,
列表用[ ]标识。
如果想要打印出来,需要加index
logging.info("title=%s" % sel.xpath('//div[@class="tit"]/em/text()').extract()[0])
找歌手
//div[@class="cnt"]/p[1]/span/@title
p1表示是div下面的第一个p元素,注意序号是从1开始的,
而且选取属性用@title,不是@title/text()
现在抓取了其ifame里面的页面,但是里面的评论数没有!
<i><span id="cnt_comment_count">评论</span></i>
正常应该是
<i>(<span id="cnt_comment_count">14115</span>)</i>
评论框也没有
<div class="n-cmt" id="comment-box" data-tid="R_SO_4_393705" data-count="0"></div>
这个链接是
附:
爬评论分析过程
chrome network 选择xhr过滤下,
Initiator 标记请求是由哪个对象或进程发起的
如果看不到initiator,点击关闭
这个请求是一个post,有两个参数,params和encSecKey
那么这两个参数是怎么获得的呢?
从initiator一栏里可以看到这个请求的“发起人”是core.js
一般这样的js都是没法看的,下载下来美化过后发现有两万多行,但是没关系,我们需要的只是部分数据。
在这个js文件中搜索params和encSecKey
那么问题就变成得到这个bua
它是由window.asrsea这个函数得到的,可以看到有4个参数,如果研究每个参数肯定是痛苦的,也没有必要,可以先把它们输出来看一下,这时候就需要线上调试js,我选择了Fiddler,在Fiddler的AutoResponder页添加Rule,大概长这样
之后网页加载使用的core.js文件就是我们本地的这个js文件了,而我们可以修改本地的这个文件来获得想要的数据
如果有多个输出,就在页面的Headers中找到encSecKey的值,与控制台输出的对比下,就可以找到真正j50的输出了。
就是下面这条了!
发现rid就是R_SO_4_加上歌曲的id
offset就是(评论页数-1) * 20
按这样的方式可以得到其余三个参数
如 第二个参数:
010001
第三个参数:
00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7
第四个参数:
0CoJUm6Qyw8W8jud
现在我们只要知道函数window.asrsea如何处理的就可以了
定位到这个函数发现它其实是一个叫d的函数
这里的i研究之后你会发现就是一个长度为16的随机字符串,既然是随机的,我就直接让他等于16个F了
这个encText明显就是params,encSecKey明显就是encSecKey
而b函数就是一个AES加密,经过了两次加密,
第一次对d也就是那个json加密,key是第四个参数,第二次对第一次加密结果进行加密,key是i。在b函数中我们可以看到
密钥偏移量iv是0102030405060708,模式是CBC,那么就不难写出对于这个json的加密了。
接下来是第二个参数encSecKey,
c (i, e,f)
这里传入c的三个参数i是16个F,e是第二个参数,f是第三个参数(值见上),全部是固定的值
那么无论歌曲id或评论页数如何变化,这个encSecKey都不随之发生变化
encSecKey:
3de07243e358cf9b6d5398c72774adcb086446650b4dd385df00a5331ae8358448d051fbe8efe36bb8f4eb22f61fd13e4db484b3fa516c81fd8c1e64058a0838b866f4e6adb449a7acb918dd02e63e795e48e99cb4c9edc57a0a7d79fa480a8d71cf679fe16ccd4e2472425f300c91ebff15e61407891b867da1d3cc8842e8ce
至此,我们得到了所有的两个参数。
No module named Crypto.Cipher
sudo pip uninstall crypto
sudo pip uninstall pycrypto
sudo pip install pycrypto
算法先通过createSecretKey生成一个16位的随机字符串作为密钥secKey,然后将明文text进行两次AES加密获得密文encText,因为secKey是在客户端上生成的,所以还需要对其进行RSA加密再传给服务端。
url=http://music.163.com/#/song?id=393705
real_url=http://172.17.0.3:8050/render.json