public class Demo {
public static void main(String[] args) throws IOException{
Map<String, String> map = new HashMap<>();
String path="C:\\Bird";
File myPath = new File(path);
if ( !myPath.exists()){//若此目录不存在,则创建
myPath.mkdir();
System.out.println("创建文件夹路径为:"+ path);
}
// map.put("collect_1", "10453");//雀形目
// map.put("collect_2", "9760");
map.put("collect_1", "9760");
map.put("collect_2", "9761");
map.put("collect_3", "9778");
String responsePic = HttpClientUtil.getInstance().sendHttpPost("https://birdnet.cn/atlas.php?mod=show&action=atlaslist", map);
Document document3=Jsoup.parse(responsePic);
// System.out.println(document3);
Elements ul=document3.select("div.picturel > *");//获取ul信息
int i=0;
Elements div=document3.getElementsByClass("pg");
Elements label=div.select("span");
String sizeString=label.attr("title");//这里是因为有些图有多页
String regEx="[^0-9]";
Pattern p = Pattern.compile(regEx);
Matcher m2 = p.matcher(sizeString);
String sizes=m2.replaceAll("").trim();
int size=Integer.valueOf(sizes);
System.out.println(size);
boolean flag=true;//设立标志位,因为只有第一张图会点进去爬两张介绍信息,其他图都不用爬
Elements pics = ul.select("ul> *");
try {
File dir = new File("C:\\Bird\\鸡形目\\雉科\\环颈山鹧鸪");
if (!dir.exists()) {
dir.mkdirs();
}
} catch (Exception e) {
e.printStackTrace();
}
String ImgPath="C:\\Bird\\鸡形目\\雉科\\环颈山鹧鸪";
for(Element pic:pics){//此时已经遍历了各个li下的资源了
Elements url2=pic.select("img[src]");
String url= url2.attr("src");
Elements a=pic.select("a[href]");
String href= a.attr("href");
String responseflag = HttpClientUtil.getInstance().sendHttpPost("https://birdnet.cn/"+href);
Document documentflag=Jsoup.parse(responseflag);
Elements kind=documentflag.getElementsByClass("mahko cl");//鸟种描述
Elements birdPics=kind.select("img[src]");//因为有两张图,所以遍历
Elements mak1=documentflag.getElementsByClass("makl");
Elements photo=mak1.select("img[src]");
String pichref= photo.attr("src");
// System.out.println(mak1);
// System.out.println(photo);
// System.out.println("+++++++++++++++++++++++");
// System.out.println(pichref);
downImages(ImgPath, pichref);
if(flag){//只下一次鸟中信息*
for(Element birdPic:birdPics )
{ String birdurl= birdPic.attr("src");
String realPath="https://birdnet.cn//"+birdurl;
downImages(ImgPath, realPath);
}
flag=false;
// System.out.println(birdurl2);
}
}//for循环结束
if(size>1){//对于多页情况
for(int j=2;j<size+1;j++)
{ String size2=String.valueOf(j);
map.put("page",size2 );
String responseContent4 = HttpClientUtil.getInstance().sendHttpPost("https://birdnet.cn/atlas.php?mod=show&action=atlaslist",map);
Document document4=Jsoup.parse(responseContent4);
// System.out.println(document3);
Elements ul2=document4.select("div.picturel > *");//获取ul信息
Elements pics2 = ul2.select("ul> *");
try {
File dir = new File("C:\\Bird\\鸡形目\\雉科\\环颈山鹧鸪");
if (!dir.exists()) {
dir.mkdirs();
}
} catch (Exception e) {
e.printStackTrace();
}
String ImgPath2="C:\\Bird\\鸡形目\\雉科\\环颈山鹧鸪";
for(Element pic:pics2){//此时已经遍历了各个li下的资源了
Elements url2=pic.select("img[src]");
String url= url2.attr("src");
Elements a=pic.select("a[href]");
String href= a.attr("href");
String responseflag = HttpClientUtil.getInstance().sendHttpPost("https://birdnet.cn/"+href);
Document documentflag=Jsoup.parse(responseflag);
Elements kind=documentflag.getElementsByClass("mahko cl");//鸟种描述
Elements birdPics=kind.select("img[src]");//因为有两张图,所以遍历
Elements mak1=documentflag.getElementsByClass("makl");
Elements photo=mak1.select("img[src]");
String pichref= photo.attr("src");
// System.out.println(mak1);
// System.out.println(photo);
// System.out.println("+++++++++++++++++++++++");
// System.out.println(pichref);
downImages(ImgPath, pichref);
}
//
}//if语句结束
}
为了使爬虫顺利进行,我将他拆分为两个部分,第一部分为爬虫并建立文件夹,第二部分就是如上,进行图片的爬取。
为了厘清逻辑,我建立了这个demo处理,因为要求是一个种类只要有一张鸟种描述和鸟种分布,而且又要下载高清大图,点进去3张,只要第一份下载3张,其他都只下载图片一张就可以了,所以我在第三层设置了标志位flag,只需在下载前设为ture,然后进行循环下载,下载后置为false
for (Element el3: els3) {
flag=true;//循环一开始标志位复位
这样就能保证一类鸟只有一张鸟种分析和鸟种分布了。
其中有一些小细节就不一一赘述了。
jsoup教程我最先看的是这个
https://www.iteye.com/blog/chenlong-1988-1679445
1、Selector选择器基本语法
tagname: 通过标签查找元素,比如:a
ns|tag: 通过标签在命名空间查找元素,比如:可以用 fb|name 语法来查找 <fb:name> 元素
关于 #id: 通过ID查找元素,比如:#logo
.class: 通过class名称查找元素,比如:.masthead
[attribute]: 利用属性查找元素,比如:[href]
el#id: 元素+ID,比如: div#logo
el.class: 元素+class,比如: div.masthead
el[attr]: 元素+class,比如: a[href]
任意组合,比如:a[href].highlight
ancestor child: 查找某个元素下子元素,比如:可以用.body p 查找在”body”元素下的所有 p元素
parent > child: 查找某个父元素下的直接子元素,比如:可以用div.content > p 查找 p 元素,也可以用body > * 查找body标签下所有直接子元素
siblingA + siblingB: 查找在A元素之前第一个同级元素B,比如:div.head + div
siblingA ~ siblingX: 查找A元素之前的同级X元素,比如:h1 ~ p
el, el, el:多个选择器组合,查找匹配任一选择器的唯一元素,例如:div.masthead, div.logo
3、Selector伪选择器语法
:lt(n): 查找哪些元素的同级索引值(它的位置在DOM树中是相对于它的父节点)小于n,比如:td:lt(3) 表示小于三列的元素
:gt(n):查找哪些元素的同级索引值大于n,比如: div p:gt(2)表示哪些div中有包含2个以上的p元素
:eq(n): 查找哪些元素的同级索引值与n相等,比如:form input:eq(1)表示包含一个input标签的Form元素
:has(seletor): 查找匹配选择器包含元素的元素,比如:div:has(p)表示哪些div包含了p元素
:not(selector): 查找与选择器不匹配的元素,比如: div:not(.logo) 表示不包含 class=logo 元素的所有 div 列表
:contains(text): 查找包含给定文本的元素,搜索不区分大不写,比如: p:contains(jsoup)
:containsOwn(text): 查找直接包含给定文本的元素
:matches(regex): 查找哪些元素的文本匹配指定的正则表达式,比如:div:matches((?i)login)
:matchesOwn(regex): 查找自身包含文本匹配指定正则表达式的元素
注意:上述伪选择器索引是从0开始的,也就是说第一个元素索引值为0,第二个元素index为1等。
我是根据
String responseflag = HttpClientUtil.getInstance().sendHttpPost("https://birdnet.cn/"+href);
Document documentflag=Jsoup.parse(responseflag);
然后打印出documentflag挨个分析,根据语法找出所需的东西,然后写出来的
网友评论