思路来源于此,注明出处:
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。。。。,好吧,回音哥确实比较伤感吧。(笑哭表情)