说到爬虫,第一个想到的编程语言大都是Python,的确,在爬取网络资源方面,Python确实有着巨大的优势,但是在爬取一些小的资源,比如说一个视频、音频、图片等比较单一的资源的时候,java也是完全可以胜任的,下面我就来介绍一下使用java基础来爬取一些网络资源。
在java.net包下封装了很多关于网络方面的类,他们使用的技术是比较成熟的,他屏蔽了嶙峋的网络连接方面的操作,提供给开发人员一个比较友好的开发接口。java.net包中有一个功能强大的类URL,他代表的就资源地址,通过他可以得到一个输入流对象,从而将资源下载到内存或磁盘中。
我们可以通过URL url = new URL(strURL);获取一个URL对象,再根据InputStream is = url.openStream();获取一个输入流对象。我们只需要这两个简单的操作,就能下载网络上的很多资源了。下面是我自己实现一个java爬虫的例子。
首先我们找到一个素材源网站,这里我找到的是一个音频素材网https://www.huiyi8.com/yinxiao/。
至于为什么要爬取音频素材,以后有机会在给大家介绍。
按下F12,打开调试界面(推荐大家使用Google、Firefox浏览器),找到media,看资源的URL。这就是我们构造URL对象时用的字符串。
这个是通过手动找到的,这样只能一个一个的爬取,速度太慢。如果我们想要找到这个网页里所有的音频文件的URL,打开网站的源代码Ctrl+U。
我们会得到这样的源代码,这个也是该资源的文本表示。我们可以通过先获得该资源的源码,再通过解析其中mp3格式的字符串,就能得到对应的资源文件,通过下面的文件名称能够得到文件的名字。我们将一个网页的所有的mp3资源存到一个map集合中,用资源地址和文件名称表示key和value。
然后我们再根据URL,通过map获取这些资源的地址以及文件名,就能够以文件的形式保存到本地了。
以下是我的代码:
package python;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Demo03python extends Thread{
public static int threadCount;
private int page;//表示下载多少页
private int folder;//表示多少套
public static int getThreadCount() {
return threadCount;
}
public static void addThreadCount() {
threadCount++;
}
public static void lessenThreadCount() {
threadCount--;
}
public Demo03python(int page) {
super();
this.page = page;
this.folder = (page/100)+1;
}
public Demo03python() {
super();
// TODO Auto-generated constructor stub
}
public Demo03python(Runnable target, String name) {
super(target, name);
// TODO Auto-generated constructor stub
}
public Demo03python(Runnable target) {
super(target);
// TODO Auto-generated constructor stub
}
public Demo03python(String name) {
super(name);
// TODO Auto-generated constructor stub
}
public Demo03python(ThreadGroup group, Runnable target, String name, long stackSize) {
super(group, target, name, stackSize);
// TODO Auto-generated constructor stub
}
public Demo03python(ThreadGroup group, Runnable target, String name) {
super(group, target, name);
// TODO Auto-generated constructor stub
}
public Demo03python(ThreadGroup group, Runnable target) {
super(group, target);
// TODO Auto-generated constructor stub
}
public Demo03python(ThreadGroup group, String name) {
super(group, name);
}
@Override
public void run() {
super.run();
addThreadCount();
System.out.println("当前下载线程数:"+threadCount);
System.out.println("第"+page+"页开启线程开始下载");
String pageUrl = "https://www.huiyi8.com/yinxiao/"+page+".html";
Map<String, String> map = analysis(pageUrl);
//先为每一页都创建一个文件夹,每个网页下载的内容都放到这个文件夹中
String folderName = "第"+folder+"套//"+"第"+page+"页";
File folder = new File(folderName);
folder.mkdirs();
//遍历map集合
Set<Entry<String, String>> entrySet = map.entrySet();
Iterator<Entry<String, String>> iterator = entrySet.iterator();
while(iterator.hasNext()) {
Entry<String, String> next = iterator.next();
//key是资源地址,value是文件名称
String key = next.getKey();
String value = next.getValue();
download(key,folderName+"//"+value);
}
lessenThreadCount();
System.out.println("当前下载线程数:"+threadCount);
}
//使用一个解析的方法,可以将得到的HTML文件解析成一个map集合
//map集合中包含了key(文件名file)和value(音频的urlStr)
public static Map<String,String> analysis(String pageUrl){
Map<String,String> map = new HashMap<String,String>();
try {
URL url = new URL(pageUrl);
InputStream is = url.openStream();
Scanner sc = new Scanner(is,"utf-8");
int l = 0;
String key = null;
String value = null;
while(sc.hasNext()) {
// mp3的文件是这样的:thumb="urlStr" 得到urlStr
// 文件名是这样的:target="_blank">file</a> 得到file
String thumb = ".*thumb.*";
String target = ".*<div.*html\" target=\"_blank\">.*</a>.*";
String result = sc.nextLine();
//如果包含了thumb或者包含了target的话,就打印出来字符串
if(Pattern.matches(thumb, result)||Pattern.matches(target, result)) {
// System.out.println(result);
l++;
}
//匹配mp3文件资源
if(Pattern.matches(thumb, result)) {
Pattern pattern = Pattern.compile("http.*mp3" );
Matcher matcher = pattern.matcher(result);
if(matcher.find()) {
String group = matcher.group(0);
key = group;
}else {
key = result;
}
}
//匹配文件名
if(Pattern.matches(target, result)) {
Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher matcher = pattern.matcher(result);
if(matcher.find()) {
String group = matcher.group(0);
value = group+".mp3";
}else {
value = result;
}
map.put(key, value);
}
}
System.out.println(l);
sc.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
System.out.println("IO流打开失败。");
e.printStackTrace();
}
return map;
}
//一个方法,传入路径,下载文件到本地
public static void download(String urlStr,String file) {
InputStream is = null;
OutputStream os = null;
try {
URL url = new URL(urlStr);
is = url.openStream();
os = new FileOutputStream(file);
int t;
while((t = is.read())!=-1) {
os.write(t);
}
System.out.println("文件"+file+"下载成功!");
} catch (Exception e) {
System.out.println("文件"+file+"下载失败!");
}finally {
try {
if(is!=null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(os!=null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package python;
public class Demo04python {
public static void main(String[] args) {
for(int i = 544;i<=1920;i++) {
Demo03python t = new Demo03python(i);
t.start();
}
}
}
在测试的时候我通过一个多线程执行下载的,在网络上进行操作的时候一般都是用的是多线程的方式,大大加快程序速度外还能避免某个资源阻塞导致程序停滞不前。
最后得到的文件目录
具体思路就是这样,我通过这样的一个方法爬取了该网站的四万多个音频文件,一共16G+,大家可以自己试试,或者看看我下的资源。https://download.csdn.net/download/qq_41803278/12201496