序言
分析網(wǎng)頁(yè)
分析請(qǐng)求
代碼實(shí)現(xiàn)
瞎比比
好久沒(méi)寫(xiě)原創(chuàng)文章,早就手癢癢了,所以擠出時(shí)間寫(xiě)了這篇,這是下面這五篇文章的連載文章:
聽(tīng)說(shuō)你的爬蟲(chóng)又被封了?(2)
爬取兩萬(wàn)多租房數(shù)據(jù),告訴你廣州房租現(xiàn)狀(4)
那這段時(shí)間我都去干嘛了呢?時(shí)間都用在寫(xiě)小程序(編程面試題庫(kù))了,現(xiàn)在也已經(jīng)寫(xiě)得七七八八了,別看這小程序功能不多。但要做的內(nèi)容倒是挺多的,給它配了個(gè)面試題庫(kù)的爬蟲(chóng)系統(tǒng),后臺(tái)內(nèi)容管理系統(tǒng)。其中用到了很多技術(shù)棧,python、nodejs、flask、koa2(nodejs庫(kù))、前端、小程序、scrapy、docker、mysql、mongodb等等。結(jié)合起來(lái)使用還是挺考驗(yàn)人的,通過(guò)這次使用,又復(fù)習(xí)了一下前端,但依然是個(gè)前端小渣渣。
作為一個(gè)老杰迷,從小學(xué)四年級(jí)就開(kāi)始聽(tīng) jay 的歌。明天就是杰倫的生日了,感覺(jué)再不搞點(diǎn)小動(dòng)作還真是對(duì)不起杰倫了。所以呢,這次寫(xiě)文,是專門(mén)獻(xiàn)給杰倫的。
如果你做的是網(wǎng)頁(yè)爬蟲(chóng),那么首先要做的是:分析這個(gè)網(wǎng)頁(yè)是服務(wù)端渲染還是客戶端渲染,即是判斷該網(wǎng)頁(yè)是同步請(qǐng)求還是異步請(qǐng)求?這個(gè)很簡(jiǎn)單,我很早就介紹過(guò)一個(gè) Chrome 插件,如圖
具體用法請(qǐng)查看我的歷史文章。
使用工具關(guān)閉 JavaScript 請(qǐng)求之后,我們得到的頁(yè)面是這樣的:
打開(kāi)之后是這樣的:
很明顯,這是一個(gè)異步請(qǐng)求。接下來(lái)就是在眾多請(qǐng)求中找到歌詞的請(qǐng)求,如圖:
接下來(lái)沒(méi)啥,就分析這個(gè)請(qǐng)求的參數(shù)。通過(guò)翻頁(yè)之后,我們來(lái)看看兩個(gè)請(qǐng)求之間是參數(shù)對(duì)比。
我們可以看出 p 是頁(yè)碼的意思,w 是關(guān)鍵詞的意思,第一個(gè)紅框和最后一個(gè)紅框是有不同的。經(jīng)過(guò)我的分析,第一個(gè)紅框不改變也沒(méi)關(guān)系,一樣是可以發(fā)送請(qǐng)求。那最后一個(gè)紅框是怎么來(lái)的?這里,我先不講解,因?yàn)檫@與本文的主題不太相關(guān),我會(huì)安排更詳細(xì)的文章告訴你,它究竟是怎么來(lái)的。深層次的原因是,我后面會(huì)有反爬蟲(chóng)系列的文章,這個(gè)內(nèi)容剛好被規(guī)劃在那個(gè)系列里面。但結(jié)論我們可以先用,結(jié)論就是:這些數(shù)字就是一些隨機(jī)數(shù),我們用代碼生成隨機(jī)數(shù)便是。
首先,先訪問(wèn)首頁(yè),拿到 cookie 等信息,以免后面被封掉。
class Spider(scrapy.Spider):
name = 'qq'
allowed_domains = ['qq.com']
start_urls = ['https://y.qq.com/portal/search.html#page=2&searchid=1&remoteplace=txt.yqq.top&t=lyric&w=%E5%91%A8%E6%9D%B0%E4%BC%A6']
def start_requests(self):
for url in self.start_urls:
yield SplashRequest(url=url, callback=self.parse, dont_filter=True)
生成必要參數(shù),拼接請(qǐng)求鏈接。
def parse(self, response):
import random
lyric_list = []
# 一共有 39 頁(yè)歌詞,這里我就不再解析了,直接拿過(guò)來(lái)用
for page in rang(1,39):
page = str(page)
# 生成隨機(jī)數(shù)
MusicJsonCallback = 'MusicJsonCallback' + str(random.random()).replace('0.', '') + str(random.randint(0, 9))
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&remoteplace=txt.yqq.lyric&searchid=96611612886809799&aggr=0&catZhida=1&lossless=0&sem=1&t=7&p=' + page + '&n=10&w=%E5%91%A8%E6%9D%B0%E4%BC%A6&g_tk=5381&jsonpCallback=' + MusicJsonCallback + '&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0'
lyric_list.append(url)
for url in lyric_list:
yield Request(url=url, method='GET', # GET or POST
callback=self.parseLyric, dont_filter=True)
解析部分,為了方便查看,這里我就不一一刪除了輸出語(yǔ)句了。
返回結(jié)果(部分):
MusicJsonCallback5105102031857011({'code':0,'data':{'keyword':'周杰倫','lyric':{'curnum':10,'curpage':2,'list':[{'albumid':56705,'albummid':'000bviBl4FjTpO','albumname':'跨時(shí)代','albumname_hilight':'跨時(shí)代','alertid':23,'belongCD':0,'cdIdx':3,'chinesesinger':0,'content':'煙花易冷 - <em>周杰倫</em> (Jay Chou)\\n 詞:方文山\\n 曲:<em>周杰倫</em>\\n 編曲:黃雨勛\\n 繁華聲 遁入空門(mén) 折煞了世人\\n 夢(mèng)偏冷 輾轉(zhuǎn)一生 情債又幾本\\n 如你默認(rèn) 生死枯等\\n 枯等一圈 又一圈的 年輪\\n 浮屠塔 斷了幾層 斷了誰(shuí)的魂\\n 痛直奔 一盞殘燈 傾塌的山門(mén)\\n 容我再等 歷史轉(zhuǎn)身\\n 等酒香醇 等你彈 一曲古箏\\n 雨紛紛 舊故里草木深\\n 我聽(tīng)聞 你始終一個(gè)人\\n 斑駁的城門(mén) 盤(pán)踞著老樹(shù)根\\n 石板上回蕩的是 再等\\n 雨紛紛 舊故里草木深\\n 我聽(tīng)聞 你仍守著孤城\\n 城郊牧笛聲 落在那座野村\\n 緣份落地生根是 我們\\n 聽(tīng)青春 迎來(lái)笑聲 羨煞許多人\\n 那史冊(cè) 溫柔不肯 下筆都太狠\\n 煙花易冷 人事易分\\n 而你在問(wèn) 我是否還 認(rèn)真\\n 千年后 累世情深 還有誰(shuí)在等\\n 而青史 豈能不真 魏書(shū)洛陽(yáng)城\\n 如你在跟 前世過(guò)門(mén)\\n 跟著紅塵 跟隨我 浪跡一生\\n 雨紛紛 舊故里草木深\\n 我聽(tīng)聞 你始終一個(gè)人\\n 斑駁的城門(mén) 盤(pán)踞著老樹(shù)根\\n 石板上回蕩的是 再等\\n 雨紛紛 舊故里草木深\\n 我聽(tīng)聞 你仍守著孤城\\n 城郊牧笛聲 落在那座野村\\n 緣份落地生根是 我們\\n 雨紛紛 舊故里草木深\\n 我聽(tīng)聞 你始終一個(gè)人\\n 斑駁的城門(mén) 盤(pán)踞著老樹(shù)根\\n 石板上回蕩的是 再等\\n 雨紛紛 雨紛紛 舊故里草木深\\n 我聽(tīng)聞 我聽(tīng)聞 你仍守著孤城\\n 城郊牧笛聲 落在那座野村\\n 緣份落地生根是 我們\\n 緣份落地生根是 我們\\n 伽藍(lán)寺聽(tīng)雨聲盼 永恒','docid':'17014914173155710954','download_url':'http://soso.music.qq.com/fcgi-bin/fcg_download_lrc.q?song=煙花易冷&singer=周杰倫&down=1&songid=680279&docid=17014914173155710954','interval':263,'isonly':1,'lyric':' 曲:<em>周杰倫</em>\\n 編曲:黃雨勛\\n 繁華聲 遁入空門(mén) 折煞了世人\\n','media_mid':'004emQMs09Z1lz','msgid':14,'nt':2495419518,'pay':{'payalbum':0,'payalbumprice':0,'paydownload':1,'payinfo':1,'payplay':0,'paytrackmouth':1,'paytrackprice':200},'preview':{'trybegin':61557,'tryend':110138,'trysize':0},'pubtime':1274112000,'pure':0,'singer':[{'id':4558,'mid':'0025NhlN2yWrP4','name':'周杰倫','name_hilight':'<em>周杰倫</em>'}],'size128':4217251,'size320':10533794,'sizeape':27633930,'sizeflac':28429729,'sizeogg':5891914,'songid':680279,'songmid':'004emQMs09Z1lz','songname':'煙花易冷','songname_hilight':'煙花易冷','strMediaMid':'004emQMs09Z1lz','stream':1,'switch':636675,'t':1,'tag':11,'type':0,'ver':0,'vid':''},{'albumid':194021,'albummid':'003Ow85E3pnoqi','albumname':'十二新作','albumname_hilight':'十二新作','alertid':23,'belongCD':0,'cdIdx':8,'chinesesinger':0,'content':'紅塵客棧 - <em>周杰倫</em> (Jay Chou)\\n 詞:方文山\\n 曲:<em>周杰倫</em>\\n 天涯的盡頭是風(fēng)沙\\n 紅塵的故事叫牽掛\\n 封刀隱沒(méi)在尋常人家 東籬下\\n 閑云野鶴古剎\\n 快馬在江湖里廝殺\\n 無(wú)非是名跟利放不下\\n 心中有江山的人豈能快意瀟灑\\n 我只求與你共華發(fā)\\n 劍出鞘恩怨了 誰(shuí)笑\\n 我只求今朝擁你 入懷抱\\n 紅塵客棧風(fēng)似刀 驟雨落宿命敲\\n 任武林誰(shuí)領(lǐng)風(fēng)騷\\n 我卻只為你折腰\\n 過(guò)荒村野橋?qū)な劳夤诺繺\n 遠(yuǎn)離人間塵囂\\n 柳絮飄執(zhí)子之手逍遙\\n 檐下窗欞斜映枝椏\\n 與你席地對(duì)座飲茶\\n 我以工筆畫(huà)將你牢牢的記下\\n 提筆不為風(fēng)雅\\n 燈下嘆紅顏近晚霞\\n 我說(shuō)緣份一如參禪不說(shuō)話\\n 你淚如梨花灑滿了紙上的天下\\n 愛(ài)恨如寫(xiě)意山水畫(huà)\\n 劍出鞘恩怨了 誰(shuí)笑\\n 我只求今朝擁你入懷抱\\n 紅塵客棧風(fēng)似刀 驟雨落宿命敲\\n 任武林誰(shuí)領(lǐng)風(fēng)騷\\n 我卻只為你折腰\\n 過(guò)荒村野橋?qū)な劳夤诺繺\n 遠(yuǎn)離人間塵囂\\n 柳絮飄執(zhí)子之手逍
它返回的結(jié)果的前面一部分,不是 json 格式的,但后面一部分又是 json 格式的。所以,我們要先解析出 json 格式的那部分結(jié)果。
def parseLyric(self, response):
# 由于其返回的結(jié)果為字符串,而且不是 json 格式的,我們還有進(jìn)一步解析
lyric = (response.body.decode('UTF-8'))
# 解析 json 格式部分的結(jié)果
first = lyric.find('(') + 1
last = lyric.rfind(')')
lyric = lyric[first:last]
import json
from datetime import datetime
json_lyric = json.loads(lyric)
for song in json_lyric['data']['lyric']['list']:
# 解析歌曲
print('專輯名稱:' + song['albumname'])
ts = int(song['pubtime'])
pubtime = datetime.fromtimestamp(ts).strftime('%Y-%m-%d')
print('發(fā)行時(shí)間:' + pubtime)
print('歌名:' + song['songname'])
singers = ''
for singer in song['singer']:
singers += singer['name']
print('歌手:' + singers)
print(song['lyric'].replace('<em>', '').replace('</em>', ''))
content = song['content'].replace('<em>', '').replace('</em>', '')
print('歌詞:' + content)
print('================================================')
# 將歌詞寫(xiě)進(jìn) txt 文本
filename = 'lyric/' + song['songname'] + '-' + pubtime + '.txt'
with open(filename, 'w') as file_to_w:
file_to_w.write(content.replace('\\n', '\r\n'))
聯(lián)系客服