You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Java如何调用API获取维基共享资源的图片标题与链接

Android Java 实现Wikimedia Commons图片资源抓取方案

1. 接口结构说明

该接口为典型的MediaWiki API返回结构,query.pages不是数组而是以页面ID为key的对象,同时接口采用分页返回逻辑,单次请求最多返回50条数据,需要通过返回的continue字段拉取全量数据。

2. 依赖引入

首先在模块级build.gradle中引入常用的网络请求和JSON解析库:

dependencies {
    // 网络请求库
    implementation 'com.squareup.okhttp3:okhttp:4.11.0'
    // JSON解析库
    implementation 'com.google.code.gson:gson:2.10.1'
    // 安卓异步任务工具,避免阻塞主线程
    implementation 'androidx.concurrent:concurrent-futures:1.1.0'
}

添加网络权限到AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

3. 实体类定义

按照接口返回结构定义对应的Java类,重点处理pages的Map结构:

// 根返回实体
public class ApiResponse {
    @SerializedName("batchcomplete")
    private String batchComplete;
    @SerializedName("continue")
    private ContinueBean continueData;
    private QueryBean query;
    // 自行添加get、set方法
}

// 分页参数实体
public class ContinueBean {
    private String gcmcontinue;
    @SerializedName("continue")
    private String continueStr;
    // 自行添加get、set方法
}

// 查询结果实体
public class QueryBean {
    // 核心:用Map接收key为页面ID的对象集合
    private Map<String, PageBean> pages;
    // 自行添加get、set方法
}

// 单张图片页面实体
public class PageBean {
    private String title;
    @SerializedName("imageinfo")
    private List<ImageInfoBean> imageInfo;
    // 自行添加get、set方法
}

// 图片信息实体
public class ImageInfoBean {
    private String url;
    // 自行添加get、set方法
}

// 最终需要的图片结果实体
public class ImageItem {
    private String title;
    private String imageUrl;
    public ImageItem(String title, String imageUrl) {
        this.title = title;
        this.imageUrl = imageUrl;
    }
    // 自行添加get、set方法
}

4. 核心抓取逻辑

分单页解析和分页拉取全量数据两部分实现:

public class WikimediaFetcher {
    private static final String BASE_API = "https://commons.wikimedia.org/w/api.php?action=query&prop=imageinfo&iiprop=timestamp|user|url&generator=categorymembers&gcmtype=file&gcmtitle=Category:Featured_pictures_on_Wikimedia_Commons&format=json&utf8";
    private final OkHttpClient okHttpClient = new OkHttpClient();
    private final Gson gson = new Gson();
    // 全量结果存储
    private final List<ImageItem> allImageItems = new ArrayList<>();

    // 对外调用入口,需运行在子线程
    public List<ImageItem> fetchAllImages() throws IOException {
        allImageItems.clear();
        String nextContinueParam = "";
        do {
            String requestUrl = BASE_API;
            // 拼接分页参数
            if (!nextContinueParam.isEmpty()) {
                requestUrl += "&gcmcontinue=" + nextContinueParam;
            }
            // 发起网络请求
            Request request = new Request.Builder()
                    .url(requestUrl)
                    .build();
            try (Response response = okHttpClient.newCall(request).execute()) {
                if (!response.isSuccessful() || response.body() == null) {
                    break;
                }
                String jsonStr = response.body().string();
                ApiResponse apiResponse = gson.fromJson(jsonStr, ApiResponse.class);
                // 解析当前页数据
                if (apiResponse.getQuery() != null && apiResponse.getQuery().getPages() != null) {
                    for (Map.Entry<String, PageBean> entry : apiResponse.getQuery().getPages().entrySet()) {
                        PageBean page = entry.getValue();
                        if (page.getImageInfo() != null && !page.getImageInfo().isEmpty()) {
                            String title = page.getTitle();
                            // 可按需去掉标题开头的File:前缀
                            if (title.startsWith("File:")) {
                                title = title.substring(5);
                            }
                            String url = page.getImageInfo().get(0).getUrl();
                            allImageItems.add(new ImageItem(title, url));
                        }
                    }
                }
                // 检查是否存在下一页
                if (apiResponse.getContinueData() != null && apiResponse.getContinueData().getGcmcontinue() != null) {
                    nextContinueParam = apiResponse.getContinueData().getGcmcontinue();
                } else {
                    nextContinueParam = "";
                }
            }
        } while (!nextContinueParam.isEmpty());
        return allImageItems;
    }
}

5. 安卓端调用注意事项

网络请求不能在主线程执行,可通过Thread+Handler实现线程切换:

// Activity中调用示例
new Thread(() -> {
    try {
        List<ImageItem> images = new WikimediaFetcher().fetchAllImages();
        // 切换到主线程更新UI
        runOnUiThread(() -> {
            // 此处更新列表UI逻辑
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}).start();

内容的提问来源于stack exchange,提问作者Mohammad Mustafa Raza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 05:54:01