音乐的评论相对来说有一丢丢困难,主要在于它嵌套的循环多一点,还多了个翻页,下面详细介绍:
思路:
1:由于评论的页数随着评论数目在不断增加,首先要匹配而歌曲总的页数
2:然后将页数作为for循环的最大循环次数,每循环一次都要翻页一次(模拟点击)
3:匹配出评论内容,并且写进去数据库
4:控制最外层循环就是循环歌曲的id,把匹配评论这部分内容打包成类,然后创建一个browser全局变量作为参数传进去
导入使用的模块:
from lxml import html
import time
from selenium import webdriver
import re
import csv
import pymysql
class Demo:
comment_list = [] # 定义评论列表文件
writer_list = [] # 定义评论者列表
# 写入数据库
conn = pymysql.connect(host='localhost' ,user = 'root',passwd = '123456',db= 'wyy' ,charset = 'utf8mb4')
curs = conn.cursor()
创建一个构造方法,将全局变量browser和url作为参数,保证在切换歌曲url的时候保持原来的浏览器窗口不变。浏览器等待的时间我是慢慢试出来的,如果时间过短的话网页加载不完,会抛错找不到contentFrame,在尝试的时候肯定是时间越短越好。
def __init__(self,browser,url):
self.browser = browser
time.sleep(2)
self.browser.get(url)
self.browser.implicitly_wait(65)
try:
self.browser.switch_to.frame('contentFrame') # 进入frame
except Exception as e:
print(e)
下一步就是找到所有的页数,笔者在这使用的是xpath匹配,python3直接导入xpath的时候会报错,及时是最新版的lxml依然会报错,所以就先导入html,再实例etree对象,通过观察每一大页都会有匹配出来text13个,观察一下最大页所在的位置,当页数超过8的时候len(texts)-4是最大页数的索引。但是还有一种情况就是如果页数在8之内,其他的文本就是None,所以需要判断一下,如果文本是None就索引减一直到找到数字就代表找到了最大页数。接下来就是循环了,返回最大页数。
def all_pages(self):
etree = html.etree
htmls = self.browser.page_source
codes = etree.HTML(htmls)
texts = codes.xpath("//a[@href='#']")
# for te in texts: #记录一下总的文本数量13个
#print(te.text)
s = 4
while (s<=13):
pa = texts[len(texts) - s].text
if pa == None:
s = s+1
else:
last_page = int(pa)
return last_page
接下来就是中心部分了,抓取我们想要的评论,匹配出‘下一页’的按钮,每循环一次翻页一次,定位出评论的文字并且写入数据库。比较简单
def get_comment(self, pages):
for x in range(pages): #64是需要抓取的页面总数***
button = self.browser.find_element_by_link_text('下一页') # 通过找到‘下一页’的按钮进行翻页
time.sleep(2)
# print(button.text)
aa = self.browser.find_elements_by_xpath('//div/div[2]/div[1]/div[1]') # 定位评论文字
for i in aa:
# print(i.text)
a = re.search(':', i.text) # 通过正则表达式进行“:”定位,得出左边是评论者,这个要去掉
# print(a)
if a:
n = i.text.index(':') + 1
writ = i.text[:n].replace(':', '') # 只保留从“:”左边的文字,就是纯正的作者名
comm = i.text[n:] # 只保留从“:”右边的文字,就是纯正的评论文字
self.curs.execute("insert into data (writer,comment) values (%s,%s) " ,(writ, comm))
self.conn.commit()
else:
#comment_list.append('')
print('')
self.conn.commit()
print('抓取了>>>>' + str(x+1) + '<<<<页')
try :
button.click() # 自动进行“下一页”的按钮
except Exception as e:
print(e)
然后就是主函数了,在主函数里创建浏览器的对象,在这里笔者设置成浏览器不加载图片,这样在运行中会节省一些时间,用到了上一篇我们写的歌曲id,最后浏览器不要忘了关了。在这我单独找了一些评论页数少于8页的歌曲id,用来测试切换url的效果。
if __name__ == '__main__':
id = open('F:/music/网易云音乐歌曲信息.csv', 'r', encoding='utf-8-sig')
id_reader = csv.DictReader(id)
columns = [row for row in id_reader]
#columns = [439646311,1348918118,541076059,1303464240] # 测试切换id
chrome_options = webdriver.ChromeOptions()
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_options.add_experimental_option("prefs", prefs)
browser = webdriver.Chrome(chrome_options= chrome_options)
for id_new in columns:
new_id = id_new['歌曲id']
url = 'https://music.163.com/#/song?id=' + str(new_id) # 测试的时候换成id_new
dd = Demo(browser=browser, url = url)
pages = dd.all_pages()
dd.get_comment(pages)
print('********************************进入下一个************************************')
time.sleep(3)
dd.browser.close()
参考:https://blog.csdn.net/johnchiao/article/details/83959089
嗯呐,然后就可以一直爬下去了…
笔者爬虫新人,有写的不对的地方的还请读者留言希望能帮助到需要的人。