吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3323|回复: 16
收起左侧

[Java 转载] java爬妹子图

[复制链接]
AItechnology 发表于 2020-7-27 15:53
之前在论坛看到一位大佬发了一个爬妹子图的爬虫程序,地址https://www.52pojie.cn/forum.php?mod=viewthread&tid=1227603&extra=page%3D1%26filter%3Dtypeid%26typeid%3D192
受这篇帖子的启发,利用其思路,自己写了一个爬去妹子图的java方法体,可以爬取https://www.mzitu.com的妹子图,哈哈,仅此分享给大家。另外,有一位大佬直接分享了成品,我这里的呢,就是大家动动脑子,自己爬取了。大佬作品地址https://www.52pojie.cn/forum.php?mod=viewthread&tid=828175&extra=page%3D1%26filter%3Dtypeid%26typeid%3D192
那么先来说说思路吧。(思路得益于低一个贴出代码的帖子)第一步:先利用jsoup获取主页上图片的链接地址;第二步:进入主页中地址的二级地址,判断是否是图片地址,如果是,利用保存程序保存图片,如果不是,进入下一级地址,如此往复,直到爬取完图片。
那么上代码了:


[Asm] 纯文本查看 复制代码
public static void getTestContent() {
		ArrayList<String> filePath = new ArrayList<>();//构建文件路径集合
        ArrayList<String> fileId  = new ArrayList<>();//构建独一无二的文件名
		String url ="https://www.mzitu.com/";
		try {
			//解析第一级地址中返回的链接地址,可以利用System.out.println(doc.toString()); 查看网页源代码,确定如何利用jsoup获取下一级地址
			Document doc = Jsoup.connect(url).get();	
			Elements el = doc.getElementsByClass("postlist");
			Elements li = el.select("ul").select("li").select("a");			
			int num=0;
			for (Element element : li){//遍历获取的地址
				num=num+1;//统计第一级地址的数量
                String url1 = String.valueOf(element.attr("href"));//获取第二层的href
                if ((num%2)==0){//有些href是广告 和图片链接最主要的区别是 含有字母p 所以判断一下
                    continue;
                }
            String ID = url1.substring(22,28);//获取文件ID ,这个值用来保存图片,但这里只是利用一级地址生成文件前缀
   
            String url2=url+ID;
            //下面内容为获取二级地址的网络请求
            Document document = Jsoup.connect(url2).get();
            Elements ending = document.getElementsByClass("pagenavi");
            Elements img = ending.select("a");
            int tmpnum=0;
            int lastnum=0;
		        for(Element element2:img) {
		        	tmpnum=tmpnum+1;//通过导航栏目统计二级网页中同一个系列的图片数目		        
		        }
		        //下面就是获取最终同一个系列有多少图片
		        if(tmpnum>2) {
		        	lastnum = Integer.valueOf(StringTools.getLastStringBySeperate(img.get(tmpnum-2).attr("href").toString(),"/"));//根据最后一张图的序号判断一个系列有多少图片
		        }else {
		        	if(tmpnum==0) {lastnum=0;}
		        	if(tmpnum==1) {lastnum=3;}
		        }
            
            	//下面是获取最终每张图片的下载地址
            	for(int i=2;i<lastnum;i++) {
					String url3=url2+"/"+String.valueOf(i);//生成同一个系列每张图的地址															
					Document docss = Jsoup.connect(url3).get();					
					Elements elss = docss.getElementsByClass("main-image");
					Elements liss = elss.select("p").select("a").select("img");
									
		            String url4 = String.valueOf(liss.get(0).attr("src"));
		            filePath.add(url4);//保存妹子图的地址
		            System.out.println(url4);
					
			            try {
							Thread.sleep(500);//延迟请求,服务器似乎存在防止拒绝服务攻击的策略,快速大量请求会被服务器拒绝
						} catch (InterruptedException e) {					
							e.printStackTrace();
						}
								
					if(i<10) {
						fileId.add(ID+"0"+String.valueOf(i));//保证文件名统一长度					
					}else {
						fileId.add(ID+String.valueOf(i));//生成唯一的文件名,需要之前的文件前缀加序号
					}
					
				}
			}
			SavePngJoup(filePath, fileId);//利用地址和文件名保存图片
        } catch (IOException e) {
            System.out.println("抓取文件过程中出错,可能是请求过于频繁服务器拒绝响应");
            e.printStackTrace();
        }finally {
            System.out.println("运行结束");
        }
			
		
		
	}


[Asm] 纯文本查看 复制代码
//使用这个方法前请自己在D盘建立test文件夹,否则会报错
public static void SavePngJoup(ArrayList<String> filePath,ArrayList<String> fileId)  {
        ByteArrayOutputStream byteOutputStream = null;
        FileOutputStream fileOutputStream = null;
        DataInputStream dataInputStream = null;
        //遍历保存图片
for (int index = 0 ; index < filePath.size() ; index++){
            String url = null;
            try {
                url = new String(filePath.get(index));//读取地址
//下面的网络请求设置服务端,否则,请求次数多了服务器拒绝响应
Connection connection = Jsoup.connect(url).userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6").referrer("https://www.mzitu.com/");
                Connection.Response response = connection.method(Connection.Method.GET).ignoreContentType(true).timeout(3*1000).execute();
                BufferedInputStream bufferedInputStream = response.bodyStream();
                try {
					Thread.sleep(500);//模拟人操作,人操作总会耗时,具体延迟多少看个人自己测试了。
//另外,这里等待时间可以是500左右的随机数,这样就更真实模拟人的点击
} catch (InterruptedException e) {				
					e.printStackTrace();
				}
                dataInputStream = new DataInputStream(bufferedInputStream);
                File file = new File("D:/test/"+fileId.get(index)+".jpg");
                fileOutputStream = new FileOutputStream(file);
                byteOutputStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int length;
                /*写入字节*/
while ((length = dataInputStream.read(buffer))>0){
                    byteOutputStream.write(buffer,0,length);
                }
                byte[] context = byteOutputStream.toByteArray();
                fileOutputStream.write(context);
                System.out.println("保存了"+file.getName());
            } catch (MalformedURLException e) {
                System.out.println("URL转换错误");
e.printStackTrace();
            } catch (FileNotFoundException e) {
                System.out.println("无法创建文件");
e.printStackTrace();
            } catch (IOException e) {
                System.out.println("文件传输出现错误");
e.printStackTrace();
            }

        }
/*关闭流*/
try {
            fileOutputStream.close();
            byteOutputStream.close();
            dataInputStream.close();
        } catch (IOException e) {
            System.out.println("关闭流出现错误");
e.printStackTrace();
        }
    }


最后贴上自己写的一个工具类

[Asm] 纯文本查看 复制代码
public class StringTools {
	//parameter : str
	//the string you need to process
	//parameter : fenggefu
	//the seperate code in string, such as the "," in the string"Type=neme, Date=20200725"
	//for example: str="haha=haha,didi=didi"
	//res=StringTools.seperateString(str,",") will return an array res[0]="haha=haha",res[1]="didi=didi"
	public static String[] seperateString(String str,String fenggefu) {
		char fengefu=fenggefu.charAt(0);
		int len=str.length();
		char ss[]=str.toCharArray();
		int numberofCode=1;
		for(int i=0;i<len;i++) {
			if(ss[i]==fengefu) {numberofCode=numberofCode+1;}
		}
		String properties[];
		if(numberofCode>0) {
			int tmpnum=0;
			properties = new String[numberofCode];
			for(int i=0;i<numberofCode;i++) {
				properties[i]="";
			}
			for(int i=0;i<len;i++) {
				if(ss[i]!=fengefu) {
					properties[tmpnum]=properties[tmpnum]+ss[i];
					}
				if(ss[i]==fengefu) {
					tmpnum=tmpnum+1;
					}
			}
		}else {
			properties = new String[1];
			properties[0]=str;
		}
		return properties;
	}

	public static String getLastStringBySeperate(String str,String fenggefu) {
		String[] reStrings=seperateString(str, fenggefu);
		return reStrings[reStrings.length-1];
	}
}

这个工具类可以把字符串分为一个数组。在本程序中之用为了获取"/"分隔的最后一组数字。有以上代码,只要在主方法调用就可以爬图了。图片很多,爬取需要时间,请耐心等待。

免费评分

参与人数 4吾爱币 +7 热心值 +4 收起 理由
苏紫方璇 + 5 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
layuai + 1 用心讨论,共获提升!
twinklestars + 1 + 1 热心回复!
panduoxi + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

xccxvb 发表于 2020-7-27 16:25
大兵马元帅 发表于 2020-7-27 16:09
Python能不能不要这么骄傲了,你会饿别人也会,你不会的别人也会。

可是python不需要写这么多代码哦,不同语言各有各的优点吧,有些东西也是只有python才比较擅长的。身为一个程序员要对自己擅长的语言有足够的信心!
大兵马元帅 发表于 2020-7-27 16:09
Python能不能不要这么骄傲了,你会饿别人也会,你不会的别人也会。
MySeeker 发表于 2020-7-27 16:13
qujf 发表于 2020-7-27 16:32
xccxvb 发表于 2020-7-27 16:25
可是python不需要写这么多代码哦,不同语言各有各的优点吧,有些东西也是只有python才比较擅长的。身为一 ...

嗯,我觉得你所的对。大部分功能每一种后台语言都可以做,就是看谁的效率和性能了。
meteornk 发表于 2020-7-27 16:33
坚持学习java开发
红烧大白菜 发表于 2020-7-27 16:40
还是喜欢直接打包,简单。
daymissed 发表于 2020-7-27 16:56
好东西,收藏备用。感谢分享
比鸽爱鸟A 发表于 2020-7-27 16:58
666,这个好,感谢楼主
我有三个艾琳 发表于 2020-7-27 17:19
当年学python就为了爬网址
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-26 02:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表