selenium抓取网易云音乐评论及歌曲信息

最近在研究springboot,就想着结合爬虫做个网易云音乐在线搜索的功能,先上波效果图把

抓取使用的是selenium+chormedriver,也试过phantomsjs,但是对于页面的元素等待好像不支持,加上chromedriver有无界面模式,所以就选择这种搭配方式。抓取的时候首先按是设置chormedriver的路径与无界面模式,需要放在电脑chorme浏览器的安装目录下

代码语言:javascript
复制
 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切换

代码语言:javascript
复制
  //切换到内嵌iframe中
        driver.switchTo().frame("g_iframe");

接下来就是对搜索列表的内容dom结构分析,首先确定外层容器class=srchsongst,里面的各条数据的class为以item开头,后面加标识的div

代码语言:javascript
复制
 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

代码语言:javascript
复制
 String songid =  song.findElement(By.cssSelector("div:nth-child(1)")).
findElement(By.tagName("a")).getAttribute("data-res-id");

下面还要获取歌曲的url(用来进一步获取评论),歌曲名称,作者,专辑,时间,采用常规的css选择器就可以

代码语言:javascript
复制
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栏进行切换,看下代码

代码语言:javascript
复制
//歌手
        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,先进行一系列设置

代码语言:javascript
复制
  //抓取网页
        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

代码语言:javascript
复制
 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