- 作为开发者,接入微信开放平台,获取用户在微信内分享的图片、视频等文件。 这是最常见的需求,比如用户从微信聊天记录中选择图片上传到你的 App。
- 作为开发者,抓取微信公众号文章、视频号内容中的媒体文件。 这涉及到网页爬虫技术,但需要注意微信的反爬机制和版权问题。
下面我将针对这两种场景,提供详细的 Java 实现方案和代码示例。

接入微信开放平台,处理用户上传的文件
这个场景的核心是利用微信提供的 JS-SDK,用户在你的网页或 H5 页面中,通过微信内置的浏览器选择文件,然后你的服务器通过微信服务器获取这个文件的临时链接,最后再从微信服务器下载文件到你的服务器。
核心流程
- 用户授权:你的网页通过微信 JS-SDK 获取用户操作权限(如
chooseImage,chooseVideo)。 - 用户选择文件:用户在微信内选择图片或视频,微信客户端会将文件的临时 Media ID 返回给你的网页。
- 网页发送 Media ID 到你的服务器:你的前端 JavaScript 代码将收到的 Media ID 发送到你自己的后端 Java 服务。
- 后端调用微信接口获取下载链接:你的 Java 服务器使用 AppID 和 AppSecret,通过微信的
https://api.weixin.qq.com/cgi-bin/media/get接口,用 Media ID 换取一个临时的 HTTPS 下载链接。 - 后端下载文件并保存:你的 Java 服务器使用上一步获取的 HTTPS 链接,向微信服务器发起请求,将文件流下载并保存到你自己的服务器上。
准备工作
- 注册微信开放平台账号:并创建一个移动应用或网站应用,获取
AppID和AppSecret。 - 获取 Access Token:调用微信接口需要
access_token,它是调用接口的凭证,它有有效期(通常为2小时),需要缓存并定时刷新。 - 配置 JS-SDK 权限:在开放平台后台为你的应用配置 JS-SDK 的使用权限。
Java 实现步骤
添加 Maven 依赖
为了方便发送 HTTP 请求和处理 JSON,我们使用 OkHttp 和 Fastjson。
<dependencies>
<!-- OkHttp for HTTP requests -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
<!-- Fastjson for JSON processing -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
获取 Access Token

创建一个工具类来管理 access_token。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class WeChatAccessTokenUtil {
private static final String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=YOUR_APPID&secret=YOUR_APPSECRET";
private static OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
private static String accessToken;
private static long expireTime;
public static synchronized String getAccessToken() {
if (accessToken != null && System.currentTimeMillis() < expireTime) {
return accessToken;
}
Request request = new Request.Builder().url(GET_TOKEN_URL).build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JSONObject jsonObject = JSON.parseObject(responseBody);
accessToken = jsonObject.getString("access_token");
// 有效期减去5分钟作为缓冲
expireTime = System.currentTimeMillis() + (jsonObject.getLong("expires_in") - 300) * 1000;
return accessToken;
} else {
// 处理错误
System.err.println("Failed to get access token: " + response.code());
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
请将 YOUR_APPID 和 YOUR_APPSECRET 替换为你自己的信息。
下载多媒体文件的核心方法
这是最关键的一步,通过 Media ID 获取文件流。

import okhttp3.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
public class WeChatMediaDownloader {
private static final String GET_MEDIA_URL = "https://api.weixin.qq.com/cgi-bin/media/get?media_id=%s&access_token=%s";
private static OkHttpClient client = new OkHttpClient();
/**
* 根据Media ID下载文件
* @param mediaId 微信返回的媒体ID
* @param saveDir 保存到服务器的目录
* @return 下载后文件的本地路径
*/
public static String downloadMedia(String mediaId, String saveDir) {
String accessToken = WeChatAccessTokenUtil.getAccessToken();
if (accessToken == null) {
System.err.println("Cannot get access token.");
return null;
}
String fileUrl = String.format(GET_MEDIA_URL, mediaId, accessToken);
Request request = new Request.Builder().url(fileUrl).build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
System.err.println("Download failed with code: " + response.code());
return null;
}
// 获取响应头,判断文件类型(可选)
String contentType = response.header("Content-Type");
System.out.println("Content-Type: " + contentType);
// 从URL推断文件后缀名
String extension = getFileExtension(contentType);
String fileName = UUID.randomUUID().toString() + extension;
// 保存文件
File outputFile = new File(saveDir, fileName);
try (InputStream inputStream = response.body().byteStream();
FileOutputStream outputStream = new FileOutputStream(outputFile)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
System.out.println("File downloaded successfully to: " + outputFile.getAbsolutePath());
return outputFile.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static String getFileExtension(String contentType) {
if (contentType == null) {
return ".file"; // 默认后缀
}
if (contentType.contains("image/jpeg")) {
return ".jpg";
} else if (contentType.contains("image/png")) {
return ".png";
} else if (contentType.contains("image/gif")) {
return ".gif";
} else if (contentType.contains("video/mp4")) {
return ".mp4";
}
// 可以根据需要添加更多类型
return ".unknown";
}
}
如何调用
你的 Java 后端会从前端接收到 mediaId,然后调用上面的方法。
public class Main {
public static void main(String[] args) {
// 这个 mediaId 是由你的前端 JS-SDK 从微信客户端获取后,发送到后端的
String mediaIdFromFrontend = "YOUR_MEDIA_ID_FROM_WECHAT";
// 确保你的服务器有这个目录的写权限
String saveDirectory = "/path/to/your/server/storage/directory";
// 调用下载方法
String localFilePath = WeChatMediaDownloader.downloadMedia(mediaIdFromFrontend, saveDirectory);
if (localFilePath != null) {
System.out.println("File processing complete. Local path: " + localFilePath);
// 后续逻辑,如将文件路径存入数据库等
} else {
System.out.println("File download failed.");
}
}
}
抓取微信公众号/视频号内容(网页爬虫)
⚠️ 重要提示: 未经授权抓取和发布他人内容可能涉及版权侵权和违反微信用户协议,此方案仅用于学习和研究目的,请勿用于商业用途或恶意爬取。
核心思路
- 获取公众号文章链接:通过搜索或已知方式找到目标文章的 URL。
- 获取网页内容:使用 Java HTTP 客户端(如 OkHttp)请求该 URL。
- 处理反爬机制:微信有很强的反爬机制,直接请求可能会被重定向或返回错误页面,你需要模拟真实浏览器行为,设置
User-Agent,并处理可能的登录态验证。 - 解析 HTML:使用 HTML 解析器(如 Jsoup)从返回的 HTML 中提取出
<img>标签的src属性(图片链接)和<video>标签的src属性(视频链接)。 - 下载媒体文件:获取到直接的媒体链接后,再次使用 OkHttp 将其下载到本地。
Java 实现步骤
添加 Maven 依赖
<dependencies>
<!-- OkHttp for HTTP requests -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
<!-- Jsoup for HTML parsing -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
</dependencies>
爬取和下载代码示例
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
public class WeChatArticleCrawler {
private static final OkHttpClient client = new OkHttpClient();
// 模拟 Chrome 浏览器的 User-Agent
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
/**
* 从微信公众号文章中下载所有图片
* @param articleUrl 微信公众号文章链接
* @param saveDir 保存目录
*/
public static void downloadImagesFromArticle(String articleUrl, String saveDir) {
try {
// 1. 获取网页内容
String htmlContent = getHtmlContent(articleUrl);
if (htmlContent == null) {
System.err.println("Failed to fetch article content.");
return;
}
// 2. 使用 Jsoup 解析 HTML
Document doc = Jsoup.parse(htmlContent);
// 选择文章内容区域内的所有 img 标签
// 注意:选择器可能需要根据微信最新的HTML结构调整
Elements imgElements = doc.select("#js_content img");
System.out.println("Found " + imgElements.size() + " images.");
// 3. 遍历并下载图片
for (Element img : imgElements) {
String imgUrl = img.attr("src");
if (imgUrl != null && !imgUrl.isEmpty()) {
System.out.println("Downloading image: " + imgUrl);
downloadMediaFile(imgUrl, saveDir, ".jpg");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getHtmlContent(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.header("User-Agent", USER_AGENT)
// 可以添加更多头信息来模拟浏览器
.addHeader("Referer", "https://weixin.qq.com/") // 设置来源页面
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
return response.body().string();
} else {
System.err.println("HTTP request failed with code: " + response.code());
// 检查是否被重定向到登录页面
System.err.println("Response message: " + response.message());
return null;
}
}
}
private static void downloadMediaFile(String fileUrl, String saveDir, String defaultExtension) {
Request request = new Request.Builder().url(fileUrl).build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
System.err.println("Download failed for " + fileUrl + " with code: " + response.code());
return;
}
String fileName = UUID.randomUUID().toString() + defaultExtension;
File outputFile = new File(saveDir, fileName);
try (InputStream inputStream = response.body().byteStream();
FileOutputStream outputStream = new FileOutputStream(outputFile)) {
byte[] buffer = new new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
System.out.println("Downloaded: " + outputFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 示例:一个公众号文章链接
String articleUrl = "https://mp.weixin.qq.com/s/xxxxxxxxxxxx"; // 替换为真实链接
String saveDirectory = "/path/to/your/article_images"; // 确保目录存在且有权限
// 创建目录(如果不存在)
new File(saveDirectory).mkdirs();
downloadImagesFromArticle(articleUrl, saveDirectory);
}
}
总结与对比
| 特性 | 场景一 (JS-SDK) | 场景二 (网页爬虫) |
|---|---|---|
| 合法性 | 高,官方推荐流程,合规。 | 低,可能违反用户协议和版权,有法律风险。 |
| 稳定性 | 高,接口稳定,微信官方维护。 | 低,微信会频繁更新页面结构和反爬策略,代码容易失效。 |
| 适用范围 | 获取用户主动选择并授权分享的文件。 | 获取(如文章、视频号)中的媒体文件。 |
| 技术复杂度 | 中等,需要理解 JS-SDK 流程,管理 Access Token。 | 较高,需要处理反爬、模拟登录、解析动态内容等。 |
| 核心 API | https://api.weixin.qq.com/cgi-bin/media/get |
无直接 API,依赖 HTTP 请求和 HTML 解析。 |
如果你的需求是处理用户从微信中选择并分享给你的 App 的文件,请务必使用场景一(JS-SDK)的方案,这是最标准、最稳定、最合规的方式。
如果你只是想学习爬虫技术或为自己的公众号管理工具抓取内容,可以使用场景二的方案,但务必遵守法律法规和平台规则。
