序章

PM最近问我要网易云的歌手的热门歌曲的信息,作为数据分析。说起网络爬虫我们都不陌生,我们分析网站的HTML的格式和URL的通用格式来写相应的算法。然后请求对应的URL来获取HTML字符串,因此总的来说,爬虫的本质就是请求和字符解析。

一.分析页面布局。

首先我们来分析网易云音乐的HTML构成(多图预警)。我们来看网易云的歌手的网页构成。

图1

图2

图1、图2中分别标注了三个地方,是我们分析一个网页的时候,需要注意的地方。

1.分析URL

2.分析菜单列表。

很容易的能够看到,网易云歌手的分布是按照【类别】来分的。我们在获取每个歌手的信息的时候,又id来表示的,其中图2中地址栏中的地址进行分析:http://music.163.com/discover/artist/cat?id=1001&inital=65

1,有前端知识的同学肯定知道,地址栏中的 “#”是前端的路由。所以我们再实际操作的时候,需要把#去掉。在地址中,http://music.163.com/discover/artist/cat?id=1001&inital=65,id=1001表示的是歌手的类别ID,inital=65表示的是歌手的按照字母排序的歌手名字类别ID。

详细来说

id=1001 表示的是 【华语男歌手】

inital=65 表示的是 【首字母为A的名字】

(读者可以访问http://music.163.com/discover/artist/cat?id=1001&inital=65查看一下网页的源码。)

我们可以通过获取分析HTML源码来获取页面上的所有的【类别ID】和【歌手名字类别ID】,进而获取所有的【歌手列表页面】

例如:

如下图

图3

图中很容一分析的页面上的歌手类别ID,华语男歌手ID为 1001、华语女歌手ID为1002、华语组合/乐队ID为1003。

同理我们很容分析出来歌手的名字类别ID如图4

图4

很容易得知:热门歌手的ID=-1、首字母为A的ID=65、首字母为B的ID=66、首字母为C的ID=67。

由上图的分析很容易知道,假如类别有N个,名字类别有M个。最后组合在一起的URL一共有N*M个。

整体思路我们分析完了。

接下来该分析源码,处理字符串来获取了我们想要的类别ID 和 名字类别ID。

/**

* 发送请求

* @param null $url 请求的URL

* @return bool|string 返回的信息

*/

function sendRequest($url=null){

$handle = null;

if (empty($url)){

$handle = fopen($this->url, "rb");

}else{

$handle = fopen($url, "rb");

}

$contents = stream_get_contents($handle);

fclose($handle);

return $contents;

}

/**

* 获取歌手歌曲主页的URL

* @param $html_str

* @return array

*/

function getSingerHomeUrl($html_str){

$typeMap = [];

$rltArr = [];

$urlRsltArr = [];

$dom = HtmlDomParser::str_get_html($html_str);

$elems = $dom->find('li');

foreach ($elems as $key => $value){

$aas = $value->find('a');

foreach ($aas as $k=>$v){

if (strpos(trim($v->href),'discover/artist/cat') !== false ){

if (strpos($v->href,'initial') !== false){

$rltArr[] = BASE_URL.$v->href;

}else{

if (is_numeric(trim($v->href,'/discover/artist/cat?id='))){

$typeMap[trim($v->href,'/discover/artist/cat?id=')] = $v->text();

}

}

}

}

}

foreach ($typeMap as $id=>$type){

foreach ($rltArr as $url){

$urlRsltArr[$type][] = str_replace('1001',$id,$url);

}

}

return $urlRsltArr;

}

其中我们用到了一个工具HtmlDomParser,这是一个专门用来解析HTML的SDK,我们可以在github上很容易搜到,在这里我用的是composer来管理这些第三方框架的。

composer require sunra/php-simple-html-dom-parser

既然说到HtmlDomParser,我就多说一句。

传进去html字符串,获取一个DOM对象

$dom = HtmlDomParser::str_get_html($html_str);

find()方法是以选择器的方式来获取其中的某一个元素的,返回的是一个数组。

$dom->find($selector);

其中有一个坑,我们一般会用var_dump()来打印一个对象。但是对于这个工具来说,这样是无法打印出我们想要的东西的。

这个HTML解析工具为我们封装了一个dump(),我只需要$dom->dump()就可以调试打印了。

其中有一个BASE_URL,这个是我定义的一个常量。

define('BASE_URL','http://music.163.com');

define('MV_BASE_URL','http://music.163.com/mv?id=');

define('SONG_BASE_URL','http://music.163.com/song?id=');

define('APP_PATH',__DIR__);

define('DATA_PATH',APP_PATH.'/data');

这些路径很容易看懂吧。接下来会用到。

通过上述的代码我们封装了好了方法,我们需要一个初始URL来驱动我们整个爬虫的运行。

$url = 'http://music.163.com/discover/artist/cat?id=1001&initial=65';

接下来我们调用我们的方法

$url = 'http://music.163.com/discover/artist/cat?id=1001&initial=65';

$html_str = sendRequest($url);

$arr = getSingerHomeUrl($html_str);

二.分析歌手页面源码

图5

可以从图5看出,整个歌手的数据分为两个部分。

第一部分:带图片的。

第二部分:不带图片。

接下来我们需要做的就是分析这两者的源码。

图6

我们分析两者的源码可以得到如下的结论。

1、a标签的herf的值包含“/artist?id=”

2、并且歌手的id为的值为数字

3、歌手的主页的url为 http://music.163.com/artist?id=xxxx

很容易得到下面的代码

/**

* 获取歌手的信息,通过解析HTML字符串

* @param $html_str HTML字符串

* @param null $type 歌手类型

* @return array

*/

public function getSingerInfo(){

$file_path = APP_PATH.'/all/singer.log';

if (!file_exists($file_path)){

touch($file_path);

}

$html_str = $this->sendRequest();

$typeUrlsMap = $this->getSingerHomeUrl($html_str);

foreach ($typeUrlsMap as $type

=>$urls){

foreach ($urls as $url){

//***这个段代码为什么这样写后续在进行讲解***

//***先立一个flag***

//-------------FLAG1--------------

$home_html_str = $this->sendRequest($url);

do{

$home_html_str = $this->sendRequest($url);

if (empty($home_html_str)) {

Log::addLog('账号被封,证在等待解封,当前的时间戳'.time(),Log::WARNING);

sleep(1);

}

}while(empty($home_html_str));

//-------------FLAG1--------------

Log::addLog('正常运行['.$type.']......',Log::WARNING);

$this->getSingerInfoByHomeHtml($home_html_str,$type,$url);

}

}

}

/**

* 获取歌手的信息,通过解析HTML字符串

* @param $html_str HTML字符串

* @param null $type 歌手类型

* @return array

*/

function getSingerInfoByHomeHtml($html_str,$type=null,$url=null){

$dom = HtmlDomParser::str_get_html($html_str);

$elems = $dom->find('li');

$rltSingerArr = [];

foreach ($elems as $key => $value){

$aas = $value->find('a');

foreach ($aas as $k=>$v){

//根据上面分析我们很容易得到每个歌手的首页地址

$id = trim(trim($v->href),"/artist?id=");

if (strpos(trim($v->href),'/artist?id=') !== false && is_numeric($id) && !empty($v->text())){

$name = $v->text();

$href = BASE_URL.trim($v->href);

$singerInfoArr = [$id,$name,'',$href,'1090',$type];

$rltStr = implode("\t",$singerInfoArr);

$rltSingerArr[] = $rltStr;

//将获取的歌手信息写入文件

file_put_contents(APP_PATH.'/all/singer.log',$rltStr.PHP_EOL,FILE_APPEND) && $this->getSongAndMvInfo($href,$id);

}

}

}

return $rltSingerArr;

}

//我们以同样的方法获取到每一首歌的URL构成

//拼接处每一首歌的URL,然后获取他的详细信息

//在上面的函数里

function getSongAndMvInfo($url=null,$id=null){

$html_str = null;

do{

$html_str = $this->sendRequest($url);

if (empty($html_str)) {

Log::addLog('请求歌手主页账号被封['.$url.'],waitting.....'.time(),Log::WARNING);

sleep(1);

}

}while(empty($html_str));

Log::addLog('歌手获取URL正常运行['.$url.']',Log::WARNING);

$dom = HtmlDomParser::str_get_html($html_str);

$elems = $dom->find('textarea');

$jsonArr = [];

$arr = [];

foreach ($elems as $elem_a){

if ($elem_a->style == "display:none;" && !$elem_a->has_child() && empty($elem_a->id) && empty($elem_a->name)){

$jsonStr = $elem_a->text();

$jsonArr = $this->jsonToArray($jsonStr);

$this->formatOutput($jsonArr,APP_PATH.'/all/song.log',$id);

}

}

}

//格式化输出

function formatOutput($jsonArr,$fileName,$id){

if (!file_exists($fileName)){

touch($fileName);

}

foreach ($jsonArr as $song){

$arr = [$song['id'],$song['name'],$id,'',SONG_BASE_URL.$song['id'],'1090','',MV_BASE_URL.$song['mvid']];

file_put_contents($fileName,implode("\t",$arr).PHP_EOL,FILE_APPEND) ;

}

}

function jsonToArray($json_str,$isObj=true){

return json_decode($json_str,$isObj);

}

解释一下FLAG1

在实际测试中,发现网易云会进行封IP,因为我们请求太频繁,但是在封了账号以后,会在在几秒以后解封账号。

总结一下:

1、分析网页构成。

2、设计字符获取算法。

后期优化

上面存在的问题

1、直接阻塞式的获取歌手和歌曲的信息

2、如果中间出现了问题,还要从头开始爬,无法从断点处继续爬。

针对上述的问题得出解决方案:

1、多进程异步处理。

先获取歌手信息,存入多个文件,或者数据库。然后主进程开启多个子进程进行处理。

2、设置异常函数句柄,在回调函数里面保存状态。

register_shutdown_function(callback $funcName)

还需要进一步完善。

php 获取字符串首歌,PHP爬虫 网易云音乐歌手和热门歌曲信息抓取相关推荐

  1. python爬虫入门——QQ音乐歌手照片及歌曲列表爬取

    #刚入门,大佬莫入 #程序功能:输入歌手名称后,程序会生成一个Word文件,Word文件里包括歌手名称.照片和所有歌曲列表! import requests, time import math fro ...

  2. python3爬虫(4):获取网易云音乐歌手所有歌曲及歌曲的精选评论

    1. 需要的python包 >pip install pycryptodome >pip install requests >>pip install lxml 2. 实践1: ...

  3. python爬虫No.1|爬取网易云音乐歌手的前50首歌曲ID及名字

    自学pythonのNo.5 引语 知识总结 Requests XPath 案例 曾经有这样的梗黑网易云音乐 实际上网易云是很不错的音乐软件之一.这个梗挺让我不舒服的,挫折谁都有,矫情没必要但对矫情之人 ...

  4. python爬虫----网易云音乐歌曲爬取并存入Excel

    因为数据要存入Excel中,所以首要目标是找个办法将数据能够存入excel中 经过在网上一番搜索后,发现用python里的xlwt模块可以比较容易的解决 一.准备工作 1.安装xlwt模块: 可以看h ...

  5. 微信状态听歌怎么添加歌曲 微信状态听歌如何设置网易云音乐

    微信状态听歌最近又被大家玩火了,在前天,网易云和微信来了波梦幻联动,网易云音乐能在微信上直接播放了,那么,微信状态听歌怎么添加歌曲? 微信状态听歌如何设置网易云音乐?下面就一起来看看吧. 微信状态听歌 ...

  6. Python爬取网易云音乐歌手歌曲和歌单(爬虫)

    Python爬取网易云音乐歌手歌曲和歌单 是 仅供学习参考 Python爬取网易云音乐网易云音乐歌手歌曲和歌单,并下载到本地 ①找到要下载歌手歌曲的链接,这里用的是: https://music.16 ...

  7. CSS——网易云音乐首页之热门推荐歌单的制作

    文章目录 前言 一.结构的布局 二.实现过程 1.HTML结构 2.CSS样式 总结 前言 本文主要讲述了网易云音乐首页的热门推荐歌单部分的实现过程,我将从先分析大致结构与布局,其次书写样式的顺序进行 ...

  8. [爬虫]Python爬取网易云音乐搜索并下载歌曲!

    Python爬取网易云音乐搜索并下载歌曲! 文章目录 Python爬取网易云音乐搜索并下载歌曲! 1.准备工作 2."实地"观察 3.开始码代码! 4.搜索并下载 结束语 1.准备 ...

  9. 解锁网易云音乐客户端变灰歌曲

    解锁网易云音乐客户端变灰歌曲 最近周杰伦出新歌了,可是最喜欢的网易云木有版权?为了听歌不得不安装多个音乐播放器?喜欢的歌还要收费开会员?这里安利一个超好用的方法,以上问题通通搞定!在分享之前首先分享原 ...

最新文章

  1. 第三十五课.基于贝叶斯的深度学习
  2. 基于Spring可扩展Schema提供自定义配置支持
  3. 一个具有多模型融合能力的网络或许是这样的
  4. Flink从入门到精通100篇(二十)-跨境电商 Shopee 的实时数仓之路
  5. CVPR 2020 《12-in-1: Multi-Task Vision and Language Representation Learning》论文笔记
  6. vite打包编译后类名混淆冲突问题处理
  7. hashmap java 便利_java遍历HashMap的高效方法
  8. Android Exception 8(Couldn't read row 0, col -1 from CursorWindow)
  9. 计算机组成原理2(PCI总线结构框图)
  10. 在ionic这个框架下(Angular JS),对URL进行重写,过滤掉URL中的#号
  11. oc76--NSMutableDictionary
  12. 江西6地列入国家智慧城市试点 智慧城市啥模样专家来描绘
  13. NOIP 2017 PJ
  14. 数据可视化--实验三:空间可视化
  15. 大盘点!关于无线AP的实用技术,看这篇就够了
  16. HNOI 2015 亚瑟王 题解
  17. day2 编码与基本数据类型转换
  18. rust怎么拆除墙壁指令_腐蚀有什么指令?基本指令及服务器指令汇总
  19. 2.8w即可拥有仿拼多多商城APP
  20. python 股票指标库talib_Python进阶量化交易专栏场外篇19-建立基于TA-Lib的指标库

热门文章

  1. Unity使用Isometric Z As Y Tilemap创建2.5D地图(二)如何按照正确遮挡顺序渲染图片
  2. python编程语言介绍-编程语言及python介绍
  3. java lru_LRU的理解与Java实现
  4. microbit和python_Microbit MicroPython 介绍
  5. C++一本通题库1005
  6. 简述CISC、RISC、RISC-V、MIPS
  7. android标题栏添加按钮_如何从iPhone或Android设备访问PC
  8. 小程序获取节点绑定数据data-index的方法
  9. 如何将明细数据关联对照表后生成汇总统计表
  10. 用Excel数据透视表快速地统计各部门的男女比例