【系列教程一】谁说 java 不能做爬虫?我第一个不服!
先做一个调研,现在传统的Java后端非常卷,不太好找工作,大家有没有兴趣用Java搞爬虫(本人就是后端转爬虫),我接下来可以出关于爬虫类的文章,包括ip、js逆向、cookie反爬、请求响应参数加解密、浏览器指纹分析及常见的反爬手段。评论区告诉我!!!
可能大部分用户觉得,数据爬取方面 python 很厉害,其实 java 也很厉害,比如我们今天要介绍的这款工具库:Jsoup。
官方解释如下:
jsoup 是一个用于处理 HTML 的 Java 库。它提供了一些非常方便的 API,用于提取和操作 HTML 页面数据,比如 DOM,CSS 等元素。
由于 jsoup 的 API 方法使用上与 jQuery 极其接近,因此如果你了解过 jQuery,那么可以轻而易举地上手这款框架。
那么如何使用它呢,下面我们一起来看看!
maven:
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.14.2</version>
</dependency>
一、爬取网站图片
在爬取网站图片之前,我们需要分析该网站的结构。我们可以使用浏览器的开发者工具来查看网站的源代码。打开该网站后,我们可以在浏览器的菜单栏中点击“工具”-“开发者工具”,然后切换到“网络”标签,刷新页面,就可以看到该网站的请求。
通过查看请求,我们可以看到该网站的图片是通过以下接口获取的:http://www.cgtpw.com/ctmn/ajax.php?act=ctmn&cat_id=0&page=1。其中,page表示页码。我们可以通过修改page的值来获取不同页的图片。
了解了网站的结构之后,我们就可以开始编写Java程序来爬取该网站的图片了。
二、异步下载图片
在爬取图片时,我们需要注意两个问题:下载图片的数量和下载图片的速度。如果一次性下载大量图片,会占用太多的内存和网络带宽,导致程序运行缓慢。另外,如果下载速度过慢,也会影响程序的运行效率。因此,我们需要采用异步下载的技术来解决这个问题。
Java提供了多种异步下载图片的方式,比如使用线程池、使用Java 8中的CompletableFuture等。本文将介绍使用Java 8中的CompletableFuture来异步下载图片。
首先,我们需要创建一个方法来下载图片。该方法接受一个图片的URL作为参数,返回一个CompletableFuture对象,该对象用于异步下载图片。代码如下:
private static CompletableFuture<Void> downloadImage(String imageUrl) {return CompletableFuture.runAsync(() -> {try {URL url = new URL(imageUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);conn.connect();if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {String fileName = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);File file = new File("images/" + fileName);InputStream inputStream = conn.getInputStream();FileOutputStream outputStream = new FileOutputStream(file);byte[] buffer = new byte[1024];int len = -1;while ((len = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, len);}inputStream.close();outputStream.close();System.out.println("Downloaded: " + fileName);} else {System.out.println("Failed to download: " + imageUrl);}} catch (Exception e) {System.out.println("Failed to download: " + imageUrl + ", " + e.getMessage());
}
});
}
该方法通过异步方式下载图片,并保存到images目录下。如果下载成功,则打印“Downloaded: 文件名”,否则打印“Failed to download: 图片URL”。
接下来,我们需要编写一个方法来批量下载图片。该方法接受一个图片URL列表作为参数,使用CompletableFuture.allOf()方法将所有异步下载任务合并为一个CompletableFuture对象,并使用join()方法等待所有任务完成。代码如下:
private static void downloadImages(List<String> imageUrls) {List<CompletableFuture<Void>> futures = new ArrayList<>();for (String imageUrl : imageUrls) {futures.add(downloadImage(imageUrl));}CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).join();
}
该方法将所有异步下载任务合并为一个CompletableFuture对象,并使用join()方法等待所有任务完成。
三、翻页爬取
由于该网站的图片是分页显示的,因此我们需要编写一个方法来翻页爬取。该方法接受一个页码作为参数,获取该页的图片URL列表,并调用异步下载方法下载图片。代码如下:
private static void crawlPage(int page) {try {String url = "http://www.cgtpw.com/ctmn/ajax.php?act=ctmn&cat_id=0&page=" + page;Document doc = Jsoup.connect(url).get();Elements elements = doc.select("div.list-box img");List<String> imageUrls = new ArrayList<>();for (Element element : elements) {String imageUrl = element.attr("data-src");imageUrls.add(imageUrl);}downloadImages(imageUrls);} catch (Exception e) {System.out.println("Failed to crawl page: " + page + ", " + e.getMessage());}
}
该方法通过Jsoup库获取网页内容,并解析出图片URL列表。然后调用异步下载方法下载图片。如果下载失败,则打印“Failed to crawl page: 页码,错误信息”。
最后,我们可以编写一个main方法来执行翻页爬取的任务。该方法可以指定起始页码和结束页码,循环爬取每一页的图片。代码如下:
public static void main(String[] args) {int startPage = 1;int endPage = 10;for (int i = startPage; i <= endPage; i++) {crawlPage(i);}
}
该方法从startPage开始,循环爬取每一页的图片,直到endPage结束。
四、总结
本文介绍了如何用Java实现爬取http://www.cgtpw.com/ctmn这个网站图片的过程,并采用异步下载和翻页爬取的技术,以提高爬取效率。在爬取网站图片时,我们需要注意下载图片的数量和下载图片的速度,可以采用异步下载的技术来解决这个问题。另外,由于该网站的图片是分页显示的,因此我们需要编写一个方法来翻页爬取。在实际开发过程中,还需要考虑一些其他因素,例如网站反爬机制、网络波动等问题。如果网站有反爬机制,我们可以采用一些反反爬的技术,例如使用代理IP、设置User-Agent等;如果网络波动导致下载失败,我们可以增加重试机制,使程序更加健壮。
完整代码奉上:
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;public class TestCrawler {public static void main(String[] args) {int startPage = 1;int endPage = 10;for (int i = startPage; i <= endPage; i++) {crawlPage(i);}}private final static String savePath = "C:\\\\Users\\\\Administrator\\\\Desktop\\\\image\\\\";private static CompletableFuture<Void> downloadImage(ImageVO imageVO) {return CompletableFuture.runAsync(() -> {try {String imageUrl = imageVO.getImageUrl();URL url = new URL(imageUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);conn.connect();if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {String fileName = imageVO.getName()+imageUrl.substring(imageUrl.lastIndexOf(".") );File file = new File(savePath + fileName);InputStream inputStream = conn.getInputStream();FileOutputStream outputStream = new FileOutputStream(file);byte[] buffer = new byte[1024];int len = -1;while ((len = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, len);}inputStream.close();outputStream.close();System.out.println("Downloaded: " + fileName);} else {System.out.println("Failed to download: " + imageUrl);}} catch (Exception e) {System.out.println("Failed to download: " + imageVO.getImageUrl() + ", " + e.getMessage());}});}private static void downloadImages(List<ImageVO> imageVOList) {List<CompletableFuture<Void>> futures = new ArrayList<>();for (ImageVO imageVO : imageVOList) {futures.add(downloadImage(imageVO));}CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).join();}private static void crawlPage(int page) {try {String url = "http://www.cgtpw.com/ctmn/index_" + page + ".html";Document doc = Jsoup.connect(url).get();Elements elements = doc.select("ul.listBox2 > li > a > img");List<ImageVO> imageUrls = new ArrayList<>();for (Element element : elements) {ImageVO imageVO = new ImageVO();String imageUrl = element.attr("src");String name = element.attr("alt");imageVO.setName(name);imageVO.setImageUrl(imageUrl);imageUrls.add(imageVO);}downloadImages(imageUrls);} catch (Exception e) {System.out.println("Failed to crawl page: " + page + ", " + e.getMessage());}}public static class ImageVO{public String getName() {return name;}public void setName(String name) {this.name = name;}public String getImageUrl() {return imageUrl;}public void setImageUrl(String imageUrl) {this.imageUrl = imageUrl;}private String name;private String imageUrl;}
}