大多数随机图片api都是采用直接跳转的方式,最常见的就是直接跳转到一些免费的图床,比如新浪图床,当然也有一些并没有进行302/301重定向直接返回图片的,本文仅针对跳转的api
随机图片,未免会随机到一点相同的,因此要进行重复判断,最简单的办法就是将重定向后的网址保存到本地,之后爬取都读取一下之前的记录,发现有重复的就不再下载。
先编写好一些文件操作的实用方法:
/**
* 输出文件到本地目录
*
* @param image
*/
public static void out(BufferedImage image, String filepath, String formatName) {
File outputfile = new File(filepath);
if (!outputfile.getParentFile().exists()) {
outputfile.getParentFile().mkdirs();
}
try {
ImageIO.write(image, formatName, outputfile);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void appendTxt(String str, String filepath) {
FileWriter fw = null;
try {
//如果文件存在,则追加内容;如果文件不存在,则创建文件
File f = new File(filepath);
fw = new FileWriter(f, true);
} catch (IOException e) {
e.printStackTrace();
}
PrintWriter pw = new PrintWriter(fw);
pw.println(str);
pw.flush();
try {
fw.flush();
pw.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读取一个文本 一行一行读取
*
* @param path
* @return
* @throws IOException
*/
public static List<String> readFile(String path) throws IOException {
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
// 使用一个字符串集合来存储文本中的路径 ,也可用String []数组
List<String> list = new ArrayList<>();
FileInputStream fis = new FileInputStream(path);
// 防止路径乱码 如果utf-8 乱码 改GBK eclipse里创建的txt 用UTF-8,在电脑上自己创建的txt 用GBK
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null) {
list.add(line);
}
br.close();
isr.close();
fis.close();
return list;
}
/**
* 获取后缀
*
* @return
*/
public static String getFileHouZhui(String filename) {
String[] strArray = filename.split("\\.");
if (strArray.length <= 1) {
return filename;
}
return strArray[strArray.length - 1];
}
public static String getUrlHOUZHUI(String url) {
String[] split = url.split("/");
return split[split.length - 1];
}
然后获取重定向后的网址,这边提供两种方式,以防止一种获取失效:
public static String getRealUrl(String urlstr) throws IOException {
URL url = new URL(urlstr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.getResponseCode();
String realUrl = conn.getURL().toString();
conn.disconnect();
return realUrl;
}
public static String getRealUrl2(String urlstr) throws IOException {
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(urlstr);
HttpParams params = client.getParams();
params.setParameter(AllClientPNames.HANDLE_REDIRECTS, false);
client.executeMethod(method);
return method.getURI().getURI();
}
编写main主方法逻辑,偷懒就全写一个类里了...
public static void main(String[] args) {
int methodHttp = 1; //设置默认爬取方式
try {
for (int i = 0; i < NUM; i++) {
String realUrl = null;
//实现爬取方案自动切换
if (methodHttp == 1){
realUrl = getRealUrl(CATCHURL);
if (realUrl.equals(CATCHURL)){
methodHttp = 2;
continue;
}
}else if (methodHttp == 2){
realUrl = getRealUrl2(CATCHURL);
if (realUrl.equals(CATCHURL)){
methodHttp = 1;
continue;
}
}
//遍历获取记录文件每一行的内容
List<String> strings = readFile(PATH + TXTNAME);
boolean flag = false;
for (String string : strings) {
//对于新浪图床,有多个服务器,因此需要取网址后缀文件名进行判断
if (getUrlHOUZHUI(string).equals(getUrlHOUZHUI(realUrl))) {
System.err.println("相同文件,取消下载!");
flag = true;
break;
}
}
if (flag) {
continue;
}
System.out.println((i + 1) + "/" + NUM + "开启爬取:" + realUrl);
BufferedImage image = ImageIO.read(new URL(realUrl));
//获取url后缀以重命名文件
String urlHOUZHUI = getUrlHOUZHUI(realUrl);
//获取文件后缀以输出对应的文件
String fileHouZhui = getFileHouZhui(urlHOUZHUI);
if (fileHouZhui.equals(urlHOUZHUI)){
fileHouZhui = "jpg";
urlHOUZHUI = urlHOUZHUI + ".jpg";
}
out(image, PATH + urlHOUZHUI, fileHouZhui);
appendTxt(realUrl, PATH + TXTNAME);
}
} catch (IOException e) {
e.printStackTrace();
}
}
注意:对于新浪图床这种有多个服务器的网站,需要判断网址后面的文件名称而不是整个网址!
例如https://tva2.sinaimg.cn/large/0072Vf1pgy1fodqoshzhbj31d60ytawh.jpg和https://tva1.sinaimg.cn/large/0072Vf1pgy1fodqoshzhbj31d60ytawh.jpg是同一张图片
声明下变量
private final static String TXTNAME = "result.txt";
private final static String PATH = "D:\\下载\\catchpic\\";
private final static String CATCHURL = "http://www.dmoe.cc/random.php";
private final static int NUM = 500;
由于有时候爬取会出现这种场景,因此建议在代码中加入一个小判断
if (getUrlHOUZHUI(realUrl).equals(".jpg")){
continue;
}
针对于另一种返回html页面的接口,经过分析发现中间仅有一个img标签,因此取img标签的src
属性即可,参考代码如下:
//需要引入Jsonip的依赖,当然也可以用正则或者字符串的方法等
//针对返回一个html页面的接口
HttpResponse httpResponse = HttpUtils.doGet(CATCHURL, null, HttpUtils.getHeaders(), null);
String s = EntityUtils.toString(httpResponse.getEntity());
Document document = Jsoup.parse(s);
Elements img = document.select("img");
//realUrl = "https:" + img.attr("src");
realUrl = img.attr("src");
分别是哔哩哔哩序号35,小米运动序号2,米友社序号13,这个是同一个账号下运行的任务