本文原創發佈於微信公衆號「極客猴」,歡迎關注第一時間獲取更多原創分享javascript
(一)java
故事的小黃花python
從出生那年就飄着git
童年的盪鞦韆github
隨記憶一直晃到如今web
Re So So Si Do Si Lajson
So La Si Si Si Si La Si La Soapi
吹着前奏望着天空瀏覽器
我想起花瓣試着掉落服務器
……
小編猴哥有個愛好,喜歡一邊聽着熟悉的旋律,一邊看着網易雲音樂歌曲中的評論,特別是精彩評論。
評論內容,讓人泫然流涕的故事,就是讓人深思的段子。
(二)
某天,猴哥突發奇想,想將本身平時喜歡聽的歌曲的精彩評論爬取下來。之後就能夠直接閱讀這些評論,無須打開網頁。
說幹就幹。猴哥打開瀏覽器訪問網易雲音樂,隨便點擊某個歌曲頁面。如今大多數網站都採用 Ajax 技術來獲取數據。因此須要先判斷網頁是否採用該技術。
有個谷歌瀏覽器插件名爲 Toggle JavaScript,它能控制頁面中 javascript 啓用或者禁用。
正常的頁面長這樣:
當禁用頁面 JavaScript 腳本以後,正常顯示數據頁面會變成一個空白頁面。
所以,能夠判定網易雲音樂加載數據方式採用 Ajax。
Ajax 技術能夠在不刷新頁面的狀況下,利用嵌在 HTML 文檔中的 JavaScript 腳本向服務器請求數據,而後更新到頁面。想進一步確認數據來源,須要知道請求域名以及請求參數。
這就須要藉助瀏覽器的開發者工具(通常按 F12 鍵會顯示),根據抓取數據包進行分析。由於咱們已經肯定網站採用 Ajax ,因此直接在選擇 XHR 過濾器過濾出全部請求。
而後依次對每一個 url 連接的 HTTP 請求進行分析,着重觀察 Headers,Preview 選項。最後,猴哥發現 R_SO_4_186001?csrf_token= 請求中有咱們須要的信息。Preview 中有字段跟精彩評論中用戶名一致。
繼續切換到 Headers 確認請求域名以及請求須要攜帶的參數。
那麼爬取思路是:使用 POST 方式攜帶參數 params 和 encSecKey 向該地址 music.163.com/weapi/v1/re… 發起HTTP 請求。返回結果中的 Json 數據就是用戶評論數據。
(三) 既然思路明確,編寫代碼就是容易多了。
這裏,猴哥使用列表來保存想爬取精彩評論的歌曲。
songs_url_list = [
'http://music.163.com/#/song?id=186016', # 晴天
'http://music.163.com/#/song?id=186001', # 七里香
'http://music.163.com/#/song?id=27876900', # Here We Are Again 《喜劇之王》電影插曲
'http://music.163.com/#/song?id=439915614', # 恰好碰見你
'http://music.163.com/#/song?id=139774', # The truth that you leave
'http://music.163.com/#/song?id=29567189', # 理想
'http://music.163.com/#/song?id=308353', # 鍾無豔
'http://music.163.com/#/song?id=31445772', # 理想三旬
'http://music.163.com/#/song?id=439915614', # 恰好碰見你
'http://music.163.com/#/song?id=28815250', # 平凡之路
'http://music.163.com/#/song?id=25706282', # 夜空中最亮的星
'http://music.163.com/#/song?id=436514312', # 成都
]
複製代碼
而後截取每一個連接中 id 字段的值。
def get_song_id(url):
""" 從 url 中截取歌曲的 id """
song_id = url.split('=')[1]
return song_id
複製代碼
接着根據 id 拼接處請求的 url 地址,再使用 requests 發起 HTTP 請求。
for each in songs_url_list:
start_spider(get_song_id(each))
time.sleep(random.randint(5, 8))
def start_spider(song_id):
""" 評論數據採用 AJAX 技術得到, 下面纔是獲取評論的請求地址 """
url = 'http://music.163.com/weapi/v1/resource/comments/R_SO_4_{}?csrf_token='.format(song_id)
headers = {
'User-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36',
'Origin': 'http://music.163.com',
'Referer': 'http://music.163.com/song?id={}'.format(song_id),
}
formdata = {
'params': '57Wh2mgebLOOPQVBc+B2wz4sCCH/nXZFEoTc/XNySiqT0V7ZxUADzDNgTXXhYgAJ5BNMryMgxhdwNzF1GyxDZo3iR9/YYbWgCAQHC5DCDuObqvxNcOcnQDaRqJCrqQcrEABW1SwKitfbD3wMEyB4tJu+rU8goSwg2FP/PBBLs9DVs1iWdWGjV6CdrocA36Rs',
'encSecKey': '63774137ba4f5cc60d1b6a3bc14985a9563a7bfdec4f3e74297ffc07514adf18f90620933a01c2db4ca989cc4e1dfc49789981424c294a34e48c2cbe7aa51533a5cc5b5776a9e499cd08770bc596655dbe8e001d1ed5fd47a27dd195128480820cc67a799d341f95d447e3522851f2b64ad1cb8350e2015b265b9e684179351c',
}
response = requests.post(url, headers=headers, data=formdata)
print('請求 [ ' + url + ' ], 狀態碼爲 ')
print(response.status_code)
# get_hot_comments(response.text)
# 將數據寫到 CSV 文件中
write_to_file(get_hot_comments(response.text))
複製代碼
由於請求返回結果是 Json 數據,咱們只須要精彩評論(HotComments)內容,因此須要對數據進行處理下。
def get_hot_comments(response):
""" 獲取精彩評論 請求返回結果是 Json 數據格式, 使用 json.loads(response) 將其轉化爲字典類型, 就能夠使用 key-value 形式獲取值 """
data_list = []
data = {}
for comment in json.loads(response)['hotComments']:
data['userId'] = comment['user']['userId']
data['nickname'] = comment['user']['nickname']
data['content'] = comment['content']
data['likedCount'] = comment['likedCount']
data_list.append(data)
data = {}
# print(data_list)
return data_list
複製代碼
最後將數據保存到 CSV 文件中。
def write_to_file(datalist):
print('開始將數據持久化……')
file_name = '網易雲音樂精彩評論.csv'
with codecs.open(file_name, 'a+', 'GBK') as csvfile:
filednames = ['用戶Id', '暱稱', '評論內容', '點贊數']
writer = csv.DictWriter(csvfile, fieldnames=filednames)
writer.writeheader()
for data in datalist:
print(data)
try:
writer.writerow({filednames[0]: data['userId'],
filednames[1]: data['nickname'],
filednames[2]: data['content'],
filednames[3]: data['likedCount']})
except UnicodeEncodeError:
print("編碼錯誤, 該數據沒法寫到文件中, 直接忽略該數據")
複製代碼
寫到這裏,小夥伴們應該瞭解如何爬取運用 Ajax 技術加載數據的網站了。可能某些網站的請求攜帶的參數只能使用一次,那就進一步數據包中 js 代碼。推斷出加密方式,本身再用代碼還原。
哈哈,這裏請容許我貼下爬取結果。
附: 程序源碼 Github 倉庫地址:163MusicCrawler
本文首發於微信公衆號,原文地址是 爬取網易雲音樂精彩評論。隨時歡迎轉載文章, 轉載請聯繫號主開通白名單,尊重做者的原創。本人微信公衆號「極客猴」,每週分享 Python 原創乾貨。涉及網絡爬蟲、數據分析、web 開發等方向。