前言

实现Scrapy框架爬取网页数据(酷狗音乐Top100名,包括排名信息、歌手信息、歌曲名、歌曲时长)

一、创建项目

在cmd中输入:

scrapy startproject kugouScrapy
cd kugouScrapy
scrapy genspider kugou www.kugou.com

目录结构:


二、编写items.py

Item 是保存爬取到的数据的容器;其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。

网页中包含大量数据,但并不是所有数据都需要存储,否则会浪费大量服务器资源,提取网页中需要的数据时,首先需要编写items.py文件,在该文件中定义需要爬取的数据

修改items.py文件,代码如下:

import scrapy


class KugouscrapyItem(scrapy.Item):
    # 定义rank存储排名信息
    rank = scrapy.Field()
    # 定义singer存储歌手信息
    singer = scrapy.Field()
    # 定义name存储歌曲名称
    name = scrapy.Field()
    # 定义time存储歌曲时长
    time = scrapy.Field()

三、编写pipelines.py

部分代码参考了别人的博客,但是我找不到原出处了,抱歉!

from itemadapter import ItemAdapter
import csv
import codecs
import json
from openpyxl import Workbook

class KugouscrapyPipeline:
    def __init__(self):
        # # ------------- 存储为txt格式 -------------
        # self.file = open('../../data/kugou_top100.txt', 'w', encoding='utf-8')
        # self.file.write('rank;singer;name;time' + '\n')

        # #------------- 存储为json格式 -------------
        # # 打开kugou_top100.json文件
        # self.file = codecs.open('../../data/kugou_top100.json', 'w', encoding='utf-8')

        # ------------- 存储为csv格式 -------------
        # 打开文件,指定方式为写,利用第3个参数把csv写数据时产生的空行消除
        self.file = open('../../data/kugou_top100.csv', 'w', encoding='utf-8-sig', newline='')
        # 设置文件第一行的字段名,注意要跟spider传过来的字典key名称相同
        self.fieldnames = ['rank', 'singer', 'name', 'time']
        # 指定文件的写入方式为csv字典写入,参数1为指定具体文件,参数2为指定字段名
        self.writer = csv.DictWriter(self.file, fieldnames=self.fieldnames)
        # 写入第一行字段名,因为只要写入一次,所以文件放在__init__里面
        self.writer.writeheader()
        #
        # # ------------- 存储为excel格式 -------------
        # self.file = Workbook()
        # self.ws = self.file.active
        # self.ws.append(['rank', 'singer', 'name', 'time'])  # 设置表头

    def process_item(self, item, spider):
        # # ------------- 存储为txt格式 -------------
        # res = dict(item)
        # rank = res['rank']
        # singer = res['singer']
        # name = res['name']
        # time = res['time']
        # self.file.write(
        #     rank + ";" + singer + ";" + name + ";" + time + ";" + '\n')

        # #------------- 存储为json格式 -------------
        # # dumps 将一个Python数据结构转为json
        # # json.dumps 序列化时对中文默认使用的ascii编码.想输出中文需要指定ensure_ascii=False
        # i = json.dumps(dict(item), ensure_ascii=False)
        # # 每条数据添加后换行
        # line = i + '\n'
        # # 将数据写入文件
        # self.file.write(line)

        # ------------- 存储为csv格式 -------------
        # 写入spider传过来的具体数值
        self.writer.writerow(item)

        # # ------------- 存储为excel格式 -------------
        # line = [item['rank'], item['singer'], item['name'], item['time']]  # 把数据中每一项整理出来
        # self.ws.append(line)  # 将数据以行的形式添加到xlsx中
        # self.file.save('../../data/kugou_top100.xlsx')  # 保存xlsx文件
        #
        return item

    def close_spider(self, spider):
        # 关闭文件
        self.file.close()


四、修改settings.py文件

修改pipelines的配置部分

开启ITEM_PIPELINES功能使得pipelines.py文件生效

设置User-Agent伪装浏览器

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'


# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'kugouScrapy.pipelines.KugouscrapyPipeline': 300,
}

为了避免服务器通过Cookie信息识别爬虫行为,需关闭本地Cookie,使得对方的服务器无法根据Cookie信息识别是否是爬虫而进行屏蔽处理,还需要设置Cookie禁用选项,代码如下:

# Disable cookies (enabled by default)
COOKIES_ENABLED = False

关闭遵守爬虫协议:

# Obey robots.txt rules
ROBOTSTXT_OBEY = False  # 禁用遵守爬虫协议

五、编写爬虫文件(核心)

①对爬虫网页URL进行分析

网页版酷狗不能手动翻页进行下一步的浏览,通过观察不同页面的URL,发现只需要更换参数即对应不同的页面,由于每页显示的为22首歌曲,因此总共需要5个URL

https://www.kugou.com/yy/rank/home/{分页参数}-8888.html

②对网页信息进行提取——使用Selector选择器

import parsel
import scrapy
import requests

# from kugouScrapy.kugouScrapy.items import KugouscrapyItem
from ..items import KugouscrapyItem


class KugouSpider(scrapy.Spider):
    name = 'kugou'
    allowed_domains = ['www.kugou.com']
    start_urls = ['https://www.kugou.com/yy/rank/home/1-8888.html?from=rank']
    page = 2
    count = 1

    def parse(self, response):

        music_list = response.selector.css('div.pc_temp_songlist li')

        for item in music_list:
            # 将items中定义的对象实例化
            music = KugouscrapyItem()
            # 在TOP1-3中,酷狗音乐将它们特殊地包在了一对strong标签下,这里我们需要特殊处理
            if self.count <= 3:
                music['rank'] = item.css('span.pc_temp_num strong::text').re_first('[0-9]+')
            else:
                music['rank'] = item.css('span.pc_temp_num::text').re_first('[0-9]+')
            # 有一些音乐由于singer部分太长,无法构成'singer - name'格式,于是采用try-except,如果有爬取不到的数据,就进入链接爬取
            try:
                music['singer'] = ''.join(item.css('a.pc_temp_songname::text').get()).split('-')[0]
                music['name'] = ''.join(item.css('a.pc_temp_songname::text').get()).split('-')[1]
            except:
                url = item.css('a.pc_temp_songname::attr(href)').get()
                response_item = requests.get(url=url)
                selector_item = parsel.Selector(response_item.text)
                music['singer'] = ''.join(selector_item.css('.audioName::text').get()).split('-')[0]
                music['name'] = ''.join(selector_item.css('.audioName::text').get()).split('-')[1]
                print(url)
            music['time'] = ''.join(item.css('span.pc_temp_time::text').get()).strip()
            self.count += 1
            # 因为要获取TOP100的数据,一页数据22条,无法整除,所以在写入文件时判断是否已满100
            if self.count <= 101:
                yield music

        if self.page <= 5:
            url = 'https://www.kugou.com/yy/rank/home/{}-8888.html'.format(str(self.page))
            self.page += 1
            yield scrapy.Request(url=url, callback=self.parse)

六、爬取结果

在控制台输入 scrapy crawl kugou 启动爬虫项目

控制台输出

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐