之前的博客已经讲解了多线程的使用,以及用HttpClient爬取网页内容,现在我们将两者结合起来使用,多线程爬取网页资源。
之前的博客链接:
当我们要爬取大量网站的时候,单线程明显上爬取的效率会慢很多,此时如果使用了多线程爬取,我们的程序爬取速率会翻倍。
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.8version>
dependency>
<dependency>
<groupId>org.jsoupgroupId>
<artifactId>jsoupartifactId>
<version>1.10.2version>
dependency>
解释说明:这里我们List集合用于存储我们要爬取的网站
package com.hmdp.httpclienTest.ThreadReload.util;
import com.hmdp.utils.ThredQuery;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadHttpClientUtil {
public static void main(String[] args) throws Exception {
//将要爬取的url存在list集合里
List<String> webs = new ArrayList<>();
webs.add("https://taolitop.com/");
webs.add("https://taolitop.com/jj.whtml");
webs.add("https://taolitop.com/dzhrjsjykf.whtml");
webs.add("https://taolitop.com/zxns.whtml");
List<String> result = ThreadHttpClientUtil.getMultiCombineResult(webs);
int i=1;
for (String html : result) {
System.out.println("第"+i+"个网页内容");
System.out.println(html);
i++;
}
}
/**
* 获取多线程结果并进行结果合并
* @return
*/
public static List<String> getMultiCombineResult(List<String> webs) throws Exception {
//开始时间
long start = System.currentTimeMillis();
//返回结果
List<String> result = new ArrayList<>();
List<Callable<String>> tasks = new ArrayList<>();
for (int i = 1; i <= 4; i++) {
Callable<String> qfe = new ThreadQueryReload(webs.get(i-1));
tasks.add(qfe);
System.out.println(i);
System.out.println(webs.get(i-1));
}
try{
//定义固定长度的线程池 防止线程过多,4就够用了
//4条数据,分成4个线程来查询
ExecutorService executorService = Executors.newFixedThreadPool(4);
//Future用于获取结果
List<Future<String>> futures=executorService.invokeAll(tasks);
//处理线程返回结果
if(futures!=null&&futures.size() > 0){
for (Future<String> future:futures){
result.addAll(Collections.singleton(future.get()));
}
}
//关闭线程池,一定不能忘记
executorService.shutdown();
}catch (Exception e){
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("线程查询数据用时:"+(end-start)+"ms");
return result;
}
}
我们以创建4个线程为例,每一个线程去爬取一个网站,这里如果你有大量的数据,可以重新设计,让每一个线程去爬取多个网站,提高效率。我的以每个线程爬取一个网站为例:
import com.hmdp.httpclienTest.HttpClientT4;
import java.util.concurrent.Callable;
public class ThreadQueryReload implements Callable<String> {
//每个线程查询出来的数据集合
private String datas;
public ThreadQueryReload(String url) throws Exception {
String html = HttpClientT4.resultHtml(url);
datas=html;
}
@Override
public String call() throws Exception {
return datas;
}
}
此时:我们将会爬取到每一个网页的内容,同时呢也提高了效率。