一、事出必有因
前段时间公司让去采集一些单品的图片,单品的图片约清晰越好。
二、最初思路
在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下载图片