Jsoup - 【Java爬虫】- 批量下载指定网站图片

本文介绍了Java库Jsoup的使用,包括从URL解析HTML文档,使用DOM和CSS选择器提取数据,以及如何利用Jsoup进行网页图片的爬取。同时提到了其对多线程和网络连接管理的局限性。
摘要由CSDN通过智能技术生成

简介

Jsoup 是一款Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的API,可通过 DOM,CSS 以及类似于 JQuery 的操作方法来取出和操作数据。

Jsoup 对多线程、连接池、代理等等的支持并不是很好,所以一般把 Jsoup 仅仅作为 HTML 解析工具使用。

  • 功能

    • 从一个 URL、文件或字符串中解析 HTML

    • 使用 DOM 或 CSS 选择器来查找、取出数据

    • 可操作 HTML 元素、属性、文本

  • 引入依赖

     <!--jsoup-->
     <dependency>
         <groupId>org.jsoup</groupId>
         <artifactId>jsoup</artifactId>
         <version>1.15.3</version>
     </dependency>
  • 解析 URL

     /**
      * 方式一:
      */
     public void jsoupTest() throws IOException {
         /**
          * 参数:
          *  1、url地址
          *  2、超时时间
          */
         Document document = Jsoup.parse(new URL("http://www.xxx.com"),10000);
         // 使用标签选择器获取指定标签中的内容
         // 获取第一个 title 标签元素的文本内容
         String title = document.getElementsByTag("title").first().text();
     }
     /**
      * 方式二:
      */
     public void jsoupTest() throws IOException {
         // 连接到指定网站
         Connection connection = Jsoup.connect("http://www.xxx.com");
         // 获取网站页面上所有的 DOM 元素
         Document document = connection.get();
     }
  • 使用 DOM 方式遍历文档

    • 元素获取

      • 根据 ID 查询元素:getElementById

      • 根据 标签 查询元素:getElementByTag

      • 根据 Class 查询元素:getElementByClass

      • 根据 属性 查询元素 getElementByAttribute

    •  Element byId = document.getElementById("qxzxqm");
       Elements byTag = document.getElementsByTag("img");
       Elements byClass = document.getElementsByClass("schoolcon_right");
       Elements byAttribute = document.getElementsByAttribute("rel");
    • 使用 Jsoup API 获取元素

      • select()

      • first()

      • get()

      • attr()

      • ......

在线 API:Jsoup (jsoup 1.6.3 API)

示例:爬取网站图片

 import org.jsoup.Connection;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.select.Elements;
 import utils.PrintLogThread;
 ​
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 ​
 /**
  * 爬取指定网址上的图片
  *
  * Tips:
  * 若出现 403 错误则可能是由于“写入”访问被禁止而造成的
  * 当试图将文件上载到目录或在目录中修改文件,但该目录不允许"写"访问时就会出现此种错误
  *
  * @author 秋玄
  * @version 1.0
  * @since 1.0
  */
 public class App {
     public static void main(String[] args) {
         // 网站地址
         String site = "https://xxx.xxx.com/";
         // 图片保存路径
         String filePath = "F://test";
         // 自定义图片名称
         String fileName = "img";
         downloadImg(site,filePath,fileName);
     }
 ​
     /**
      * 获取指定网站上所有图片
      * @param website       指定网站的完整域名 包括请求协议,例如:www.xxx.com
      * @param filePath      图片存放路径 例如:F://test
      * @param fileName      图片名称 例如:xxx
      */
     private static void downloadImg(String website,String filePath,String fileName) {
         List<String> urlList = new ArrayList<>();
         try {
             // 获取网站图片的 src
             // 连接到指定网站
             Connection connection = Jsoup.connect(website);
             // 获取网站页面上所有的 DOM 元素
             Document document = connection.get();
             // 获取所有的 img 元素
             Elements imgs = document.getElementsByTag("img");
             // 遍历 imgs
             for (int i = 0; i < imgs.size(); i++) {
                 // 获取 img 元素的 src 属性
                 String src = imgs.get(i).attr("src");
 ​
                 // url地址以 “//” 开始,需要拼接请求协议
                 if (src.startsWith("//")){
                     src = "http:" + src;
                 }
 ​
                 // 路径为 空 或 “about:blank” 则不添加到 List 中
                 if (src.length() != 0 && !"about:blank".equals(src)) {
                     urlList.add(src);
                 }
 ​
                 // 下载图片
                 getImg(urlList,filePath,fileName);
 ​
                 // 记录日志到 log.txt 文件
                 PrintLogThread thread = new PrintLogThread("下载完成,第" + (i + 1) + "张图片",filePath + "//log.txt");
                 thread.start();
             }
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 ​
     /**
      * 下载指定 URL 的图片
      * @param imgURL        图片地址的 list 集合
      * @param filePath      图片存放路径
      * @param fileName      图片文件名称
      */
     private static void getImg(List<String> imgURL,String filePath,String fileName){
         InputStream in = null;
         FileOutputStream fos = null;
 ​
         // 遍历图片地址 list 集合
         for (int i = 0; i < imgURL.size(); i++) {
             try {
                 URL url = new URL(imgURL.get(i));
                 in = url.openStream();
 ​
                 // 拼接文件存放路径及文件名
                 String path = appendPath(filePath,fileName,i);
 ​
                 // 将图片写入本地
                 fos = new FileOutputStream(path);
                 byte[] bytes = new byte[1024];
                 int count = in.read(bytes);
                 while(count != -1){
                     fos.write(bytes,0,count);
                     fos.flush();
                     count = in.read(bytes);
                 }
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }finally {
                 // 释放资源
                 if (in != null) {
                     try {
                         in.close();
                     } catch (IOException e) {
                         throw new RuntimeException(e);
                     }
                 }
                 if (fos != null) {
                     try {
                         fos.close();
                     } catch (IOException e) {
                         throw new RuntimeException(e);
                     }
                 }
             }
         }
     }
 ​
     /**
      * 拼接文件存放路径及文件名
      * @param filePath      文件路径
      * @param fileName      文件名
      * @param i             文件编号
      * @return              文件完整路径
      * 格式:文件路径 + 文件名称 + _ + 文件编号 + 文件后缀(.jpg)
      */
     private static String appendPath(String filePath,String fileName,Integer i) {
         return filePath + "//" + fileName + "_" + (i + 1) + ".jpg";
     }
 }
package utils;
 ​
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.PrintStream;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 ​
 /**
  * 日志工具类 - 记录日志
  *
  * @author 秋玄
  * @version 1.0.0
  * @since 1.0.0
  */
 public class LoggerUtil {
     /**
      * 记录日志
      * @param msg           需要记录的信息
      * @param filePath      日志文件的路径
      */
     public static void log(String msg,String filePath){
         try {
             // 指定一个日志文件
             PrintStream printStream = new PrintStream(new FileOutputStream(filePath,true));
 ​
             // 改变输出方向
             System.setOut(printStream);
 ​
             // 日期调用方法时的当前时间
             Date now = new Date();
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
             String strTime = sdf.format(now);
 ​
             // 输出日志信息到日志文件
             System.out.println(strTime + " : " + msg);
 ​
         } catch (FileNotFoundException e) {
             throw new RuntimeException(e);
         }
     }
 }
 package utils;
 ​
 public class PrintLogThread extends Thread{
     private String msg;
     private String filePath;
 ​
     private PrintLogThread(){}
 ​
     public PrintLogThread(String msg,String filePath){
         this.msg = msg;
         this.filePath = filePath;
     }
 ​
     @Override
     public void run() {
         LoggerUtil logger = new LoggerUtil();
         logger.log(msg,filePath);
     }
 }
<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
          http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 ​
     <groupId>org.example</groupId>
     <artifactId>JavaCrawler</artifactId>
     <version>1.0-SNAPSHOT</version>
 ​
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
     </properties>
 ​
     <dependencies>
         <!-- Java网络爬虫工具 Jsoup -->
         <dependency>
             <groupId>org.jsoup</groupId>
             <artifactId>jsoup</artifactId>
             <version>1.14.3</version>
         </dependency>
     </dependencies>
 ​
 </project>

一  叶  知  秋,奥  妙  玄  心

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
运行环境 .NET Framework2.0 开发工具 Microsoft Visual Studio 2005 二. 部分代码说明(主要讲解异步分析和下载): 异步分析下载采取的策略是同时分析同时下载,即未等待数据全部分析完毕就开始把已经分析出来的图片链接开始下载下载成功的均在List框链接前面划上了√ ,未能下载图片有可能是分析错误或者是下载异常。 1. 异步分析部分代码 /// /// 异步分析下载 /// private void AsyncAnalyzeAndDownload(string url, string savePath) { this.uriString = url; this.savePath = savePath; #region 分析计时开始 count = 0; count1 = 0; freq = 0; result = 0; QueryPerformanceFrequency(ref freq); QueryPerformanceCounter(ref count); #endregion using (WebClient wClient = new WebClient()) { AutoResetEvent waiter = new AutoResetEvent(false); wClient.Credentials = CredentialCache.DefaultCredentials; wClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(AsyncURIAnalyze); wClient.DownloadDataAsync(new Uri(uriString), waiter); //waiter.WaitOne(); //阻止当前线程,直到收到信号 } } /// /// 异步分析 /// protected void AsyncURIAnalyze(Object sender, DownloadDataCompletedEventArgs e) { AutoResetEvent waiter = (AutoResetEvent)e.UserState; try { if (!e.Cancelled && e.Error == null) { string dnDir = string.Empty; string domainName = string.Empty; string uri = uriString; //获得域名 http://www.sina.com/ Match match = Regex.Match(uri, @"((http(s)?://)?)+[\w-.]+[^/]");//, RegexOptions.IgnoreCase domainName = match.Value; //获得域名最深层目录 http://www.sina.com/mail/ if (domainName.Equals(uri
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qx_java_1024

祝老板生意兴隆,财源广进!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值