最近在研究springboot,就想着结合爬虫做个网易云音乐在线搜索的功能,先上波效果图把
抓取使用的是selenium+chormedriver,也试过phantomsjs,但是对于页面的元素等待好像不支持,加上chromedriver有无界面模式,所以就选择这种搭配方式。抓取的时候首先按是设置chormedriver的路径与无界面模式,需要放在电脑chorme浏览器的安装目录下
String loadurl = MessageFormat.format("https://music.163.com/#/search/m/?s={0}&type=1", URLEncoder.encode(musicname));
String DRIVER_PATH = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe";
System.setProperty("webdriver.chrome.driver",DRIVER_PATH);
ChromeOptions opt = new ChromeOptions();
//使用谷歌的无头模式 PhantomJS后续高版本不在收到seleunim的支持,且开源暂停开发
opt.addArguments("headless");
WebDriver driver = new ChromeDriver(opt);
然后访问网易云音乐主页,其中的url是通过构造搜索形式的地址直接访问,type=1是指歌曲搜索,注意网页中的搜索列表内容部分是内嵌的iframe,需要进行浏览器的dom切换
//切换到内嵌iframe中
driver.switchTo().frame("g_iframe");
接下来就是对搜索列表的内容dom结构分析,首先确定外层容器class=srchsongst,里面的各条数据的class为以item开头,后面加标识的div
List<WebElement> songlist = driver.findElement(By.className("srchsongst")).
findElements(By.cssSelector("div[class^='item']"));
定位到行之后,需要对歌曲的各个列进行元素抽取,首先获取歌曲id,这个id后面有作用,因为歌曲id的div没有特别唯一的class或者其他属性,不能靠常规的css选择来定位,找寻顾虑后,发现id的容器始终是行数据的第1个div,所以可以采用chidren列表的方式取到目标div
String songid = song.findElement(By.cssSelector("div:nth-child(1)")).
findElement(By.tagName("a")).getAttribute("data-res-id");
下面还要获取歌曲的url(用来进一步获取评论),歌曲名称,作者,专辑,时间,采用常规的css选择器就可以
String url = URLEncoder.encode(song.
findElement(By.cssSelector("div[class$='w0']")).findElement(By.tagName("a")).getAttribute("href"));
String musciname = song.findElement(By.cssSelector("div[class$='w0']")).
findElement(By.tagName("b")).getAttribute("title");
String author = song.findElement(By.cssSelector("div[class$='w1']")).
findElement(By.className("text")).getText();
String album = song.findElement(By.cssSelector("div[class$='w2']")).
findElement(By.tagName("a")).getText();
String time = song.findElement(By.cssSelector("div:nth-child(6)")).getText();
获取其他三个栏位,歌手专辑,歌单原理差不多,只需要模拟鼠标事件点击tab栏进行切换,看下代码
//歌手
driver.findElement(By.cssSelector("a[data-type='100']")).click();
//等待页面数据加载完成
WebDriverWait wait = new WebDriverWait(driver, 20);
//com.google.guava版本问题引起的传入函数条件不满足泛型
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("ul[class^='m-cvrlst']")));
List<WebElement> authorinfolist = driver.
findElement(By.cssSelector("ul[class^='m-cvrlst']")).findElements(By.cssSelector("div[class^='u-cover']"));
List<AuthorInfo> authorlist = new ArrayList<AuthorInfo>();
for(WebElement author:authorinfolist){
AuthorInfo authorInfo = new AuthorInfo();
String imageurl = author.findElement(By.tagName("img")).getAttribute("src");
String authorname = author.findElement(By.tagName("span")).getAttribute("title");
authorInfo.setAutorname(authorname);
authorInfo.setImageurl(imageurl);
authorlist.add(authorInfo);
}
其中a[data-type='100']代表的就是栏目标签,type的值不同代表栏位不同,wait.unti方法就是之前所说的等待页面某个元素加载的方法,因为切换栏位可能由于ajax加载或者页面的数据部分刷新,可能数据没有完全展示出来就进行dom分析,导致数据抓不到,其他2个栏目抓取方法大同小异,最后会给大家贴上源码地址。
抓取完毕列表,就可以开始访问歌曲详细页面进行评论抓取了,老规矩,先分析dom结构,这边因为不需要等待元素,所以使用了phantomjs,先进行一系列设置
//抓取网页
DesiredCapabilities dcaps = new DesiredCapabilities();
//ssl证书支持
dcaps.setCapability("acceptSslCerts", true);
//截屏支持
dcaps.setCapability("takesScreenshot", true);
//css搜索支持
dcaps.setCapability("cssSelectorsEnabled", true);
//js支持
dcaps.setJavascriptEnabled(true);
try {
//驱动支持
dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY,
ResourceUtils.getURL("src/main/resources/static/plugins/phantomjs/").getPath()+"phantomjs.exe");
}catch (Exception e){
System.out.println("phantomjs error");
e.printStackTrace();
}
//创建无界面浏览器对象
PhantomJSDriver driver = new PhantomJSDriver(dcaps);
driver.get(url);
//切换到内嵌iframe中
driver.switchTo().frame("g_iframe");
首先定位外层容器地div class=m-cmmt,再到行数据div class=itm,再定位到最底层容器cntwrap,评论内容是以cnt开头class的div,评论时间是time开头class的div
String nickname = content.findElement(By.tagName("a")).getText();
String commentcontent =content.findElement(By.cssSelector("div[class^='cnt']")).
getText().replace(nickname+":","");
String commentdate = content.findElement(By.cssSelector("div[class^='time']")).getText();
上个效果图
最后讲下下载功能,网易云有一个外链播放地址http://music.163.com/song/media/outer/url?id=,id后面传之前我们获取到的歌曲id就可以,打开是个外链播放器,直接下载既可以
注:chromedriver和电脑安装的浏览器版本要一致,下面给出对应列表连接
对应列表:https://blog.csdn.net/yoyocat915/article/details/80580066
驱动列表:http://npm.taobao.org/mirrors/chromedriver/
源码地址
前端:https://github.com/grassprogramming/yblog/tree/master/main/resources/static/pages/spider/music
后端:https://github.com/grassprogramming/yblog/tree/master/main/java/com/blog/spider/controller