背景
近期GF写论文需要爬取Flickr网站上的某个关键词的所有图片信息,并且生成excel用于数据分析。在找了许多资料之后,实现了该功能,其实难度并不大,在Flickr官方API文档中写的也挺详细的,而且还有官方Flickr4JavaDemo,只是过程中容易遇到了一些坑,特此记下,方便后人。
实现功能
搜索某关键字,获取到Flickr中匹配到该关键字的图片,并获取其中的包括图片ID,用户信息,图片链接,图片经纬度信息及拍摄信息等等,最后导入到excel中。
准备工作
1.一台可以访问flickr的电脑
2.IDEA
3.jdk1.8(官方规定jdk要在1.8及以上)
实现过程
工程是依赖Maven构建的,IDE采用IDEA
导入官方API
在pom.xml中加入
<dependency>
<groupId>com.flickr4java</groupId>
<artifactId>flickr4java</artifactId>
<version>2.19</version>
</dependency>
调用API
使用api的时候,需要在flickr申请key和secret。
贴出主要代码,完整项目请移步github
package com.liushiyao.flickr;
import com.flickr4java.flickr.Flickr;
import com.flickr4java.flickr.FlickrException;
import com.flickr4java.flickr.REST;
import com.flickr4java.flickr.photos.Photo;
import com.flickr4java.flickr.photos.PhotoList;
import com.flickr4java.flickr.photos.PhotosInterface;
import com.flickr4java.flickr.photos.SearchParameters;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public class SearchExample
{
static String apiKey = "自己的key";
static String sharedSecret = "自己的secret";
public static final int MAX_PRE_PAGE = 500;
Flickr flickr;
public SearchExample() throws IOException
{
flickr = new Flickr(apiKey, sharedSecret, new REST());
Flickr.debugRequest = false;
Flickr.debugStream = false;
}
private PhotoList<Photo> search(String text) throws FlickrException
{
PhotosInterface photos = flickr.getPhotosInterface();
SearchParameters params = new SearchParameters();
Set<String> strings = new HashSet<String>();
strings.add("date_taken");
strings.add("tags");
strings.add("title");
strings.add("geo"); //获取经纬度信息,如果没有设置woeid则此项没有返回结果
strings.add("owner_name");
params.setExtras(strings); //额外信息
String [] tags = new String[] {"广州"};
params.setTags(tags);
params.setText(text);
params.setWoeId("26198245"); //woeid-地点id,可以在https://www.flickr.com/places/info/26198245 查询
params.setMinTakenDate(new Date(1093996800));
params.setSort(SearchParameters.DATE_POSTED_DESC);
PhotoList<Photo> photoPhotoList = new PhotoList<Photo>();
int index = 1,pages = 1;
do {
PhotoList<Photo> results = photos.search(params, MAX_PRE_PAGE, index);
if(results != null && !results.isEmpty()){
photoPhotoList.addAll(results);
}
pages = results.getPages();//分页后共有多少页
int page = results.getPage();
System.out.println("进度:"+page+"/"+pages+"页");
index++;
}while (index < pages);
return photoPhotoList;
}
public static void main(String[] args) throws Exception
{
SearchExample t = new SearchExample();
PhotoList<Photo> photoPhotoList= t.search(args.length == 0 ? "广州" : args[0]);
System.out.println("总共:"+photoPhotoList.size()+"条数据");
// 创建工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建工作表
HSSFSheet sheet = workbook.createSheet("sheet1");
//标题
HSSFRow titleRows = sheet.createRow(0);
titleRows.createCell(0).setCellValue("id");
titleRows.createCell(1).setCellValue("用户名称");
titleRows.createCell(2).setCellValue("图片标题");
titleRows.createCell(3).setCellValue("拍摄时间");
titleRows.createCell(4).setCellValue("标签");
titleRows.createCell(5).setCellValue("图片链接");
titleRows.createCell(6).setCellValue("经度");
titleRows.createCell(7).setCellValue("纬度");
for (int row = 0; row < photoPhotoList.size(); row++)
{
HSSFRow rows = sheet.createRow(row+1);
// 向工作表中添加数据
rows.createCell(0).setCellValue(photoPhotoList.get(row).getId());
rows.createCell(1).setCellValue(photoPhotoList.get(row).getOwner().getUsername());
rows.createCell(2).setCellValue(photoPhotoList.get(row).getTitle());
rows.createCell(3).setCellValue(new SimpleDateFormat("yyy-MM-dd").format(photoPhotoList.get(row).getDateTaken()));
rows.createCell(4).setCellValue(Arrays.toString(photoPhotoList.get(row).getTags().toArray()));
rows.createCell(5).setCellValue(photoPhotoList.get(row).getLargeUrl());
rows.createCell(6).setCellValue(photoPhotoList.get(row).getGeoData().getLongitude());
rows.createCell(7).setCellValue(photoPhotoList.get(row).getGeoData().getLatitude());
}
sheet.createRow(photoPhotoList.size()+2).createCell(0).setCellValue("总数:"+photoPhotoList.size()+"条");
File xlsFile = new File("data.xls");
FileOutputStream xlsStream = new FileOutputStream(xlsFile);
workbook.write(xlsStream);
}
}
设置代理(重点)
前面代码部分很简单,不懂的可以去查查官方的API文档。设置代理正是该篇文章所介绍的重点。
因为Flickr在国内是无法直接访问的,所以需要FQ。成功FQ之后,浏览器可以访问了,但是IDEA并不可以方位到,所以IDEA需要设置代理。
IDEA无法访问,所以一直报连接超时的错误:
org.scribe.exceptions.OAuthConnectionException: There was a problem while creating a connection to the remote service.
at org.scribe.model.Request.send(Request.java:70)
at org.scribe.model.Request.send(Request.java:76)
at com.flickr4java.flickr.REST.get(REST.java:174)
at com.flickr4java.flickr.photos.PhotosInterface.search(PhotosInterface.java:1047)
at com.liushiyao.flickr.SearchExample.search(SearchExample.java:63)
at com.liushiyao.flickr.SearchExample.main(SearchExample.java:89)
Caused by: java.net.ConnectException: Connection timed out: connect
1.首先设置shadowsocks为全局代理
2.设置IDEA代理
Settings->HTTP Proxy中设置:
在HTTP的tab下填写shadowsocks中的账号密码,然后点击check connection,输入Flickr的网址,检查一下IDEA是否能够访问Flickr
成功访问!(这一步是让IDEA可以FQ,如果只是让程序可以访问,可以省略这一步,直接操作第三部)
3.设置jvm代理
执行第二步,运行程序依然连接超时,经过多番查找,终于发现仍有一个地方需要设置–jvm参数。设置IDEA代理只是让IDEA可以FQ,但是java程序并不可以,所以需要如下设置:
在运行java程序前,我们可以设置程序参数或者是jvm参数,如上图。
我们需要在vm options这一栏中输入:
-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=1080 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=1080
这样jvm成功映射到这个端口,这样程序就可以跑起来了。
运行结果
大功告成!
常见问题
- SLF4J报错
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
原因是官方项目中少了依赖,在pom.xml中添加以及代码就好
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
总结
代码并不难,官网也有例子,麻烦的是代理设置,花了不少时间,特写此文。