この記事では、Python が NetEase Cloud Music で人気のあるコメントを取得する例を詳しく紹介します。とても良い参考値です
最近、テキストマイニング関連のコンテンツを勉強しています。 テキストを実行したい場合、賢い女性はご飯を作ることができないと言われています。分析するには、まずテキストが必要です。テキストを取得するには、インターネットから既製のテキスト文書をダウンロードしたり、サードパーティが提供する API を介してデータを取得したりするなど、さまざまな方法があります。しかし、データを取得するための直接ダウンロード チャネルや API がないため、必要なデータを直接取得できない場合があります。では、このとき何をすべきでしょうか?より良い方法は、Web クローラーを使用することです。これは、ユーザーになりすまして必要なデータを取得するコンピューター プログラムを作成することです。コンピュータの効率を活かして、簡単かつ迅速にデータを取得することができます。
では、クローラはどうやって書くのでしょうか? Java、php、Python など、クローラーの作成に使用できる言語は多数ありますが、私は個人的には Python を使用することを好みます。 Python には強力なネットワーク ライブラリが組み込まれているだけでなく、多くの優れたサードパーティ ライブラリがホイールを直接構築しているため、それを使用するだけでクローラーを作成できます。他の言語を使用するにはさらに多くのコードを記述する必要があるのに対し、実際には 10 行未満の Python コードを使用して小さなクローラーを作成できると言っても過言ではありません。簡潔で理解しやすいことは、Python の大きな利点です。
さて、早速、今日の本題に入りましょう。 NetEase Cloud Music は近年非常に人気があり、私は NetEase Cloud Music を数年間使用しています。私は以前 QQ Music と Kugou を使用していましたが、NetEase Cloud Music の最も優れた機能は、正確な曲の推奨と独自のユーザー レビューです (念のために言っておきますが、これはソフトな記事ではありません)。宣伝ですので、コメントしないでください!多くの「いいね!」を獲得した曲の下には、いくつかのコメントが表示されることがあります。さらに、NetEase Cloud Musicは数日前に厳選したユーザーレビューを地下鉄に掲載し、NetEase Cloud Musicのレビューが再び人気になりました。したがって、NetEase Cloud のコメントを分析し、パターン、特にいくつかのホットなコメントの共通の特徴を発見したいと考えています。この目的で、NetEase Cloud のコメントをクロールし始めました。
Python には urllib と urllib2 という 2 つの組み込みネットワーク ライブラリがありますが、これら 2 つのライブラリは特に使いやすいわけではないため、ここでは評判の高いサードパーティ ライブラリである request を使用します。リクエストを使用すると、エージェントのセットアップやログインのシミュレーションなど、より複雑なクローラーの作業をわずか数行のコードで実現できます。 pip がすでにインストールされている場合は、pip install リクエストを使用してインストールします。中国語のドキュメントのアドレスは次のとおりです: http://docs.python-requests.org/zh_CN/latest/user/quickstart.html ご質問がある場合は、公式ドキュメントを参照してください。非常に詳細な説明があります。その上。 urllib と urllib2 という 2 つのライブラリも非常に便利なので、今後機会があれば紹介します。
クローラーを正式に紹介する前に、まずクローラーの基本的な動作原理について説明します。ブラウザを開いて特定の URL にアクセスすると、サーバーがリクエストを受信した後、基本的に特定のリクエストがサーバーに送信されます。当社のリクエストはデータを返し、そのデータはブラウザによって解析されて当社に表示されます。コードを使用する場合は、ブラウザのこの手順をスキップし、特定のデータをサーバーに直接送信し、サーバーから返されたデータを取得して必要な情報を抽出する必要があります。しかし、問題は、サーバーが送信したリクエストを検証する必要がある場合、リクエストが不正であると判断した場合、データが返されなかったり、間違ったデータが返されたりすることです。したがって、この状況を回避するには、サーバーからの応答を正常に取得するために、プログラムを通常のユーザーに偽装する必要がある場合があります。どうやって隠蔽するの?これは、ユーザーがブラウザーを介して Web ページにアクセスする場合と、私たちがプログラムを介して Web ページにアクセスする場合の違いによって異なります。一般に、ブラウザを通じてWebページにアクセスすると、アクセスしたURLに加えて、ヘッダー(ヘッダー情報)などの付加情報もサービスに送信します。これは、Webサイトの本人証明書に相当します。リクエストを送信すると、サーバーはこのデータを認識し、通常のブラウザを介してアクセスしていることがわかり、データは素直に返されます。したがって、私たちのプログラムはブラウザのように、リクエストを送信するときに私たちの身元を示す情報を提供し、データをスムーズに取得できるようにする必要があります。場合によっては、データを取得するためにログインする必要があるため、ログインをシミュレートする必要があります。基本的に、ブラウザ経由でログインするということは、何らかのフォーム情報 (ユーザー名、パスワード、その他の情報を含む) をサーバーに送信することを意味し、サーバーがそれを検証した後、アプリケーション プログラムにも同じことが当てはまります。ブラウザ投稿では、そのまま送信します。擬似ログインについては後ほど具体的に紹介します。もちろん、Web サイトによってはクロール対策が講じられているため、アクセスが速すぎると IP アドレスがブロックされる場合があります (通常は Douban)。このとき、プロキシ サーバーを設定する必要もあります。つまり、ある IP がブロックされている場合は、別の IP に変更します。これを行う方法については、後で説明します。
最後に、クローラーを作成するプロセスで非常に役立つと思うちょっとしたトリックを紹介します。 Firefox または Chrome を使用している場合は、開発者ツール (chrome) または Web コンソール (firefox) という場所に気づいたかもしれません。このツールを使用すると、Web サイトにアクセスしたときにブラウザーがどのような情報を送信し、サーバーがどのような情報を返すかが明確にわかるため、この情報がクローラーを作成するための鍵となります。以下で、それがどれほど役立つかを見ていきます。
------------------------------------------------ ----公式スタート分けライン----------------------------------------- - ----------
まず、NetEase Cloud Music の Web バージョンを開き、ランダムに曲を選択して、その Web ページを開きます。ここでは、ジェイ・チョウの「Sunny Day」を例に挙げます。以下の図 1 に示すように
図 1
次に、図 2 に示すように、Web コンソールを開きます (Chrom を使用している場合は、開発者ツールを開きます。他のブラウザの場合も同様であるはずです)。
図 2
次に、この時点で、ネットワークをクリックし、すべての情報をクリアして、[再送信] (ブラウザを更新するのと同じ) をクリックする必要があります。これにより、ブラウザがどのような情報を送信し、サーバーが応答する情報。以下の図 3 に示すように図 3
更新後に取得されたデータを以下の図 4 に示します。図 4
ブラウザが大量のデータを送信していることがわかります。情報がたくさんあるので、どこに行きたいですか?ここでは、ステータス コードによってサーバー リクエストのステータスを示すことができます。ステータス コードは、リクエストが正常であることを意味する 200 と、リクエストが異常であることを意味する 304 です (さまざまな種類があります)。ステータス コードについて詳しく知りたい場合は、自分で検索してください。ここでは 304 の具体的な意味については説明しません。したがって、通常はステータス コード 200 のリクエストのみを確認する必要があります。また、右側の列のプレビューを通じて、サーバーがどのような情報を返すか (または応答を表示するか) を大まかに観察できます。以下の図 5 に示すように:図 5
これら 2 つの方法を組み合わせることで、分析したいリクエストを素早く見つけることができます。図 5 のリクエスト URL 列は、リクエストする URL であることに注意してください。get と post という 2 つのリクエスト メソッドがあります。もう 1 つ注目する必要があるのは、user-Agent (クライアント情報) が含まれるリクエスト ヘッダーです。 )、参照 (どこからジャンプするか) およびその他の情報 通常、get メソッドでも post メソッドでもヘッダー情報を持ってきます。ヘッダー情報を以下の図 6 に示します。
図 6
さらに、get リクエストでは、通常、リクエストのパラメータが直接変更されることに注意してください。パラメータ1=値1&パラメータ2=値2などはこの形式で送信されるため、追加のリクエストパラメータを持ってくる必要はありません。通常、投稿リクエストではパラメータをURLに直接置くのではなく追加のパラメータを持ってくる必要があるため、場合によっては料金も支払う必要があります。パラメータ列に注目してください。注意深く検索した結果、以下の図 7 に示すように、元のコメント関連のリクエストが http://music.163.com/weapi/v1/resource/comments/R_SO_4_186016?csrf_token= で見つかりました。図 7
このリクエストをクリックすると、リクエスト内に 2 つのパラメータがあり、1 つは params で、もう 1 つは encSecKey です。これらの 2 つのパラメータの値は非常に長いです。暗号化されているように感じられるはずです。以下の図 8 に示すように:
図 8
サーバーから返されるコメント関連データは json 形式であり、非常に豊富な情報 (コメント投稿者に関する情報、コメントの日付、コメントの数など) が含まれています。 (実際、hotComments は人気のあるコメントであり、comments はコメントの配列です)
図 9
この時点で、次のようになります。方向を決定します。つまり、params と encSecKey を決定するだけで済みます。私はこの問題に長い間取り組んできましたが、まだこれら 2 つのパラメーターの暗号化方法を理解できません。 http://music.163.com /weapi/v1/resource/comments/R_SO_4_186016?csrf_token= R_SO_4_ の後の数字は、この曲の param 値と encSecKey 値の ID 値です。異なる曲の場合、A などの曲の 2 つのパラメータが次の場合、値が曲 B に渡される場合、同じページ番号では、このパラメータはユニバーサルです。つまり、次の 2 つのパラメータ値が同じ場合、 A の最初のページを他の曲の 2 つのパラメータに渡すと、最初のページのコメントは 2 ページ目、3 ページ目などでも同様です。ただし、残念ながら、ページのパラメーターが異なると、この方法では限られた数のページしかキャプチャできません (もちろん、すべてのデータをキャプチャしたい場合は、コメントの総数をキャプチャするだけで十分です)。これら 2 つのパラメータ値がどのように暗号化されるか。私はそれが理解できないと思ったので、昨夜、この質問でZhihuに行って検索したところ、実際に答えを見つけました。ここまでで、NetEase Cloud Music のコメントのすべてのデータをキャプチャする方法の説明が終わりました。
いつものように、最後にコードをアップロードしましたが、私自身のテストで機能しました: #!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# @Time : 2017/3/28 8:46
# @Author : Lyrichu
# @Email : 919987476@qq.com
# @File : NetCloud_spider3.py
'''
@Description:
网易云音乐评论爬虫,可以完整爬取整个评论
部分参考了@平胸小仙女的文章(地址:https://www.zhihu.com/question/36081767)
post加密部分也给出了,可以参考原帖:
作者:平胸小仙女
链接:https://www.zhihu.com/question/36081767/answer/140287795
来源:知乎
'''
from Crypto.Cipher import AES
import base64
import requests
import json
import codecs
import time
# 头部信息
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|00&99|null&null&null#hub&420100#10#0#0|155439&1|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':'http://music.163.com/'
}
# 设置代理服务器
proxies= {
'http:':'http://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"
# 获取参数
def get_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)
return h_encText
# 获取 encSecKey
def get_encSecKey():
encSecKey = "257348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831f6394d5a3fd2e3881736d94a02ca919d952872e7d0a50ebfa1769a7a62d512f5f1ca21aec60bc3819a9c3ffca5eca9a0dba6d6f7249b06f5965ecfff3695b54e1c28f3f624750ed39e7de08fc8493242e26dbc4484a01c76f739e135637c"
return encSecKey
# 解密过程
def AES_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 = base64.b64encode(encrypt_text)
return encrypt_text
# 获得评论json数据
def get_json(url, params, encSecKey):
data = {
"params": params,
"encSecKey": encSecKey
}
response = requests.post(url, headers=headers, data=data,proxies = proxies)
return response.content
# 抓取热门评论,返回热评列表
def get_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))
for item in hot_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)
return hot_comments_list
# 抓取某一首歌的全部评论
def get_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)
for i in range(page): # 逐页抓取
params = get_params(i+1)
encSecKey = get_encSecKey()
json_text = get_json(url,params,encSecKey)
json_dict = json.loads(json_text)
if i == 0:
print("共有%d条评论!" % comments_num) # 全部评论总数
for item in json_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))
return all_comments_list
# 将评论写入文本文件
def save_to_file(list,filename):
with codecs.open(filename,'a',encoding='utf-8') as f:
f.writelines(list)
print("写入文件成功!")
if __name__ == "__main__":
start_time = time.time() # 开始时间
url = "http://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))
上記のコードを使用して実行し、ジェイ・チョウの人気曲「Sunny Day」(130 万件以上のコメント) の 2 つをキャッチしました。 「告白バルーン」(コメント数 20,000)、前者は約 20 分、後者は 6,600 秒以上 (つまり、ほぼ 2 時間) かかりました。スクリーンショットは次のとおりです。それぞれをスペースで区切っていることに注意してください。1 行には、ユーザー ID、ユーザーのニックネーム、ユーザーのアバター、アドレス、コメント時間、合計いいね数、コンテンツが含まれています。
以上がNetEase Cloud Music で人気のあるコメントをクロールする Python メソッドを共有するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。