关键词:
????????关注后回复 “进群” ,拉你进程序员交流群????????
作者:Victor.Chang
原文:blog.csdn.net/qq_35402412/article/details/113627625
目的
爬取搜狗图片上千张美女图片并下载到本地
准备工作
爬取地址:https://pic.sogou.com/pics?query=%E7%BE%8E%E5%A5%B3
分析
打开上面的地址,按F12开发者工具 - NetWork - XHR - 页面往下滑动XHR栏出现请求信息如下:
Request URL :https://pic.sogou.com/napi/pc/searchList?mode=1&start=48&xml_len=48&query=%E7%BE%8E%E5%A5%B3
分析这段请求URL的主要几个参数:
start=48 表示从第48张图片开始检索
xml_len=48 从地48张往后获取48张图片
query=?搜索关键词(例:美女,这里浏览器自动做了转码,不影响我们使用)
点击Respose,找个JSON格式器辅助过去看看。
JSON格式:https://www.bejson.com/
分析Respose返回的信息,可以发现我们想要的图片地址放在 picUrl里,
思路
通过以上分析,不难实现下载方法,思路如下:
设置URL请求参数
访问URL请求,获取图片地址
图片地址存入List
遍历List,使用线程池下载到本地
代码
SougouImgProcessor.java 爬取图片类
import com.alibaba.fastjson.JSONObject;
import us.codecraft.webmagic.utils.HttpClientUtils;
import victor.chang.crawler.pipeline.SougouImgPipeline;
import java.util.ArrayList;
import java.util.List;
/**
* A simple PageProcessor.
* @author code4crafter@gmail.com <br>
* @since 0.1.0
*/
public class SougouImgProcessor
private String url;
private SougouImgPipeline pipeline;
private List<JSONObject> dataList;
private List<String> urlList;
private String word;
public SougouImgProcessor(String url,String word)
this.url = url;
this.word = word;
this.pipeline = new SougouImgPipeline();
this.dataList = new ArrayList<>();
this.urlList = new ArrayList<>();
public void process(int idx, int size)
String res = HttpClientUtils.get(String.format(this.url, idx, size, this.word));
JSONObject object = JSONObject.parseObject(res);
List<JSONObject> items = (List<JSONObject>)((JSONObject)object.get("data")).get("items");
for(JSONObject item : items)
this.urlList.add(item.getString("picUrl"));
this.dataList.addAll(items);
// 下载
public void pipelineData()
// 多线程
pipeline.processSync(this.urlList, this.word);
public static void main(String[] args)
String url = "https://pic.sogou.com/napi/pc/searchList?mode=1&start=%s&xml_len=%s&query=%s";
SougouImgProcessor processor = new SougouImgProcessor(url,"美女");
int start = 0, size = 50, limit = 1000; // 定义爬取开始索引、每次爬取数量、总共爬取数量
for(int i=start;i<start+limit;i+=size)
processor.process(i, size);
processor.pipelineData();
SougouImgPipeline.java 图片下载类
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Store results in files.<br>
* @author code4crafter@gmail.com <br>
* @since 0.1.0
*/
public class SougouImgPipeline
private String extension = ".jpg";
private String path;
private volatile AtomicInteger suc;
private volatile AtomicInteger fails;
public SougouImgPipeline()
setPath("E:/pipeline/sougou");
suc = new AtomicInteger();
fails = new AtomicInteger();
public SougouImgPipeline(String path)
setPath(path);
suc = new AtomicInteger();
fails = new AtomicInteger();
public SougouImgPipeline(String path, String extension)
setPath(path);
this.extension = extension;
suc = new AtomicInteger();
fails = new AtomicInteger();
public void setPath(String path)
this.path = path;
/**
* 下载
* @param url
* @param cate
* @throws Exception
*/
private void downloadImg(String url, String cate, String name) throws Exception
String path = this.path + "/" + cate + "/";
File dir = new File(path);
if (!dir.exists()) // 目录不存在则创建目录
dir.mkdirs();
String realExt = url.substring(url.lastIndexOf(".")); // 获取扩展名
String fileName = name + realExt;
fileName = fileName.replace("-", "");
String filePath = path + fileName;
File img = new File(filePath);
if(img.exists()) // 若文件之前已经下载过,则跳过
System.out.println(String.format("文件%s已存在本地目录",fileName));
return;
URLConnection con = new URL(url).openConnection();
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
InputStream inputStream = con.getInputStream();
byte[] bs = new byte[1024];
File file = new File(filePath);
FileOutputStream os = new FileOutputStream(file, true);
// 开始读取 写入
int len;
while ((len = inputStream.read(bs)) != -1)
os.write(bs, 0, len);
System.out.println("picUrl: " + url);
System.out.println(String.format("正在下载第%s张图片", suc.getAndIncrement()));
/**
* 单线程处理
*
* @param data
* @param word
*/
public void process(List<String> data, String word)
long start = System.currentTimeMillis();
for (String picUrl : data)
if (picUrl == null)
continue;
try
downloadImg(picUrl, word, picUrl);
catch (Exception e)
fails.incrementAndGet();
System.out.println("下载成功: " + suc.get());
System.out.println("下载失败: " + fails.get());
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) / 1000 + "秒");
/**
* 多线程处理
*
* @param data
* @param word
*/
public void processSync(List<String> data, String word)
long start = System.currentTimeMillis();
int count = 0;
ExecutorService executorService = Executors.newCachedThreadPool(); // 创建缓存线程池
for (int i=0;i<data.size();i++)
String picUrl = data.get(i);
if (picUrl == null)
continue;
String name = "";
if(i<10)
name="000"+i;
else if(i<100)
name="00"+i;
else if(i<1000)
name="0"+i;
String finalName = name;
executorService.execute(() ->
try
downloadImg(picUrl, word, finalName);
catch (Exception e)
fails.incrementAndGet();
);
count++;
executorService.shutdown();
try
if (!executorService.awaitTermination(60, TimeUnit.SECONDS))
// 超时的时候向线程池中所有的线程发出中断(interrupted)。
// executorService.shutdownNow();
System.out.println("AwaitTermination Finished");
System.out.println("共有URL: "+data.size());
System.out.println("下载成功: " + suc);
System.out.println("下载失败: " + fails);
File dir = new File(this.path + "/" + word + "/");
int len = Objects.requireNonNull(dir.list()).length;
System.out.println("当前共有文件: "+len);
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) / 1000.0 + "秒");
catch (InterruptedException e)
e.printStackTrace();
/**
* 多线程分段处理
*
* @param data
* @param word
* @param threadNum
*/
public void processSync2(List<String> data, final String word, int threadNum)
if (data.size() < threadNum)
process(data, word);
else
ExecutorService executorService = Executors.newCachedThreadPool();
int num = data.size() / threadNum; //每段要处理的数量
for (int i = 0; i < threadNum; i++)
int start = i * num;
int end = (i + 1) * num;
if (i == threadNum - 1)
end = data.size();
final List<String> cutList = data.subList(start, end);
executorService.execute(() -> process(cutList, word));
executorService.shutdown();
HttpClientUtils.java http请求工具类
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author code4crafter@gmail.com
* Date: 17/3/27
*/
public abstract class HttpClientUtils
public static Map<String, List<String>> convertHeaders(Header[] headers)
Map<String, List<String>> results = new HashMap<String, List<String>>();
for (Header header : headers)
List<String> list = results.get(header.getName());
if (list == null)
list = new ArrayList<String>();
results.put(header.getName(), list);
list.add(header.getValue());
return results;
/**
* http的get请求
* @param url
*/
public static String get(String url)
return get(url, "UTF-8");
public static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
/**
* http的get请求
* @param url
*/
public static String get(String url, String charset)
HttpGet httpGet = new HttpGet(url);
return executeRequest(httpGet, charset);
/**
* http的get请求,增加异步请求头参数
* @param url
*/
public static String ajaxGet(String url)
return ajaxGet(url, "UTF-8");
/**
* http的get请求,增加异步请求头参数
*
* @param url
*/
public static String ajaxGet(String url, String charset)
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("X-Requested-With", "XMLHttpRequest");
return executeRequest(httpGet, charset);
/**
* @param url
* @return
*/
public static String ajaxGet(CloseableHttpClient httpclient, String url)
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("X-Requested-With", "XMLHttpRequest");
return executeRequest(httpclient, httpGet, "UTF-8");
/**
* http的post请求,传递map格式参数
*/
public static String post(String url, Map<String, String> dataMap)
return post(url, dataMap, "UTF-8");
/**
* http的post请求,传递map格式参数
*/
public static String post(String url, Map<String, String> dataMap, String charset)
HttpPost httpPost = new HttpPost(url);
try
if (dataMap != null)
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : dataMap.entrySet())
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nvps, charset);
formEntity.setContentEncoding(charset);
httpPost.setEntity(formEntity);
catch (UnsupportedEncodingException e)
e.printStackTrace();
return executeRequest(httpPost, charset);
/**
* http的post请求,增加异步请求头参数,传递map格式参数
*/
public static String ajaxPost(String url, Map<String, String> dataMap)
return ajaxPost(url, dataMap, "UTF-8");
/**
* http的post请求,增加异步请求头参数,传递map格式参数
*/
public static String ajaxPost(String url, Map<String, String> dataMap, String charset)
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("X-Requested-With", "XMLHttpRequest");
try
if (dataMap != null)
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : dataMap.entrySet())
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nvps, charset);
formEntity.setContentEncoding(charset);
httpPost.setEntity(formEntity);
catch (UnsupportedEncodingException e)
e.printStackTrace();
return executeRequest(httpPost, charset);
/**
* http的post请求,增加异步请求头参数,传递json格式参数
*/
public static String ajaxPostJson(String url, String jsonString)
return ajaxPostJson(url, jsonString, "UTF-8");
/**
* http的post请求,增加异步请求头参数,传递json格式参数
*/
public static String ajaxPostJson(String url, String jsonString, String charset)
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("X-Requested-With", "XMLHttpRequest");
StringEntity stringEntity = new StringEntity(jsonString, charset);// 解决中文乱码问题
stringEntity.setContentEncoding(charset);
stringEntity.setContentType("application/json");
httpPost.setEntity(stringEntity);
return executeRequest(httpPost, charset);
/**
* 执行一个http请求,传递HttpGet或HttpPost参数
*/
public static String executeRequest(HttpUriRequest httpRequest)
return executeRequest(httpRequest, "UTF-8");
/**
* 执行一个http请求,传递HttpGet或HttpPost参数
*/
public static String executeRequest(HttpUriRequest httpRequest, String charset)
CloseableHttpClient httpclient;
if ("https".equals(httpRequest.getURI().getScheme()))
httpclient = createSSLInsecureClient();
else
httpclient = HttpClients.createDefault();
String result = "";
try
try
CloseableHttpResponse response = httpclient.execute(httpRequest);
HttpEntity entity = null;
try
entity = response.getEntity();
result = EntityUtils.toString(entity, charset);
finally
EntityUtils.consume(entity);
response.close();
finally
httpclient.close();
catch (IOException ex)
ex.printStackTrace();
return result;
public static String executeRequest(CloseableHttpClient httpclient, HttpUriRequest httpRequest, String charset)
String result = "";
try
try
CloseableHttpResponse response = httpclient.execute(httpRequest);
HttpEntity entity = null;
try
entity = response.getEntity();
result = EntityUtils.toString(entity, charset);
finally
EntityUtils.consume(entity);
response.close();
finally
httpclient.close();
catch (IOException ex)
ex.printStackTrace();
return result;
/**
* 创建 SSL连接
*/
public static CloseableHttpClient createSSLInsecureClient()
try
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(new TrustStrategy()
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
return true;
).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier()
@Override
public boolean verify(String hostname, SSLSession session)
return true;
);
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
catch (GeneralSecurityException ex)
throw new RuntimeException(ex);
运行
由于网络等原因,我们发现并不能全部下载成功,不过可以多次运行尝试,可以实现较高的下载成功率。
666,厉害了。。
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
点击????卡片,关注后回复【面试题
】即可获取
在看点这里好文分享给更多人↓↓
用java爬美女图片,厉害了。。(代码片段)
目的爬取搜狗图片上千张美女图片并下载到本地准备工作爬取地址:https://pic.sogou.com/pics?query=%E7%BE%8E%E5%A5%B3分析打开上面的地址,按F12开发者工具-NetWork-XHR-页面往下滑动XHR栏出现请求信息如下:RequestURL:https:/... 查看详情
用java爬小姐姐图片,这个厉害了。。。
目的爬取搜狗图片上千张美女图片并下载到本地准备工作爬取地址:https://pic.sogou.com/pics?query=%E7%BE%8E%E5%A5%B3分析打开上面的地址,按F12开发者工具-NetWork-XHR-页面往下滑动XHR栏出现请求信息如下:RequestURL:https:/... 查看详情
用java爬小姐姐图片,直接拿来用!这个厉害了。。。
....net/qq_35402412/article/details/113627625目的爬取搜狗图片上千张美女图片并下载到本地准备工作爬取地址:https://pic.sogou.com/pics?query=%E7%BE%8E%E5%A5%B3分析打开上面的地址,按F12开 查看详情
厉害了,用java也能实现图片识别!(代码片段)
点击上方蓝色“终端研发部”,选择“设为星标”学最好的别人,做最好的我们 最近闲来无事研究了一下用Java如何模拟浏览器的行为,在实验登录的步骤时碰到了识别验证码的问题,于是在网上查找了关于Java如... 查看详情
厉害了,美女同事用单例模式实现了雪花算法!(代码片段)
点击关注公众号,Java干货及时送达雪花算法雪花算法适用于生成全局唯一的编号,比如数据库主键id,订单编号等至于为什么叫雪花算法,是因为科学家通过研究认为自然界中不存在两片完全相同的雪花,所... 查看详情
java几行代码提取图片文字,过个厉害了。。(代码片段)
来源:blog.csdn.net/weixin_44671737/article/details/110000864摘要近日浏览网上一些图片提取文字的网站,觉得甚是有趣,花费半日也做了个在线图片识别程序,完成了两个技术方案的选择,一是tesseract+pythonflask的方案... 查看详情
厉害了!单点登录系统用8张漫画就解释了。。。(代码片段)
...;u.nu/2k4wkJSONWebToken(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。让我们来假想一下一个场景。在A用户关注了B用户的时候,系统发邮件给B用户,并且附有一个... 查看详情
python爬虫入门教程:蜂鸟网图片爬取(代码片段)
...束了,新的工作又开始了,今天我们继续爬取一个网站,这个网站为 http://image.fengniao.com/ ,蜂鸟一个摄影大牛聚集的地方,本教程请用来学习,不要用于商业目的,不出意外,蜂鸟是有版权保护的网站。 2.蜂鸟网图... 查看详情
回车桌面图片爬取(代码片段)
回车桌面图片爬取今天我们就来爬爬这个网站https://tu.enterdesk.com/这个网站能爬的资源还是很多的,但我就写一个例子,其他的可以根据思路去写。首先还是先来分析下这个网站的图片获取过程我选择的是图库,先随便选择一个... 查看详情
java爬网页图片到本地(代码片段)
一、前言如何用java实现爬网页的照片呢?二、看代码packagecom.expt.ares.web;importcom.alibaba.fastjson2.JSON;importcom.expt.ares.vo.GetImgVO;importlombok.extern.slf4j.Slf4j;importorg.springframework.web.bind.annotation 查看详情
python写爬虫-爬甘农大学校新闻(代码片段)
...: 人生苦短,我用Python究竟它有多么强大, 多么简洁?抱着这个好奇心,趁不忙的几天.还是忍不住的小学了一下.(--其实学了还不到两天)随便用一个"HelloWorld 查看详情
python爬虫爬取百度图片(代码片段)
...开发环境涉及的知识点ostimeurllib.errorquotere(.*?)re.compile(key)代码实现开发环境日期:2021.9.11开发环境:python3.9和pycharmps:pycharm今天第一次用,随着将越来越多开发环境集成到vscode上,感觉太复杂了,配 查看详情
nginx这个功能厉害了!(代码片段)
点击上方关注“终端研发部”设为“星标”,和你一起掌握更多数据库知识原文:https://www.cnblogs.com/cjsblog/p/12163207.html作者:废物大师兄1.需求将生产环境的流量拷贝到预上线环境或测试环境,这样做有很多好处&... 查看详情
nginx这个功能厉害了!(代码片段)
点击上方关注“终端研发部”设为“星标”,和你一起掌握更多数据库知识原文:https://www.cnblogs.com/cjsblog/p/12163207.html作者:废物大师兄1.需求将生产环境的流量拷贝到预上线环境或测试环境,这样做有很多好处&... 查看详情
python:20行代码爬取高质量帅哥美女视频,让你一次看个够(代码片段)
...!又到了化身曹贼的时间!冲鸭!今天咱们把这个网站上的小姐姐小哥哥都给爬下来,当然你学会了去爬啥那就都随便了~环境模块用到的环境是Python3.6和pycharm需要安装两个模块,requests和re模块,还会用到... 查看详情
使用elasticsearch搭建自己的搜索系统,这个厉害了。。(代码片段)
作者:HaiXiang来源:https://www.cnblogs.com/haixiang/p/12867160.html什么是elasticsearchElasticsearch是一个开源的高度可扩展的全文搜索和分析引擎,拥有查询近实时的超强性能。大名鼎鼎的Lucene搜索引擎被广泛用于搜索领域,但是操作复杂繁... 查看详情
汽车之家数据爬取:文章链接//图片//标题(代码片段)
(1)打印出来的东西乱码,如何处理这个问题?importrequestsresponse=requests.get(url=‘https://www.autohome.com.cn/beijing/‘#最新的地址是可以出来的#url=‘https://www.autohome.com.cn/news/‘#老的地址会出现乱码问题)print(response.text)(2)importrequestsresponse=req... 查看详情
2021最新java开发者学习路线,太厉害了!(代码片段)
...个过程,那就是从头到尾依次执行。任何资源都会为这个程序服务,这必然就会存在 浪费资源 的情况。这里说的浪费资源指的是资源空闲,没有充分使用的情况。操作系统为我们的程序带来了 并发性,操作系... 查看详情