1. 程式人生 > >資料分析:當迴音哥唱music時,他在唱些什麼~~~

資料分析:當迴音哥唱music時,他在唱些什麼~~~

思路來源於此,註明出處:

尊重原創

——————————————————————————————

簡單來說,我們想分析某一位歌手所唱的所有歌曲(主流網站上可以找出來的),主要出現的詞彙是什麼(更能反映歌手的偏好)。下面開始動手做:

第一個,爬資料

爬資料這裡我用的是scrapy + selenium,二話不說,先上程式碼:

# scrapy中置於 spider 下的 爬蟲.py

from scrapy import Spider,Request
from selenium import webdriver
from .. import process_text_format
from .. import items


class HuiyingeSpider(Spider):
    name = 'huiyinge'
    allowed_domains=['https://y.qq.com']

    def __init__(self):
        self.browser = webdriver.Chrome()
        self.browser.set_page_load_timeout(30)

    def closed(self,spider):
        print("spider closed")
        self.browser.close()

    def start_requests(self):
        start_urls = ['https://y.qq.com/portal/search.html#page={}&searchid=1&remoteplace=txt.yqq.top&t=lyric&w=%E5%9B%9E%E9%9F%B3%E5%93%A5'.format(str(i)) for i in range(1,11,1)]
        for url in start_urls:
            yield self.make_requests_from_url(url=url)

    def parse(self, response):
        titles = response.xpath('//*[@id="lyric_box"]/div[1]/ul/li/h3/a[1]/text()').extract()
        lrcs = response.xpath('//*[@id="lyric_box"]/div[1]/ul/li/div[2]/p').extract()

        for title, lrc in zip(titles, lrcs):
            item = items.HuiyingeItem()
            item['title'] = title
            item['lrc'] = process_text_format.prcessTextFormat(lrc)
            yield item

這裡我們選擇的是*q音樂,嗯,迴音哥的音樂在這個網站上比較全

這裡由於後邊我們對資料的儲存需要(我們是儲存到檔案txt中的,而不是存入資料庫),我們把歌名當做txt檔名,歌詞存入其中充當內容,所以分成title和lrc兩個欄位,但是lrc裡有很多html標籤,例如<p><span>之類的,我們要取出較為正常的歌詞,對此我們做一個格式化處理,就是上面的prcessTextFormat函式

#scrapy 下 自己建立的py檔案 process_text_format.py

def prcessTextFormat(text):

    flagOfIsHaveHtml = text.find('<')

    while flagOfIsHaveHtml != -1:
        indexStart = flagOfIsHaveHtml
        indexEnd = text.find('>')
        text = text.replace(text[indexStart:indexEnd + 1], '\n', 1)
        flagOfIsHaveHtml = text.find('<')

    return text.strip()

if __name__ == '__main__':
    text = '''<p>天后 - <span class="c_tx_highlight">迴音哥</span> (Echo)<br> 詞:彭學斌<br> 曲:彭學斌<br> 終於找到藉口趁著醉意上心頭<br> 表達我所有感受<br> 寂寞漸濃沉默留在舞池角落<br> 你說的太少或太多<br> 都會讓人更惶恐<br> 誰任由誰放縱誰會先讓出自由<br> 最後一定總是我<br> 雙腳懸空在你冷酷熱情間遊走<br> 被侵佔所有還要笑著接受<br> 我嫉妒你的愛氣勢如虹<br> 像個人氣高居不下的天后<br> 你要的不是我而是一種虛榮<br> 有人疼才顯得多麼出眾<br> 我陷入盲目狂戀的寬容<br> 成全了你萬眾寵愛的天后<br> 若愛只剩誘惑只剩彼此忍受<br> 別再互相折磨<br> 因為我們都有錯<br> 推開蒼白的手推開蒼白的廝守<br> 管你有多麼失措<br> 別再叫我心軟是最致命的脆弱<br> 我明明都懂卻仍拼死效忠<br> 我嫉妒你的愛氣勢如虹<br> 像個人氣高居不下的天后<br> 你要的不是我而是一種虛榮<br> 有人疼才顯得多麼出眾<br> 我陷入盲目狂戀的寬容<br> 成全了你萬眾寵愛的天后<br> 若愛只剩誘惑只剩彼此忍受<br> 別再互相折磨<br> 因為我們都有錯<br> 如果有一天愛不再迷惑<br> 足夠去看清所有是非對錯<br> 直到那個時候<br> 你在我的心中<br> 將不再被歌頌<br> 把你當作天后<br> 不會再是我</p>'''
    print(prcessTextFormat(text))

由於我們選擇是selenium來去載入頁面(這樣就不用害怕js或者之類的載入東東導致我們不能爬到資料了),所以我們需要修改中間鍵

#scrapy 下的 middlewares.py

from scrapy.http import HtmlResponse
from selenium.common.exceptions import TimeoutException
import time

class SeleniumMiddleware(object):
    def process_request(self, request, spider):
        if spider.name == 'huiyinge':
            try:
                spider.browser.get(request.url)
                # elem = spider.browser.find_element_by_class_name('next js_pageindex')
            except TimeoutException as e:
                print('超時')
                spider.browser.execute_script('window.stop()')
            time.sleep(2)
            return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source,
                                encoding="utf-8", request=request)

同樣貼出items.py和pipelines.py,感覺沒什麼好說的,pipelines我選擇的處理方式是直接把資料儲存成檔案而不是存入資料庫

# scrapy 下的 items.py

import scrapy


class HuiyingeItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    lrc = scrapy.Field()
# scrapy 下的 pipelines.py

class ScrapySeleniumPipeline(object):

    def process_item(self, item, spider):

        fileName = item['title']

        with open('file/{}.txt'.format(fileName), 'w') as f:
            f.write(item['lrc'])

為了在執行過程中便於除錯,我們加一個指令碼

# scrapy 下 新建的便於pycharm執行和除錯的指令碼py begin.py

from scrapy import cmdline
cmdline.execute("scrapy crawl huiyinge".split())

然後把這個在 執行/除錯設定 裡面設定一下就好了(更詳細的過程百度也有,這裡就不再贅述了)

展示一個爬到的歌曲吧,也是目前比較喜歡的一首歌:

然後問題來了,lrc裡有很多冗餘欄位,比如重複出現歌手,監製,編曲之類的人名,這些可能會對我們後邊篩選關鍵詞造成影響,所以我們做一個簡單的預處理,剔除其中的一些欄位(正式歌詞之前的段落)

# pretreatment_huiyin.py  預處理歌詞py

import os

def remove_sundry(line):
    indexOfColon = line.find(':')
    if (indexOfColon != -1):
        if line.__len__() == (indexOfColon + 1):
            return 2
        return 1
    return 0

flagOfIsSkip = False

if __name__ == '__main__':
    list = os.listdir('file')
    for fileName in list:
        if(fileName.find('.txt') != -1):
            with open('file/{}'.format(fileName),'r') as f:
                 # print(fileName)
                index = 1
                newFile = '';
                for line in f.readlines():
                    # print(line)
                    if (index > 3):

                        if flagOfIsSkip:
                            flagOfIsSkip = False
                            continue

                        flagOfIdAdd = remove_sundry(line)

                        if flagOfIdAdd == 0:
                            newFile += line
                        if flagOfIdAdd == 2:
                            flagOfIsSkip = True

                    else:
                        index = index + 1

            with open('file/{}'.format(fileName), 'w') as f:
                f.write(newFile)

這裡處理的效果並不是很理想,首先把前三行除掉,因為前三行都是歌名,歌手名,還有他的英文名,然後我們隊後邊的段落檢查是否這一行有冒號(:)有的話,說明這一行是類似於監製,編曲之類的冗餘資訊,我們就把他去掉,然而還是有漏網之魚,有的冒號之後沒有內容,而是直接換行顯示對應的音樂人,我們加一個檢查就是如果冒號後換行的話,就刪掉下一行,然而即使這樣,還是又一部分有漏網之魚(唉,只能抱怨一句網站還是不夠規範吧)。剩下的自己稍微改一下吧。(格式太千奇百怪的話,也就只能人為干預了,哼!)

修改好後,我們就開始正式的分析資料了,上程式碼

# 分析資料的py analyze_huiyin.py

import jieba.posseg as psg
import os
from collections import Counter

def check_word_characteristic(word_flag):
    if(word_flag.find('r') != -1 or word_flag.find('p') != -1 or word_flag.find('c') != -1 or word_flag.find('u') != -1):
        return False
    return True

if __name__ == '__main__':

    files = os.listdir('file')
    print(files.__len__())
    items = []
    for fileName in files:
        if(fileName.find('.txt') != -1):
            with open('file/{}'.format(fileName),'r') as f:
                item = []
                itemSet = set()
                for line in f.readlines():
                    for word, flag in psg.cut(line.strip()):
                        if(check_word_characteristic(flag)):
                            temp = word + "_" + flag;
                            item.append(temp)
            itemSet.update(item)
            items.append(itemSet)
    counter_items = Counter()
    for item in items:
        counter_items.update(item)
    print(counter_items)

這裡主要的思想前面的微信公眾號已經說了,主要是就讀取資料 -> 對單個歌曲做分詞,set去重 -> 統計所有的歌曲,累加起來 -> collections.counter來進行統計。這裡我們加上了詞性的過濾,過濾掉一些助詞,代詞,介詞,連詞之類的虛詞

最後的統計結構展示一下(人為過濾了一下常見的動詞)

'沒有_v': 21

'不會_v': 18

'不要_df': 16

'知道_v': 15

'幸福_a': 15

'寂寞_a': 14

'不能_v': 14

'夢_n': 13

'眼淚_n': 12

'永遠_d': 12

emmmm。。。。,好吧,迴音哥確實比較傷感吧。(笑哭表情)