scrapy趕上ajax,抓取QQ音樂周杰倫專輯與歌詞(6)

爬蟲利器初體驗(1)html

據說你的爬蟲又被封了?(2)前端

爬取數據不保存,就是耍流氓(3)node

爬取兩萬多租房數據,告訴你廣州房租現狀(4)python

scrapy 也能爬取妹子圖?(5)mysql

scrapy趕上ajax,抓取QQ音樂周杰倫專輯與歌詞(6)面試

目錄

  • 序言
  • 分析網頁
  • 分析請求
  • 代碼實現
  • 瞎比比

序言

很久沒寫原創文章,早就手癢癢了,因此擠出時間寫了這篇,這是下面這五篇文章的連載文章: (1) (2) 那這段時間我都去幹嗎了呢?時間都用在寫小程序(編程面試題庫)了,如今也已經寫得七七八八了,別看這小程序功能很少。但要作的內容卻是挺多的,給它配了個面試題庫的爬蟲系統,後臺內容管理系統。其中用到了不少技術棧,python、nodejs、flask、koa2(nodejs庫)、前端、小程序、scrapy、docker、mysql、mongodb等等。結合起來使用仍是挺考驗人的,經過此次使用,又複習了一下前端,但依然是個前端小渣渣。 做爲一個老傑迷,從四年級就開始聽 jay 的歌。明天是杰倫的生日,感受再不搞點小動做還真是對不起杰倫了。此次寫文呢,是專門獻給杰倫的。ajax

分析網頁

若是你作的是網頁爬蟲,那麼首先要作的是:分析這個網頁是服務端渲染仍是客戶端渲染,便是判斷該網頁是同步請求仍是異步請求?這個很簡單,我很早就介紹過一個 Chrome 插件,如圖 sql

具體用法請查看個人歷史文章。 使用工具關閉 JavaScript 請求以後,咱們獲得的頁面是這樣的:

關閉 JavaScript
打開以後是這樣的:
開啓 JavaScript
很明顯,這是一個異步請求。接下來就是在衆多請求中找到歌詞的請求,如圖:

分析請求

接下來沒啥,就分析這個請求的參數。經過翻頁以後,咱們來看看兩個請求之間是參數對比。 mongodb

第一頁歌詞請求參數
第二頁歌詞請求參數
咱們能夠看出 p 是頁碼的意思,w 是關鍵詞的意思,第一個紅框和最後一個紅框是有不一樣的。通過個人分析,第一個紅框不變也不要緊,同樣是可使用。那第二個紅框是怎麼來的?這裏,我先不講解,由於這與本文的主題不太相關,我會安排更詳細的文章告訴你,它到底是怎麼來的。深層次的緣由是,我後面會有反爬蟲系列的文章,這個內容恰好在規劃在那個系列裏面。但結論咱們能夠先用,結論就是:這些數字就是一些隨機數,咱們用代碼生成隨機數即是。

代碼實現

訪問首頁

首先,先訪問首頁,拿到 cookie 等信息,以避免後面被封掉。docker

class Spider(scrapy.Spider):
    name = 'qq'
    allowed_domains = ['jianshu.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)
複製代碼

實現異步請求

生成必要參數,拼接請求連接。

def parse(self, response):
    import random
    lyric_list = []
    # 一共有 39 頁歌詞,這裏我就再也不解析了,直接拿過來用
    for page in rang(1,39):
        page = str(page)
        # 生成隨機數
        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&notice=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)
複製代碼

解析歌曲

解析部分,爲了方便查看,這裏我就不一一刪除了輸出語句了。 返回結果(部分):

MusicJsonCallback5105102031857011({"code":0,"data":{"keyword":"周杰倫","lyric":{"curnum":10,"curpage":2,"list":[{"albumid":56705,"albummid":"000bviBl4FjTpO","albumname":"跨時代","albumname_hilight":"跨時代","alertid":23,"belongCD":0,"cdIdx":3,"chinesesinger":0,"content":"煙花易冷 - <em>周杰倫</em> (Jay Chou)\\n 詞:方文山\\n 曲:<em>周杰倫</em>\\n 編曲:黃雨勳\\n 繁華聲 遁入空門 折煞了世人\\n 夢偏冷 展轉一輩子 情債又幾本\\n 如你默認 生死枯等\\n 枯等一圈 又一圈的 年輪\\n 浮屠塔 斷了幾層 斷了誰的魂\\n 痛直奔 一盞殘燈 傾塌的山門\\n 容我再等 歷史轉身\\n 等酒香醇 等你彈 一曲古箏\\n 雨紛紛 舊故里草木深\\n 我聽聞 你始終一我的\\n 斑駁的城門 盤踞着老樹根\\n 石板上回蕩的是 再等\\n 雨紛紛 舊故里草木深\\n 我聽聞 你仍守着孤城\\n 城郊牧笛聲 落在那座野村\\n 緣份落地生根是 咱們\\n 聽青春 迎來笑聲 羨煞許多人\\n 那史冊 溫柔不願 下筆都太狠\\n 煙花易冷 人事易分\\n 而你在問 我是否還 認真\\n 千年後 累世情深 還有誰在等\\n 而青史 豈能不真 魏書洛陽城\\n 如你在跟 前世過門\\n 跟着紅塵 跟隨我 浪跡一輩子\\n 雨紛紛 舊故里草木深\\n 我聽聞 你始終一我的\\n 斑駁的城門 盤踞着老樹根\\n 石板上回蕩的是 再等\\n 雨紛紛 舊故里草木深\\n 我聽聞 你仍守着孤城\\n 城郊牧笛聲 落在那座野村\\n 緣份落地生根是 咱們\\n 雨紛紛 舊故里草木深\\n 我聽聞 你始終一我的\\n 斑駁的城門 盤踞着老樹根\\n 石板上回蕩的是 再等\\n 雨紛紛 雨紛紛 舊故里草木深\\n 我聽聞 我聽聞 你仍守着孤城\\n 城郊牧笛聲 落在那座野村\\n 緣份落地生根是 咱們\\n 緣份落地生根是 咱們\\n 伽藍寺聽雨聲盼 永恆","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 繁華聲 遁入空門 折煞了世人\\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 天涯的盡頭是風沙\\n 紅塵的故事叫牽掛\\n 封刀隱沒在尋常人家 東籬下\\n 閒雲野鶴古剎\\n 快馬在江湖裏廝殺\\n 無非是名跟利放不下\\n 心中有江山的人豈能快意瀟灑\\n 我只求與你共華髮\\n 劍出鞘恩怨了 誰笑\\n 我只求今朝擁你 入懷抱\\n 紅塵客棧風似刀 驟雨落宿命敲\\n 任武林誰領風騷\\n 我卻只爲你折腰\\n 過荒村野橋尋世外古道\\n 遠離人間塵囂\\n 柳絮飄執子之手逍遙\\n 檐下窗櫺斜映枝椏\\n 與你席地對座飲茶\\n 我以工筆畫將你緊緊的記下\\n 提筆不爲風雅\\n 燈下嘆紅顏近晚霞\\n 我說緣份一如參禪不說話\\n 你淚如梨花灑滿了紙上的天下\\n 愛恨如寫意山水畫\\n 劍出鞘恩怨了 誰笑\\n 我只求今朝擁你入懷抱\\n 紅塵客棧風似刀 驟雨落宿命敲\\n 任武林誰領風騷\\n 我卻只爲你折腰\\n 過荒村野橋尋世外古道\\n 遠離人間塵囂\\n 柳絮飄執子之手逍 複製代碼

它返回的結果的前面一部分,不是 json 格式的,但後面一部分又是 json 格式的。因此,咱們要先解析出 json 格式的那部分結果。

def parseLyric(self, response):
    # 因爲其返回的結果爲字符串,並且不是 json 格式的,咱們還有進一步解析
    lyric = (response.body.decode('UTF-8'))
    # 解析 json 格式部分的結果
    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('發行時間:' + 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('================================================')
        # 將歌詞寫進 txt 文本
        filename = 'lyric/' + song['songname'] + "-" + pubtime + '.txt'
        with open(filename, 'w') as file_to_w:
            file_to_w.write(content.replace("\\n", '\r\n'))
複製代碼

瞎比比

感嘆一句:從新寫文章真是爽!!這裏只給出了分析歌詞的源碼,在 GitHub 中,我還寫了分析專輯的代碼,詳見 GitHub。後臺回覆「杰倫歌詞」,獲取杰倫的全部歌詞。回覆「杰倫源碼」,獲取源碼。

本文首發於公衆號「zone7」,關注獲取最新推文!

image
相關文章
相關標籤/搜索