【系列教程一】谁说 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;
    }
}

猜你喜欢

转载自blog.csdn.net/Dark_orange/article/details/130244483