java的段子_java爬取捧腹网段子(多线程版)

本文介绍了如何通过实现Callable接口,创建多线程爬虫,提高爬取网页内容的速度。通过AtomicInteger保证线程安全,使用ExecutorService提交任务,Future获取返回结果,最终统一写入文件。实验结果显示,多线程版本显著提升了爬取效率。
摘要由CSDN通过智能技术生成

上一篇文章讲述了如何使用Java爬取内容并写入文件,但是速度堪忧,今天将代码搞成了多线程版本,

具体方式如下:

新建一个splider类,继承callable接口,用于存放我们需要多线程执行的逻辑:

将上一篇文章中爬取网页内容的代码搬过来

public class Splider implements Callable {

// 使用atomicInteger保证共享变量的安全自增

private AtomicInteger pageNum = new AtomicInteger(0);

@Override

public StringBuilder call() throws Exception {

// 当前页码

Integer privateNum = this.pageNum.addAndGet(1);

// 存储当前页的文本

StringBuilder currentPageText = new StringBuilder();

System.out.println("正在爬取第" + privateNum + "页内容。。。");

String html = ConnectionUtil.Connect("https://www.pengfu.com/xiaohua_" + privateNum + ".html");

Document doc = Jsoup.parse(html);

Elements titles = doc.select("h1.dp-b");

for (Element titleEle : titles) {

Element parent = titleEle.parent();

String title = titleEle.getElementsByTag("a").text();

String author = parent.select("p.user_name_list > a").text();

String content = parent.select("div.content-img").text();

// 将内容格式化

currentPageText.append(title)

.append("\r\n作者:").append(author)

.append("\r\n").append(content)

.append("\r\n").append("\r\n");

}

currentPageText.append("-------------第").append(privateNum).append("页-------------").append("\r\n");

System.out.println("第" + privateNum + "页内容爬取完毕。。。");

// 将当前页内容返回给future对象

return currentPageText;

}

}

主函数:

public static void main(String[] args) throws ExecutionException, InterruptedException {

long startTime = System.currentTimeMillis();

// 创建大小为5的线程池

ExecutorService esPool = Executors.newFixedThreadPool(5);

List> futureList = new ArrayList<>();

Splider splider = new Splider();

for (int i = 1; i <= 10; i++) {

futureList.add(esPool.submit(splider));

}

List finishCount = new ArrayList<>();

for (Future future : futureList) {

// 线程结束,将线程返回的内容添加到list

finishCount.add(future.get());

}

/*

* 所有内容爬取完毕,将内容统一写入磁盘

*/

if (finishCount.size() == 10) {

StringBuilder allText = new StringBuilder();

/*

* finishCount中future.get()的顺序 和 futureList中的future顺序一致

* 所以内容是从第1页...第N页顺序写入

*/

for (StringBuilder pageNum : finishCount) {

allText.append(pageNum);

}

// 写入磁盘

Test.writeToFile(allText.toString());

long endTime = System.currentTimeMillis();

System.out.println("耗时 : " + (endTime - startTime));

// 关闭线程池

esPool.shutdownNow();

}

}

执行结果:

77b6f0195932d7808eb90c21a30b08d8.png

查看本地文件,顺序和内容也都没有问题:

6e3ee8426e73d357d1410aa4e2152e53.png

总结:

多个线程共享变量,只new一个实例,传给多个线程使用;

可以使用atomit类、synchronized、volitaile、lock保证多线程共享变量的安全性;

future.get()顺序和executorService.submit()顺序一致,和谁先执行完毕无关

使用callable + future可以获取线程返回值、捕获;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值