泉源:lyrichu
www.cnblogs.com/lyrichu/p/6635798.html
如有好文章投稿,请点击→这里相识详情
近来在研究文本发掘相干的内容,所谓巧妇难为无米之炊,要想举行文天职析,起首得到有文本吧。获取文本的方式有很多,比如从网上下载现成的文本文档,大概通过第三方提供的API举行获取数据。但是有的时间我们想要的数据并不能直接获取,由于并不提供直接的下载渠道大概API供我们获取数据。那么这个时间该怎么办呢?有一种比力好的办法是通过网络爬虫,即编写盘算机程序伪装成用户去得到想要的数据。利用盘算机的高效,我们可以轻松快速地获取数据。
那么该怎样写一个爬虫呢?有很多种语言都可以写爬虫,比如Java,php,python等,我个人比力喜好利用python。由于python不但有着内置的功能强大的网络库,尚有诸多良好的第三方库,别人直接造好了轮子,我们直接拿过来用就可以了,这为写爬虫带来了极大的方便。不浮夸地说,利用不到10行python代码着实就可以写一个小小的爬虫,而利用其他的语言可以要多写很多代码,简便易懂正是python的巨大的上风。
好了废话不多说,进入本日的正题。近来几年网易云音乐火了起来,我本身就是网易云音乐的用户,用了几年了。从前用的是QQ音乐和酷狗,通过我本身的切身履历来看,我以为网易云音乐最优特色的就是其精准的歌曲保举和独具特色的用户批评(谨慎声明!!!这不是软文,非广告!!!仅代表个人观点,非喜勿喷!)。常常一首歌曲下面会有一些被点赞浩繁的神批评。加上前些日子网易云音乐将精选用户批评搬上了地铁,网易云音乐的批评又火了一把。以是我想对网易云的批评举行分析,发现此中的规律,特别是分析一些热评具有什么共同的特点。带着这个目标,我开始了对网易云批评的抓取工作。
python内置了两个网络库urllib和urllib2,但是这两个库利用起来不是特别方便,以是在这里我们利用一个广受好评的第三方库requests。利用requests只用很少的几行代码就可以实现设置署理,模仿登岸等比力复杂的爬虫工作。假如已经安装pip的话,直接利用pipinstallrequests即可安装。中文文档地点在此https://docs.python-requests.org/zh_CN/latest/user/quickstart.html,各人有什么题目可以自行参考官方文档,上面会有非常具体的先容。至于urllib和urllib2这两个库也是比力有效的,以后假如有机遇我会再给各人先容一下。
在正式开始先容爬虫之前,起首来说一下爬虫的根本工作原理,我们知道我们打开欣赏器访问某个网址本质上是向服务器发送了肯定的哀求,服务器在收到我们的哀求之后,会根据我们的哀求返回数据,然后通过欣赏器将这些数据分析好,出现在我们的面前。假如我们利用代码的话,就要跳过欣赏器的这个步调,直接向服务器发送肯定的数据,然后再取回服务器返回的数据,提取出我们想要的信息。但是题目是,有的时间服务器必要对我们发送的哀求举行校验,假如它以为我们的哀求黑白法的,就会不返回数据,大概返回错误的数据。以是为了克制发生这种环境,我们有的时间必要把程序伪装成一个正常的用户,以便顺遂得到服务器的回应。怎样伪装呢?这就要看用户通过欣赏器访问一个网页与我们通过程序访问一个网页之间的区别。通常来说,我们通过欣赏器访问一个网页,除了发送访问的url之外,还会给服务发送额外的信息,比如headers(头部信息)等,这就相称于是哀求的身份证明,服务器看到了这些数据,就会知道我们是通过正常的欣赏器访问的,就会乖乖地返回数据给我们了。以是我们程序就得像欣赏器一样,在发送哀求的时间,带上这些标记着我们身份的信息,如许就能顺遂拿到数据。有的时间,我们必须在登录状态下才华得到一些数据,以是我们必须要模仿登录。本质上来说,通过欣赏器登录就是post一些表单信息给服务器(包罗用户名,暗码等信息),服务器校验之后我们就可以顺遂登录了,利用程序也是一样,欣赏器post什么数据,我们原样发送就可以了。关于模仿登录,我背面会专门先容一下。固然事变有的时间也不会这么顺遂,由于有些网站设置了反爬步伐,比如假如访问过快,偶然间会被封ip(典范的比如豆瓣)。这个时间我们还得要设置署理服务器,即变动我们的ip地点,假如一个ip被封了,就换别的一个ip,具体怎么做,这些话题以后渐渐再说。
末了,再先容一个我以为在写爬虫过程中非常有效的一个小本领。假如你在利用火狐欣赏器大概chrome的话,大概你会留意到有一个叫作开辟者工具(chrome)大概web控制台(firefox)的地方。这个工具非常有效,由于利用它,我们可以清楚地看到在访问一个网站的过程中,欣赏器到底发送了什么信息,服务器毕竟返回了什么信息,这些信息是我们写爬虫的关键地点。下面你就会看到它的巨大用处。
————————正式开始的分割线——————————
起首打开网易云音乐的网页版,任意选择一首歌曲打开它的网页,这里我以周杰伦的《好天》为例。如下图1
图1
接下来打开web控制台(chrom的话打开开辟者工具,假如是其他欣赏器应该也是雷同),如下图2
图2
然后这个时间我们必要点选网络,打扫全部的信息,然后点击重新发送(相称于是革新欣赏器),如许我们就可以直观看到欣赏器发送了什么信息以及服务器回应了什么信息。如下图3
图3
革新之后得到的数据如下图4所示:
图4
可以看到欣赏器发送了非常多的信息,那么哪一个才是我们想要的呢?这里我们可以通过状态码做一个开端的判定,statuscode(状态码)标记了服务器哀求的状态,这里状态码为200即表现哀求正常,而304则表现不正常(状态码种类非常多,假如要想具体相识可以自行搜刮,这里不说304具体的寄义了)。以是我们一样平常只用看状态码为200的哀求就可以了,尚有就是,我们可以通过右边栏的预览来大抵观察服务器返回了什么信息(大概查察相应)。如下图5所示:
图5
通过这两种方法连合一样平常我们就可以快速找到我们想要分析的哀求。留意图5中的哀求网址一栏便是我们想要哀求的网址,哀求的方法有两种:get和post,尚有一个必要重点关注的就是哀求头,内里包罗了user-Agent(客户端信息),refrence(从那边跳转过来)等多种信息,一样平常无论是get还是post方法我们都会把头部信息带上。头部信息如下图6所示:
图6
别的还必要留意的是:get哀求一样平常就直接把哀求的参数以?parameter1=value1parameter2=value2等如许的情势发送了,以是不必要带上额外的哀求参数,而post哀求则一样平常必要带上额外的参数,而不直接把参数放在url当中,以是有的时间我们还必要关注参数这一栏。颠末细致探求,我们终于找到原来与批评相干的哀求在https://music.163.com/weapi/v1/resource/comments/R_SO_4_186016?csrf_token=这个哀求当中,如下图7所示:
图7
点开这个哀求,我们发现它是一个post哀求,哀求的参数有两个,一个是params,尚有一个是encSecKey,这两个参数的值非常的长,感觉应该像是加密过的。如下图8所示:
图8
服务器返回的和批评相干的数据为json格式的,内里含有非常丰富的信息(比如有关批评者的信息,批评日期,点赞数,批评内容等等),如下图9所示:(着实hotComments为热门批评,comments为批评数组)
图9
至此,我们已经确定了方向了,即只必要确定params和encSecKey这两个参数值即可,这个题目困扰了我一下战书,我弄了好久也没有搞清楚这两个参数的加密方式,但是我发现了一个规律,https://music.163.com/weapi/v1/resource/comments/R_SO_4_186016?csrf_token=中R_SO_4_背面的数字就是这首歌的id值,而对于差别的歌曲的param和encSecKey值,假如把一首歌比如A的这两个参数值传给B这首歌,那么对于雷同的页数,这种参数是通用的,即A的第一页的两个参数值传给其他任何一首歌的两个参数,都可以得到相应歌曲的第一页的批评,对于第二页,第三页等也是雷同。但是遗憾的是,差别的页数参数是差别的,这种办法只能抓取有限的几页(固然抓取批评总数和热门批评已经充足了),假如要想抓取全部数据,就必须搞明白这两个参数值的加密方式。以为没有搞明白,昨天晚上我带着这个题目去知乎搜刮了一下,居然真的被我找到了答案。在这个题目https://www.zhihu.com/question/36081767下,@平胸小仙女这位知友具体阐明白怎样破解这两个参数的加密过程,我研究了一下,发现还是有点小复杂的,按照他写的方法,我改动了一下,就乐成得到了全部的批评。这里要对@平胸小仙女(个人主页https://www.zhihu.com/people/luocaodan/answers)表现感谢。假如各人对于破解参数加密有爱好的话,可以去直接参考原帖,地点是:https://www.zhihu.com/question/36081767。
到此为止,怎样抓取网易云音乐的批评全部数据就全部讲完了。按照惯例,末了上代码,亲测有效:
#!/usr/bin/envpython2.7
#-*-coding:utf-8-*-
#ahref="https://www.jobbole.com/members/dai745726163"@Time/a:2017/3/288:46
#@Author:Lyrichu
#ahref="https://www.jobbole.com/members/Email"@Email/a:919987476@qq.com
#@File:NetCloud_spider3.py
'''
@Deion:
网易云音乐批评爬虫,可以完备爬取整个批评
部分参考了@平胸小仙女的文章(地点:https://www.zhihu.com/question/36081767)
post加密部分也给出了,可以参考原帖:
作者:平胸小仙女
链接:https://www.zhihu.com/question/36081767/answer/140287795
泉源:知乎
'''
fromCrypto.CipherimportAES
import
importrequests
importjson
importcodecs
importtime
#头部信息
headers={
'Host':"music.163.com",
'Accept-Language':"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
'Accept-Encoding':"gzip,deflate",
'Content-Type':"application/x-www-form-urlencoded",
'Cookie':"_ntes_nnid=754361b04b121e078dee797cdb30e0fd,1486026808627;_ntes_nuid=754361b04b121e078dee797cdb30e0fd;JSESSIONID-WYYY=yfqt9ofhY%5CIYNkXW71TqY5OtSZyjE%2FoswGgtl4dMv3Oa7%5CQ50T%2FVaee%2FMSsCifHE0TGtRMYhSPpr20i%5CRO%2BO%2B9pbbJnrUvGzkibhNqw3Tlgn%5Coil%2FrW7zFZZWSA3K9gD77MPSVH6fnv5hIT8ms70MNB3CxK5r3ecj3tFMlWFbFOZmGw%5C%3A1490677541180;_iuqxldmzr_=32;vjuids=c8ca7976.15a029d006a.0.51373751e63af8;vjlast=1486102528.1490172479.21;__gads=ID=a9eed5e3cae4d252:T=1486102537:S=ALNI_Mb5XX2vlkjsiU5cIy91-ToUDoFxIw;vinfo_n_f_l_n3=411a2def7f75a62e.1.1.1486349441669.1486349607905.1490173828142;P_INFO=m15527594439@163.com|1489375076|1|study|0099|nullnullnull#hub420100#10#0#0|1554391|study_client|15527594439@163.com;NTES_CMT_USER_INFO=84794134%7Cm155****4439%7Chttps%3A%2F%2Fsimg.ws.126.net%2Fe%2Fimg5.cache.netease.com%2Ftie%2Fimages%2Fyun%2Fphoto_default_62.png.39x39.100.jpg%7Cfalse%7CbTE1NTI3NTk0NDM5QDE2My5jb20%3D;usertrack=c+5+hljHgU0T1FDmA66MAg==;Province=027;City=027;_ga=GA1.2.1549851014.1489469781;__utma=94650624.1549851014.1489469781.1490664577.1490672820.8;__utmc=94650624;__utmz=94650624.1490661822.6.2.utmcsr=baidu|utmccn=(organic)|utmcmd=organic;playerid=81568911;__utmb=94650624.23.10.1490672820",
'Connection':"keep-alive",
'Referer':'https://music.163.com/'
}
#设置署理服务器
proxies={
'http:':'https://121.232.146.184',
'https:':'https://144.255.48.197'
}
#offset的取值为:(批评页数-1)*20,total第一页为true,别的页为false
#first_param='{rid:"",offset:"0",total:"true",limit:"20",csrf_token:""}'#第一个参数
second_param="010001"#第二个参数
#第三个参数
third_param="00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
#第四个参数
forth_param="0CoJUm6Qyw8W8jud"
#获取参数
defget_params(page):#page为传入页数
iv="0102030405060708"
first_key=forth_param
second_key=16*'F'
if(page==1):#假如为第一页
first_param='{rid:"",offset:"0",total:"true",limit:"20",csrf_token:""}'
h_encText=AES_encrypt(first_param,first_key,iv)
else:
offset=str((page-1)*20)
first_param='{rid:"",offset:"%s",total:"%s",limit:"20",csrf_token:""}'%(offset,'false')
h_encText=AES_encrypt(first_param,first_key,iv)
h_encText=AES_encrypt(h_encText,second_key,iv)
returnh_encText
#获取encSecKey
defget_encSecKey():
encSecKey="257348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831f6394d5a3fd2e3881736d94a02ca919d952872e7d0a50ebfa1769a7a62d512f5f1ca21aec60bc3819a9c3ffca5eca9a0dba6d6f7249b06f5965ecfff3695b54e1c28f3f624750ed39e7de08fc8493242e26dbc4484a01c76f739e135637c"
returnencSecKey
#解密过程
defAES_encrypt(text,key,iv):
pad=16-len(text)%16
text=text+pad*chr(pad)
encryptor=AES.new(key,AES.MODE_CBC,iv)
encrypt_text=encryptor.encrypt(text)
encrypt_text=.b64encode(encrypt_text)
returnencrypt_text
#得到批评json数据
defget_json(url,params,encSecKey):
data={
"params":params,
"encSecKey":encSecKey
}
response=requests.post(url,headers=headers,data=data,proxies=proxies)
returnresponse.content
#抓取热门批评,返回热评列表
defget_hot_comments(url):
hot_comments_list=[]
hot_comments_list.append(u"用户ID用户昵称用户头像地点批评时间点赞总数批评内容n")
params=get_params(1)#第一页
encSecKey=get_encSecKey()
json_text=get_json(url,params,encSecKey)
json_dict=json.loads(json_text)
hot_comments=json_dict['hotComments']#热门批评
print("共有%d条热门批评!"%len(hot_comments))
foriteminhot_comments:
comment=item['content']#批评内容
likedCount=item['likedCount']#点赞总数
comment_time=item['time']#批评时间(时间戳)
userID=item['user']['userID']#批评者id
nickname=item['user']['nickname']#昵称
avatarUrl=item['user']['avatarUrl']#头像地点
comment_info=userID+""+nickname+""+avatarUrl+""+comment_time+""+likedCount+""+comment+u"n"
hot_comments_list.append(comment_info)
returnhot_comments_list
#抓取某一首歌的全部批评
defget_all_comments(url):
all_comments_list=[]#存放全部批评
all_comments_list.append(u"用户ID用户昵称用户头像地点批评时间点赞总数批评内容n")#头部信息
params=get_params(1)
encSecKey=get_encSecKey()
json_text=get_json(url,params,encSecKey)
json_dict=json.loads(json_text)
comments_num=int(json_dict['total'])
if(comments_num%20==0):
page=comments_num/20
else:
page=int(comments_num/20)+1
print("共有%d页批评!"%page)
foriinrange(page):#逐页抓取
params=get_params(i+1)
encSecKey=get_encSecKey()
json_text=get_json(url,params,encSecKey)
json_dict=json.loads(json_text)
ifi==0:
print("共有%d条批评!"%comments_num)#全部批评总数
foriteminjson_dict['comments']:
comment=item['content']#批评内容
likedCount=item['likedCount']#点赞总数
comment_time=item['time']#批评时间(时间戳)
userID=item['user']['userId']#批评者id
nickname=item['user']['nickname']#昵称
avatarUrl=item['user']['avatarUrl']#头像地点
comment_info=unicode(userID)+u""+nickname+u""+avatarUrl+u""+unicode(comment_time)+u""+unicode(likedCount)+u""+comment+u"n"
all_comments_list.append(comment_info)
print("第%d页抓取完毕!"%(i+1))
returnall_comments_list
#将批评写入文本文件
defsave_to_file(list,filename):
withcodecs.open(filename,'a',encoding='utf-8')asf:
f.writelines(list)
print("写入文件乐成!")
if__name__=="__main__":
start_time=time.time()#开始时间
url="https://music.163.com/weapi/v1/resource/comments/R_SO_4_186016/?csrf_token="
filename=u"好天.txt"
all_comments_list=get_all_comments(url)
save_to_file(all_comments_list,filename)
end_time=time.time()#竣事时间
print("程序耗时%f秒."%(end_time-start_time))
我利用上述代码跑了一下,抓了两首周杰伦的热门歌曲《好天》(有130多万批评)和《告白气球》(有20多万批评),前者跑了大概有20多分钟,后者有6600多秒(也就是将近2个小时),截图如下:
留意我是按照空格来分隔的,每一行分别有效户ID用户昵称用户头像地点批评时间点赞总数批评内容这些内容。我将这两个txt文件上传到百度云了,对数据感爱好的同砚可以直接下载举行文天职析,地点为:《好天》(https://pan.baidu.com/s/1boBglfp),《告白气球》(https://pan.baidu.com/s/1o8O7k1s),大概本身跑一下代码抓取一下也是可以的(留意不要开太多线程给网易云的服务器太大压力哦~~中心有一段时间服务器返回数据特别慢,不知道是不是限定访问了,厥后又好了)。我背面大概会本身去对批评数据举行可视化分析,敬请等待!
看完本文有劳绩?请转发分享给更多人
关注「Python开辟者」,提拔Python技能
我要评论