天天看点

python实现爬取网易云音乐评论,并且将评论信息存储到pymysql

python实现爬取网易云音乐评论,并且将评论信息存储到pymysql

第一步:我们要准备好我们的环境
python编辑器
python3.6 
只要是python3都行      

我们这次抓取是通过网易云特定的API进行一个请求并且抓取的

网易云API:
获取评论的API
http://music.163.com/api/v1/resource/comments/R_SO_4_{歌曲ID}?limit={每页限制数量}&offset={评论数总偏移}
获取评论对应用户的信息API:
https://music.163.com/api/v1/user/detail/{用户ID}      

​​https://music.163.com/api/v1/resource/comments/R_SO_4_​​​ 上面这部分是官方接口的基础URL,由于网易云评论是Ajax类型,所以我们去评论的界面右击检查,单击R_SO_4_’ + str(songid) + '?csrf_token=这个包,发现表单数据为

python实现爬取网易云音乐评论,并且将评论信息存储到pymysql

由此可知,当我们对网易云评论界面发起请求时,需要加入这部分的表单数据。通过构造URL之后,便可对其发起请求,得到json格式数据。

我们通过上面的API构建一个配置文件,config.py

config.py
import re

SONGID = '190449'
SONGNAME = '吻别'
LIMIT_NUM = 100

PATTERN = re.compile(r'[\n\t\r\/]') #替换掉评论中的特殊字符以防插入数据库时报错
#数据库名
DATABASE = '****'
#数据库表名
TABLE_COMMENTS = '****'
HOST = '****'
USER = '****'
PASSWD = '****'

ROOT_URL = 'http://music.163.com/api/v1/resource/comments/R_SO_4_'+SONGID+'?limit='+str(LIMIT_NUM)+'&offset=%s'
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
    'Host': 'music.163.com',
    #自己本地电脑的cookie,用来识别
    'Cookie': '****',
}      

在抓取,我们要创自己本地的数据库:

我先用常用的数据库类型创建了数据库:

CREATE TABLE IF NOT EXISTS `comments`(
   `id` int(100) auto_increment primary key,
   `commentId` INT NOT NULL,
   `content` VARCHAR(100) NOT NULL,
   `likedCount` VARCHAR(40) NOT NULL,
   `time` TIMESTAMP,
   `userId` int(100) NOT NULL,
   `songId` int(100) NOT NULL,
   `songName` VARCHAR(40) NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;      

这个上面的语句与下面的抓取文件在存储的时候产生了不少的冲突:

第一个问题:

python实现爬取网易云音乐评论,并且将评论信息存储到pymysql

但是数据可以存储到数据库,不过commentId这个数据没有在数据库里面,

python实现爬取网易云音乐评论,并且将评论信息存储到pymysql

这个问题是:

类型不匹配,commentId int类型长度不匹配,超出范围的问题,
我原本用int ,int 默认是11的长度,我后面用int(100)也不行

于是我用了类型为bigint时,可以插入 id =1113333333333的这条数据
成功解决问题      

第二个问题:

python实现爬取网易云音乐评论,并且将评论信息存储到pymysql

这个也是一个类型不匹配问题:

解决方法:
自己的表的content字段 长度不够,则改数据库中content类型为 mediumtext类型即可      

在存储过程后还会出现另外一个问题就是遇到一些特殊字符是会出现一个字符存储不了的问题,这个是一个编码格式问题

CHARSET=utf8
我们把编码格式改为:
CHARSET=utf8mb4就可以

也可以在创建数据库后通过:
alter table 表名 convert to character set utf8mb4;
修改      

经过解决这些问题后,我们创建正确的数据库语句为:

CREATE TABLE IF NOT EXISTS `comments`(
   `id` int(100) auto_increment primary key,
   `commentId` BIGINT NOT NULL,
   `content` mediumtext NOT NULL,
   `likedCount` VARCHAR(40) NOT NULL,
   `time` TIMESTAMP,
   `userId` BIGINT NOT NULL,
   `songId` BIGINT NOT NULL,
   `songName` VARCHAR(40) NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


或者:
CREATE TABLE IF NOT EXISTS `comments`(
   `id` int(100) auto_increment primary key,
   `commentId` BIGINT NOT NULL,
   `content` mediumtext NOT NULL,
   `likedCount` VARCHAR(40) NOT NULL,
   `time` TIMESTAMP,
   `userId` BIGINT NOT NULL,
   `songId` BIGINT NOT NULL,
   `songName` VARCHAR(40) NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

alter table 表名 convert to character set utf8mb4;
修改      

上面就是我在创建数据库文件中,遇到到了不少的坑,以及解决方法。

下面是我们抓取的主函数:

crawler.py
# -*- coding=utf-8 -*-
import json
from datetime import datetime
import requests
import config
import pymysql
import gevent
from gevent import monkey
monkey.patch_all()

class Crawler(object):
    def run(self, url):
        print('crawl ', url)
        self.parse_page(url)

    def down(self,url):
        try:
            return requests.get(url=url, headers=config.HEADERS).text
        except Exception as e:
            print('down err>>>', e)

    def parse_page(self, url):
        content = self.down(url)
        js = json.loads(content)
        datas = []
        for c in js['comments']:
            data = {}
            try:
                data['commentId'] = c['commentId']
                data['content'] = config.PATTERN.sub('', c['content'])
                data['likedCount'] = int(c['likedCount'])
                data['time'] = datetime.fromtimestamp(c['time']//1000)
                data['userId'] = c['user']['userId']
                datas.append(data)
            except Exception as e:
                print('解析js出错>>>', e)
        self.save(datas)

    def save(self, datas):
        conn = pymysql.connect(host=config.HOST, user=config.USER, passwd=config.PASSWD, db=config.DATABASE, charset='utf8mb4') # 注意字符集要设为utf8mb4,以支持存储评论中的emoji表情
        cursor = conn.cursor()
        sql = 'insert into '+config.TABLE_COMMENTS+' (commentId,content,likedCount,time,userId,songId,songName) VALUES (%s,%s,%s,%s,%s,%s,%s)'
        for data in datas:
            try:
                # cursor.execute('SELECT max(id) FROM '+config.TABLE_COMMENTS)
                # s = cursor.fetchone()[0]
                # if s:
                #   id_ = s+1
                # else:
                #   id_ = 1
                cursor.execute(sql, (data['commentId'], data['content'], data['likedCount'], data['time'], data['userId'], config.SONGID, config.SONGNAME))
                conn.commit()
            except Exception as e:
                print('存储错误>>>', e)
        cursor.close()
        conn.close()


    def main(self, pages):
        url_list = [config.ROOT_URL%(num*config.LIMIT_NUM) for num in range(0, pages//config.LIMIT_NUM+1)]
        job_list = [gevent.spawn(self.run, url) for url in url_list]
        gevent.joinall(job_list)

def getTotal():
    try:
        req = requests.get(config.ROOT_URL%(0), headers=config.HEADERS).text
        js = json.loads(req)
        return js['total']
    except Exception as e:
        print(e)
    return None

if __name__=="__main__":
    total = getTotal()
    spider = Crawler()
    spider.main(total)      

成功运行:

python实现爬取网易云音乐评论,并且将评论信息存储到pymysql

网易云官方对于API的请求是有限制的,频繁访问会被封禁ip