Java爬取网易云音乐民谣并导入Excel分析

前言

考虑到这里有不少人没有接触过Java网络爬虫,因此我会从很基础的Jsoup分析HttpClient获取的网页讲起。了解这些东西能够直接看后面的“正式进入案例”,跳过前面这些基础。我导入的是“Excel转换工具XXL-EXCEL”这个开源项目而后在这个基础上写的这个Demo(下面会详细分析).看了这篇文章还有问题,记得给我留言我会尽力帮你解决。若是文章哪里有问题或者须要改进,也请留言告诉我,共同进步。html

项目分析

几天前用HttpClien+Jsoup把网易云音乐的民谣抓取下来,惋惜显示效果是下面这样的: java

没有导入Excel以前
想着若是能像前几天用开源的爬虫爬取知乎后而后导入Excel简单分析也好一点,以下图(下图只是简单的对导入进去的一我的的关注者作了一个排序):
知乎爬虫Excel分析
经过查阅文档知道Apache下有一个专门操做office各类文档的API: POI,用这个API的话操做起来原理也很简单,可是很麻烦须要写不少代码,并且条理也不是很清楚。因此去Github上找了找有没有更方便的方法,Github有不少关于这方面的开源项目,通过各类尝试,最终选择了: 《Java对象和Excel转换工具XXL-EXCEL》,经过这个框架能够灵活的进行Java对象和Excel文档相互转换。

而后最终就是下面这个效果: node

网易云Excel分析

案例基础

①Jsoup解析网页分析

Maven依赖:git

<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
		<dependency>
			<groupId>org.jsoup</groupId>
			<artifactId>jsoup</artifactId>
			<version>1.7.2</version>
		</dependency>
复制代码

请求网页和解析网页,咱们都以推酷网:www.tuicool.com/为例子。 先看一个实例(本实例获取的是推酷网首页的热门文章的信息):github

package news;

import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class TuicoolHotArticles {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		String url = "https://www.tuicool.com/";
		Document document = Jsoup.connect(url)
				.userAgent("Mozilla/5.0 (Windows NT 6.1; rv:30.0) Gecko/20100101 Firefox/30.0").get();

		// #id: 经过ID查找元素,好比:#logo
		Elements items = document.select(".list_article_item ");
		System.out.println(items.size());
		for (Element item : items) {
			// 标题。(类名title下的 a标签的title属性获取)
			String title = item.select(".title a").attr("title");
			// 标题图片地址(类名article_thumb_image下的 img标签的src属性获取)
			String picture_href = item.select(".article_thumb_image img").attr("src");
			// 时间 。(类名tip下的最后一个span标签的文字获取)
			String date = item.select(".tip span").last().text();
			// 做者 。(类名tip下的第一个span标签的文字获取)
			String author = item.select(".tip span").first().text();

			System.out.println("标题: " + title);
			System.out.println("标题图片地址:" + picture_href);
			System.out.println("发布日期 " + date);
			System.out.println("做者 " + author);
			System.out.println();
			System.out.println();
		}
	}

}

复制代码

实例结果: apache

结果
实例分析:

  1. 网页元素分析

元素位置->右键->查看元素(Inspent Element) 浏览器

查看元素
2. Jsoup解析 经过元素分析咱们便可获取所在div类名以及元素的其余属性,经过这些属性咱们便可获取该元素。上面代码我已经给你详细的注释,若是还有问题能够留言给我。

若是想了解更详细的Jsoup操做请查看 jsoup中文文档bash

②HttpClient请求网页分析

Maven依赖:网络

<!-- httpclient -->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.5.4</version>
		</dependency>
复制代码

下面是一个获取推酷首页源代码的例子:app

package www.java1234.com.httpclientDemo2;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

/** * TODO 在www.java1234.com.httpclientDemo.HelloWorld2咱们获取推酷网热门文章 * 咱们这里经过模拟浏览器的方法来从新获取 * * @date 2017年12月16日 */
public class GetTuicoolHotArticles {

	public static void main(String[] args) throws ClientProtocolException, IOException {
		// TODO Auto-generated method stub
		CloseableHttpClient httpClient = HttpClients.createDefault(); // 建立httpClient实例
		HttpGet httpGet = new HttpGet("https://www.tuicool.com/"); // 建立httpget实例
		// 设置请求头信息Uer-Agent模拟浏览器
		httpGet.setHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0");
		CloseableHttpResponse response = httpClient.execute(httpGet); // 执行httpget请求
		// 获取响应状态
		//System.out.println("响应状态为:" + response.getStatusLine());
		HttpEntity entity = response.getEntity(); // 获取返回实体
		 System.out.println("网页内容:" + EntityUtils.toString(entity, "utf-8"));
		// 获取响应内容类型Content-Type
		// System.out.println("content-type:" + entity.getContentType());
		response.close(); // response关闭
		httpClient.close(); // httpClient关闭
	}

}
复制代码

这个例子有一点须要说明的是由于推酷网设置了简单的反爬因此咱们这里必须设置请求头信息Uer-Agent模拟浏览器访问,代码已经注释。

若是想深刻学习HttpClient,请查看HttpClient官网

③Maven的简单使用

网上有不少这面的教程,并且Maven这个工具真的很实用,不会的能够在网上找一找教程。再不会留言找我,我教,😁嘿嘿。

正式进入本案例

完整源码下载:github.com/Snailclimb/… XXL-EXCEL的Maven依赖

<!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-excel-core/ -->
<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-excel</artifactId>
    <version>1.0.0</version>
</dependency>
复制代码

我一共新建了三个类:

类结构
Wangyiyun.java:网易云音乐实体类。

WangyiyunMinyao.java:网易云音乐工具类,用于获取存放歌曲对象打得Arraylist集合。

TestWangyiyun.java:测试类,测试获取网易云音乐民谣信息而且输出到Excel中。 由于一次抓取的是一个页面,因此抓取到控制台有输出,速度可能有点慢。 Wangyiyun.java

package com.xuxueli.poi.excel.test.model;

import org.apache.poi.hssf.util.HSSFColor;

import com.xuxueli.poi.excel.annotation.ExcelField;
import com.xuxueli.poi.excel.annotation.ExcelSheet;

@ExcelSheet(name = "网易云音乐民谣分析", headColor = HSSFColor.HSSFColorPredefined.LIGHT_GREEN)
public class Wangyiyun {

	@ExcelField(name = "歌曲介绍")
	private String description;

	@ExcelField(name = "歌曲连接地址")
	private String href;

	@ExcelField(name = "歌曲播放次数")
	private int playNums;

	public Wangyiyun() {
	}

	public Wangyiyun(String description, String href, int playNums) {
		this.description = description;
		this.href = href;
		this.playNums = playNums;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getHref() {
		return href;
	}

	public void setHref(String href) {
		this.href = href;
	}

	public int getPlayNums() {
		return playNums;
	}

	public void setPlayNums(int playNums) {
		this.playNums = playNums;
	}

	@Override
	public String toString() {
		return "Wangyiyun [歌曲介绍=" + description + ", 歌曲连接地址=" + href + ", 歌曲播放次数=" + playNums + "]";
	}

}

复制代码

WangyiyunMinyao.java

package utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.xuxueli.poi.excel.test.model.Wangyiyun;
/** * TODO 该类用于获取保存在Arraylist中的歌曲对象 * @date 2017年12月21日 */

public class WangyiyunMinyao {

	/** * 该方法爬取了歌曲标题和连接地址而且调用了GetTheNumberOfPlays()方法用于获取歌曲连接地址页面的详细播放次数 * * @param url_str * @param charset * @throws ClientProtocolException * @throws IOException */
	public static ArrayList<Wangyiyun> Crawl(String url_str, String charset) throws ClientProtocolException, IOException {
		// 获取
		CloseableHttpClient hc=HttpClients.createDefault();
		//HttpClient hc = new DefaultHttpClient();
		HttpGet hg = new HttpGet(url_str);
		HttpResponse response = hc.execute(hg);
		HttpEntity entity = response.getEntity();

		InputStream htm_in = null;
		ArrayList<Wangyiyun> arrayList = new ArrayList<>();
		if (entity != null) {
			htm_in = entity.getContent();
			String htm_str = InputStream2String(htm_in, charset);
			Document doc = Jsoup.parse(htm_str);
			Elements links = doc.select("div[class=g-bd]").select("div[class=g-wrap p-pl f-pr]")
					.select("ul[class=m-cvrlst f-cb]").select("div[class=u-cover u-cover-1");
			for (Element link : links) {
				Elements lin = link.select("a");
				// 歌曲描述
				String description = lin.attr("title");
				// 歌曲连接地址
				String href = lin.attr("href");
				href = "http://music.163.com" + href;
				/* * System.out.print(re_title + " "); * System.out.print(re_url + " "); int nums = * GetTheNumberOfPlays(re_url, charset); */
				int nums =GetTheNumberOfPlays(href, charset);
				Wangyiyun wangyiyun = new Wangyiyun(description, href, nums);
				arrayList.add(wangyiyun);
			}
		}
		return arrayList;
	}

	/** * 该方法爬取歌曲连接地址页面的播放次数 * * @param url_str * @param charset * @throws ClientProtocolException * @throws IOExceptionGet * the number of plays */
	public static int GetTheNumberOfPlays(String url_str, String charset) throws ClientProtocolException, IOException {
		CloseableHttpClient hc=HttpClients.createDefault();
		HttpGet hg = new HttpGet(url_str);
		HttpResponse response = hc.execute(hg);
		HttpEntity entity = response.getEntity();

		InputStream htm_in = null;
		int nums = 0;
		if (entity != null) {
			htm_in = entity.getContent();
			String htm_str = InputStream2String(htm_in, charset);
			Document doc = Jsoup.parse(htm_str);
			String links = doc.select("div[class=u-title u-title-1 f-cb]").select("div[class=more s-fc3]")
					.select("strong").text();
			nums = Integer.parseInt(links);
		}
		return nums;
	}

	/* * public static void saveHtml(String filepath, String str) { * * try { OutputStreamWriter outs = new OutputStreamWriter(new * FileOutputStream(filepath, true), "utf-8"); * outs.write("http://www.dailystrength.org" + str + "\r\n"); outs.close(); * } catch (IOException e) { System.out.println("Error at save html..."); * System.out.println(str); e.printStackTrace(); } } */

	public static String InputStream2String(InputStream in_st, String charset) throws IOException {
		BufferedReader buff = new BufferedReader(new InputStreamReader(in_st, charset));
		StringBuffer res = new StringBuffer();
		String line = "";
		while ((line = buff.readLine()) != null) {
			res.append(line);
		}
		return res.toString();
	}
}
复制代码

TestWangyiyun.java

package com.xuxueli.poi.excel.test;

import java.io.IOException;
import java.util.ArrayList;

import org.apache.http.client.ClientProtocolException;

import com.xuxueli.poi.excel.ExcelExportUtil;
import com.xuxueli.poi.excel.test.model.Wangyiyun;

import utils.WangyiyunMinyao;

public class TestWangyiyun {

	public static void main(String[] args) throws ClientProtocolException, IOException {
		int page = 0;
		// 这里只爬取了3页数据
		ArrayList<Wangyiyun> wangyiyunArraylist=new ArrayList<>();
		for (int i = 0; i < 3; i++) {
			// 爬取
			String url_str = "http://music.163.com/discover/playlist/?order=hot&cat=民谣&limit=35&offset=" + page;
			ArrayList<Wangyiyun> arrayList = WangyiyunMinyao.Crawl(url_str, "utf-8");
			wangyiyunArraylist.addAll(arrayList);
			for (Wangyiyun wangyiyun : arrayList) {
				System.out.println(wangyiyun);
			}
			
			/**
			 * Excel导出:Object 转换为 Excel
			 */			
			// page参数加35(这个35是分析民谣栏)
			page = page + 35;
		}
		String filePath = "wangyiyun.xls";
		ExcelExportUtil.exportToFile(filePath, wangyiyunArraylist, wangyiyunArraylist);
	}

}
复制代码

容易出现的错误

导入Maven依赖或者导入个人Maven项目后项目上会有感叹号,这种状况应该是Jar包下载出错。(笔主在这里卡了很长时间)

解决办法:

查看错误->找到出错的Jar->找到对应jar包存放位置->删除该jar包->去官网本身下载。

补充

刚才知道你们可能由于jar包下载错误或者各类问题有问题。 下面是个人项目的效果图。目前已经更新到Github。实在还有问题的能够把个人项目拷贝下来看看。 完整源码下载:github.com/Snailclimb/…(包含导入Excel的工具源码)

效果图
相关文章
相关标签/搜索