当前位置:AIGC资讯 > 数据采集 > 正文

WebMagic+curl 爬虫采集图片

一、事出必有因

    前段时间公司让去采集一些单品的图片,单品的图片约清晰越好。

二、最初思路

    在WebMagic没有找到下载文件用的下载器(Downloader),一开始是在网上找的HttpClient的代码,想要自己实现一个文件下载的Downloader,但是由于单个图片太大,由于网络不稳定,有时候在下载时就总是出现线程假死状态。

  /**
     * 从网络Url中下载文件(我一开始是使用这个方法去下载图片,但是总是出问题。)
     * @param urlStr
     * @param fileName
     * @param savePath
     * @throws IOException
     */
    public static void  downLoadFromUrl(String urlStr,String fileName,String savePath) throws IOException{
        URL url = new URL(urlStr);  
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
                //设置超时间为3秒
        conn.setConnectTimeout(3*1000);
        //防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

        //得到输入流
        InputStream inputStream = conn.getInputStream();  
        //获取自己数组
        byte[] getData = readInputStream(inputStream);    

        //文件保存位置
        File saveDir = new File(savePath);
        if(!saveDir.exists()){
            saveDir.mkdir();
        }
        File file = new File(saveDir+File.separator+fileName);    
        FileOutputStream fos = new FileOutputStream(file);     
        fos.write(getData); 
        if(fos!=null){
            fos.close();  
        }
        if(inputStream!=null){
            inputStream.close();
        }


        System.out.println("info:"+url+" download success"); 

    }

(上面代码参考:java 从网络Url中下载文件)

三、自己实现的Java curl下载器(Pipeline)

    curl是PHP的一个工具,也是linux上自带的一个命令,简称神器。

$ which curl
/usr/bin/curl

1、curl简单命令介绍

下载单个文件,默认将输出打印到标准输出中(STDOUT)中

curl https://www.baidu.com/

通过-o/-O选项保存下载的文件到指定的文件中

-o:将文件保存为命令行中指定的文件名的文件中
-O:使用URL中默认的文件名保存文件到本地

1 # 将文件下载到本地并命名为mygettext.html
2 curl -o mygettext.html http://www.gnu.org/software/gettext/manual/gettext.html
3 
4 # 将文件保存到本地并命名为gettext.html
5 curl -O http://www.gnu.org/software/gettext/manual/gettext.html

同样可以使用转向字符">"对输出进行转向输出

同时获取多个文件

curl -O URL1 -O URL2

若同时从同一站点下载多个文件时,curl会尝试重用链接(connection)。

断点续传

通过使用-C选项可对大文件使用断点续传功能,如:

1 # 当文件在下载完成之前结束该进程
2 $ curl -O http://www.gnu.org/software/gettext/manual/gettext.html
3 ##############             20.1%
4 
5 # 通过添加-C选项继续对该文件进行下载,已经下载过的文件不会被重新下载
6 curl -C - -O http://www.gnu.org/software/gettext/manual/gettext.html
7 ###############            21.1%

curl 取得HTTP返回的状态码:-w %{http_code}

curl https://www.baidu.com/ -o ./baidu.html -w %{http_code} -s
## -w %{http_code} 控制额外输出(小写w)
## -s silent 模式,不输出任何东西(小写s)
## -o ./baidu.html 把下载的数据保存到当前文件夹下的baidu.html(小写o)

参考:CURL常用命令

          常用HTTP状态码和CURL 000问题

2、实现Java curl下载器

如果是window系统,需要先下载curl.exe(抱歉没有用过Mac)

去Github下载curl。打开src/目录,就是curl.exe
        

java curl Downloader

package com.lacerta.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class DownloadPictureUtil {

	public static void main(String[] args) {
		long i = System.currentTimeMillis();
		boolean b = downloadPicture(
				"https://www.baidu.com/img/bd_logo1.png",
				"D:/curltest.jpg");
		System.out.println("下载是否成功:" + b + "\t使用时间" + (System.currentTimeMillis() - i) + "ms");
	}

	public static boolean downloadPicture(String imgURL, String target) {
		String[] cmds = { //
				"C:/Users/AnXiaole/Downloads/curl-7.52.1/src/curl", //
				"-o", //把下载的数据保存到指定的文件中,这里是target(小写o)
				target, //
				imgURL, //需要下载的URI网址
				"-s", //silent 模式,不输出任何东西(小写s)
				"-w \n%{http_code}"//控制额外输出(小写w)
		};
		ProcessBuilder pb = new ProcessBuilder(cmds);
		pb.redirectErrorStream(true);
		Process p;
		BufferedReader br = null;
		try {
			p = pb.start();
			String line = null;
			br = new BufferedReader(new InputStreamReader(p.getInputStream()));
			while ((line = br.readLine()) != null) {
				if (line.trim().contains("200")) {
					System.out.println("Download Img 200:\t" + cmds[2]);
					return true;
				}
				if (line.trim().contains("404")) {
					System.out.println("Download Img 404:\t" + cmds[2]);
					return false;
				}
			}
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

和WebMagic集成的使用方法

在我自定义的FilePipeline:IntaoFilePipeline中使用DownloadPictureUtil下载器:
boolean b = DownloadPictureUtil.downloadPicture(url, path + (i + 1) + ".jpg");

package com.lacerta.intao.babyimg.designerchildrenswear;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

import com.lacerta.util.DownloadPictureUtil;

import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.FilePipeline;

public class IntaoFilePipeline extends FilePipeline {

	public IntaoFilePipeline() {
		setPath("/data/webmagic/");
	}

	public IntaoFilePipeline(String path) {
		setPath(path);
	}

	@Override
	public void process(ResultItems resultItems, Task task) {
		String path = this.path + task.getUUID()
				+ PATH_SEPERATOR /* + resultItems.get("单品品牌\t") */ + resultItems.get("单品id\t") + PATH_SEPERATOR;
		PrintWriter printWriter = null;
		try {
			printWriter = new PrintWriter(new OutputStreamWriter(
					new FileOutputStream(getFile(path + "单品" + resultItems.get("单品id\t") + ".html"), true), "UTF-8"));

			printWriter.println("<meta charset=\"utf-8\">");
			printWriter.println("当前采集地址:\t" + resultItems.getRequest().getUrl() + "<br/>");
			for (Map.Entry<String, Object> entry : resultItems.getAll().entrySet()) {
				printWriter.println(entry.getKey() + ":\t" + entry.getValue() + "<br/>");
			}

			Object object = resultItems.get("图片路径\t");// 获得WebMagic抓取到的图片路径list
			if (object != null) {
				List<String> picUrl = (List<String>) object;
				for (int i = 0; i < picUrl.size(); i++) {
					String url = picUrl.get(i);
					for (int j = 0; j <= task.getSite().getRetryTimes(); j++) {
						boolean b = DownloadPictureUtil.downloadPicture(url, path + (i + 1) + ".jpg");
						if (b) {
							break;
						} else {
							try {
								Thread.sleep(task.getSite().getSleepTime());
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (printWriter != null) {
				printWriter.close();
			}
		}
	}

}

WebMagic启动方法

	public static void main(String[] args) throws IOException {

		Spider spider = Spider.create(new IntaoPageProcessor())//
				.setScheduler(
						new FileCacheQueueScheduler("D:/资料包/work/lacerta/intao/" + site.getDomain() + "/scheduler"))
				.addPipeline(new ConsolePipeline())//
				.addPipeline(new IntaoFilePipeline("D:/资料包/work/lacerta/intao"))// 加入IntaoFilePipeline
		;

		spider.addUrl("这里是要下载的url,这里就写我当时抓取的url了");

		spider.thread(60).run(); // 当时我使用了60个线程。
	}

四、参考

CURL常用命令

常用HTTP状态码和CURL 000问题

curl / Download

利用webmagic下载图片

更新时间 2023-11-08