思路來源於此,註明出處:
https://mp.weixin.qq.com/s/gx04XBv0qRuQB75ccPCi3g
尊重原創
——————————————————————————————
簡單來說,我們想分析某一位歌手所唱的所有歌曲(主流網站上可以找出來的),主要出現的詞彙是什麼(更能反映歌手的偏好)。下面開始動手做:
第一個,爬數據
爬數據這裏我用的是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。。。。,好吧,迴音哥確實比較傷感吧。(笑哭表情)