Commit ea3ae1b6 authored by zsq's avatar zsq

完成爬取公众号和文章

parents
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/
# Java爬取公众号文章
# 项目介绍
> 前提是你得有一个公众号账号
1. 用接口模拟公众号扫码登录,得到登录状态的cookie和token
2. 有了登录状态就可以请求搜索公众号接口
3. 选中公众号,查询该公众号发布的文章
# 技术栈
1. Java
2. OkHttp3
3. Cookie管理
4. Jackson
5. Java awt包,用来显示二维码图片
6. FutureTask 线程返回值
# 演示
## 得到二维码图片,手机端扫描
![](./doc/images/1.png)
## 扫码确认,搜索公众号
![](./doc/images/2.png)
## 搜索公众号下的文章列表
![](./doc/images/3.png)
# 待探索的功能
1. Cookie持久化,本地序列化或者redis分布式
2. IP代理池
3. 做成SpringBoot项目,定时爬取文章
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>top.iszsq</groupId>
<artifactId>sq-weixin-api-demo</artifactId>
<version>0.1</version>
<packaging>jar</packaging>
<description>模拟登陆微信公众号后台,调用搜索公众号、公众号文章等接口</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- OKHttp3依赖 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.8.1</version>
</dependency>
<!-- 工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<!-- json序列化-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.2</version>
<scope>compile</scope>
</dependency>
<!-- 工具包-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- 单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package top.iszsq.weixin;
import org.apache.commons.lang3.StringUtils;
import top.iszsq.weixin.api.WeiXinApi;
import top.iszsq.weixin.awt.MyImageShowFrame;
import top.iszsq.weixin.model.Article;
import top.iszsq.weixin.model.BizData;
import top.iszsq.weixin.model.WxResultBody;
import top.iszsq.weixin.okhttp.MyCookieStore;
import top.iszsq.weixin.okhttp.MyOkHttpClient;
import top.iszsq.weixin.utils.HttpUtils;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 程序主入口
* @author zsq
* @version 1.0
* @date 2021/3/31 10:57
*/
public class Application {
private static MyImageShowFrame myImageShowFrame;
/**
* 主入口
* @param args
*/
public static void main(String[] args) throws IOException {
//图片显示控件
myImageShowFrame = new MyImageShowFrame();
// 1. POST请求开始登录接口,初始化cookie
String sessionid = "" + System.currentTimeMillis() + (int)(Math.random()*100);
WxResultBody wxResultBody = WeiXinApi.startLogin(sessionid);
System.out.println("---请求开始登录接口 返回结果:" + wxResultBody.toString());
// 2. 请求获取二维码图片接口,得到流
InputStream qrCodeIs = WeiXinApi.getQRCode();
//转成图片显示
myImageShowFrame.showImage(qrCodeIs);
// 3.轮询二维码状态接口
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
while (true) {
WxResultBody askQRCode = WeiXinApi.askQRCode();
Integer status = askQRCode.getStatus();
if (status == 3) {
System.out.println("二维码已过期");
return 3;
} else if (status == 4) {
System.out.println("已扫码,等待确认");
} else if (status == 1) {
System.out.println("已确认登录,请稍后...");
return 1;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
while (true) {
Thread queryThread = new Thread(futureTask);
queryThread.start();
if (!futureTask.isDone()) {
System.out.println("--正在查询扫码状态,请尽快扫码!");
}
try {
Integer integer = futureTask.get();
if (integer == 1) {
//说明扫码确认成功,否则重新获取图片
//关闭图片显示
myImageShowFrame.close();
break;
} else {
//重新获取二维码图片显示
myImageShowFrame.showImage(WeiXinApi.getQRCode());
}
} catch (Exception e) {
System.out.println("查询接口出错了");
break;
}
}
// 4.确认登录后,请求登录接口,拿到登录状态的cookie
WxResultBody bizlogin = WeiXinApi.bizlogin();
//重定向地址
String redirect_url = bizlogin.getRedirect_url();
//解析成键值对
Map<String, String> loginRes = HttpUtils.parseQueryParams(redirect_url);
//得到token
String token = loginRes.get("token");
//设置全局token值
MyCookieStore.setToken(token);
System.out.println("---恭喜你,登录成功!");
// ok
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("----请输入你想搜索的公众号:");
String gzName = scanner.nextLine();
if (StringUtils.isBlank(gzName)) {
System.out.println("--不能搜空的");
continue;
}
System.out.println("开始搜索:" + gzName);
WxResultBody<List<BizData>> searchBiz = WeiXinApi.searchBiz(gzName);
System.out.println("----请按序号选择公众号");
List<BizData> list = searchBiz.getList();
int ii = 1;
for (BizData bizData : list) {
System.out.println( ii + ":" + bizData.getNickname());
ii++;
}
int index = 0;
while (true) {
try {
String numStr = scanner.nextLine();
index = Integer.parseInt(numStr);
if (index < 0 || index > list.size()) {
System.out.println("超出范围了,重选!!");
}
break;
} catch (Exception e){
System.out.println("你得输入一个数字!!!!");
}
}
BizData select = list.get(index - 1);
System.out.println(String.format("--好的,开始搜索【%s】的文章...", select.getNickname()));
WxResultBody<List<Article>> findExList = WeiXinApi.findExList(select.getFakeid());
List<Article> exList = findExList.getApp_msg_list();
for (Article article : exList) {
System.out.println("---" + article.getTitle());
}
}
}
}
package top.iszsq.weixin;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 16:09
*/
public class MyScanner {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入你想搜索的公众号:");
String line = scanner.nextLine();
System.out.println("你输入的是:" + line);
//搜索公众号列表
List<String> list = new ArrayList<>();
list.add("csdn");
list.add("csdn2");
list.add("csdn3");
System.out.println("----请按序号选择公众号");
int i = 1;
for (String item : list) {
System.out.println( i + ":" + item);
i++;
}
}
}
}
package top.iszsq.weixin.api;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.StringUtils;
import top.iszsq.weixin.enums.WxResultStatus;
import top.iszsq.weixin.exceptions.WxApiException;
import top.iszsq.weixin.model.Article;
import top.iszsq.weixin.model.BizData;
import top.iszsq.weixin.model.WxResultBody;
import top.iszsq.weixin.okhttp.MyCookieStore;
import top.iszsq.weixin.utils.HttpUtils;
import top.iszsq.weixin.utils.JsonUtils;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 微信api封装
* @author zsq
* @version 1.0
* @date 2021/3/31 11:13
*/
public class WeiXinApi {
/**接口地址**/
public static final Map<String, String> URL_MAP = new HashMap<>();
static {
//初始化登录cookie
URL_MAP.put("startLogin", "https://mp.weixin.qq.com/cgi-bin/bizlogin?action=startlogin");
//二维码图片接口
URL_MAP.put("getqrcode", "https://mp.weixin.qq.com/cgi-bin/scanloginqrcode");
//二维码扫描状态接口
URL_MAP.put("qrcodeAsk", "https://mp.weixin.qq.com/cgi-bin/scanloginqrcode");
//扫码确认后,登录接口
URL_MAP.put("bizlogin", "https://mp.weixin.qq.com/cgi-bin/bizlogin?action=login");
//扫码确认后,登录接口
URL_MAP.put("searchbiz", "https://mp.weixin.qq.com/cgi-bin/searchbiz");
//扫码确认后,登录接口
URL_MAP.put("findListEx", "https://mp.weixin.qq.com/cgi-bin/appmsg");
}
/**
* POST请求开始登录接口,初始化cookie
* @param sessionid 时间戳,加两位随机数
* @return
*/
public static WxResultBody startLogin(String sessionid) {
if (StringUtils.isBlank(sessionid)) {
sessionid = "" + System.currentTimeMillis() + (int)(Math.random()*100);
}
Map<String, String> params = new HashMap<>(8);
params.put("sessionid", sessionid);
params.put("userlang", "zh_CN");
params.put("redirect_url", "");
params.put("login_type", "3");
params.put("token", "");
params.put("lang", "zh_CN");
params.put("f", "json");
params.put("ajax", "1");
WxResultBody wxResultBody = parseWxResultBody(HttpUtils.doPost(URL_MAP.get("startLogin"), params));
return wxResultBody;
}
/**
* 获取二维码图片 字节输出流
* @return
*/
public static InputStream getQRCode() {
Map<String, String> params = new HashMap<>(2);
params.put("action", "getqrcode");
params.put("random", System.currentTimeMillis() + "");
InputStream inputStream = HttpUtils.doGetStream(URL_MAP.get("getqrcode"), params);
return inputStream;
}
/**
* GET 轮询二维码状态接口
* @return
*/
public static WxResultBody askQRCode() {
Map<String, String> params = new HashMap<>(5);
params.put("action", "ask");
params.put("token", "");
params.put("lang", "zh_CN");
params.put("f", "json");
params.put("ajax", "1");
WxResultBody wxResultBody = parseWxResultBody(HttpUtils.doGet(URL_MAP.get("qrcodeAsk"), params));
return wxResultBody;
}
/**
* 扫码确认后,登录接口
* @return
*/
public static WxResultBody bizlogin() {
Map<String, String> params = new HashMap<>(10);
params.put("userlang", "zh_CN");
params.put("redirect_url", "");
params.put("cookie_forbidden", "0");
params.put("cookie_cleaned", "0");
params.put("plugin_used", "0");
params.put("login_type", "3");
params.put("token", "");
params.put("lang", "zh_CN");
params.put("f", "json");
params.put("ajax", "1");
WxResultBody wxResultBody = parseWxResultBody(HttpUtils.doPost(URL_MAP.get("bizlogin"), params));
return wxResultBody;
}
/**
* 搜索公众号
* @return
*/
public static WxResultBody<List<BizData>> searchBiz(String keyword){
Map<String, String> params = new HashMap<>(10);
params.put("action", "search_biz");
params.put("begin", "0");
params.put("count", "5");
params.put("query", keyword);
params.put("token", MyCookieStore.getToken());
params.put("lang", "zh_CN");
params.put("f", "json");
params.put("ajax", "1");
WxResultBody<List<BizData>> wxResultBody = parseWxResultBody(HttpUtils.doGet(URL_MAP.get("searchbiz"), params),
new TypeReference<WxResultBody<List<BizData>>>() {}
);
return wxResultBody;
}
/**
* 搜索公众号的文章
* @return
*/
public static WxResultBody<List<Article>> findExList(String fakeid){
Map<String, String> params = new HashMap<>(10);
params.put("action", "list_ex");
params.put("begin", "0");
params.put("count", "5");
params.put("fakeid", fakeid);
params.put("token", MyCookieStore.getToken());
params.put("type", "9");
params.put("query", "");
params.put("lang", "zh_CN");
params.put("f", "json");
params.put("ajax", "1");
WxResultBody<List<Article>> wxResultBody = parseWxResultBody(HttpUtils.doGet(URL_MAP.get("findListEx"), params),
new TypeReference<WxResultBody<List<Article>>>() {}
);
return wxResultBody;
}
/**
* 转成java bean
* @param jsonRes json结果字符串
* @return
*/
public static WxResultBody parseWxResultBody(String jsonRes) {
WxResultBody wxResultBody = JsonUtils.jsonToObj(jsonRes, WxResultBody.class);
checkIsSuccess(wxResultBody);
return wxResultBody;
}
/**
* 转成java bean
* @param jsonRes json结果字符串
* @return
*/
public static <T> T parseWxResultBody(String jsonRes, TypeReference<T> typeReference) {
T wxResultBody = JsonUtils.jsonToObj(jsonRes, typeReference);
checkIsSuccess((WxResultBody) wxResultBody);
return wxResultBody;
}
public static void checkIsSuccess(WxResultBody wxResultBody) {
// 判断是否请求成功
if (wxResultBody == null) {
throw new WxApiException(WxResultStatus.FAIL_NULL_RES);
}
if (wxResultBody.getBase_resp().getRet() == null
|| wxResultBody.getBase_resp().getRet() != 0) {
throw new WxApiException(WxResultStatus.FAIL_STATUS);
}
}
}
package top.iszsq.weixin.awt;
import javax.swing.*;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 显示一张图片
* @author zsq
* @version 1.0
* @date 2021/3/31 11:01
*/
public class MyImageShowFrame extends JFrame {
public MyImageShowFrame() {
this.setSize(450, 450);
this.setDefaultCloseOperation(2);
}
public void showImage(InputStream is) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len = 0;
while ( (len = is.read(buff)) > -1 ) {
os.write(buff, 0, len);
}
ImageIcon icon = new ImageIcon(os.toByteArray());
JButton button = new JButton();
button.setMargin(new java.awt.Insets(0, 0, 0, 0));
button.setIcon(icon);
button.setPreferredSize(new Dimension(400,400));
this.setPreferredSize(new Dimension(icon.getIconWidth() - 1, icon.getIconHeight() - 1));
this.getContentPane().add(button);
this.setVisible(true);
}
public void close() {
this.setVisible(false);
}
}
package top.iszsq.weixin.enums;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 14:19
*/
public enum WxResultStatus {
/**请求成功**/
SUCCESS(200, "成功"),
/**请求失败**/
FAIL(500, "请求失败"),
/**返回结果对象解析失败**/
FAIL_NULL_RES(510, "返回结果对象解析失败"),
/**返回结果为失败状态**/
FAIL_STATUS(520, "返回结果为失败状态"),
/**读取io流失败**/
FAIL_IO_ERR(530, "读取io流失败")
;
private int status;
private String name;
WxResultStatus(int status, String name){
this.status = status;
this.name = name;
}
}
package top.iszsq.weixin.exceptions;
import top.iszsq.weixin.enums.WxResultStatus;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 14:37
*/
public class WxApiException extends RuntimeException {
/**错误枚举**/
private WxResultStatus wxResultStatus;
public WxApiException(WxResultStatus wxResultStatus) {
super(wxResultStatus.name());
this.wxResultStatus = wxResultStatus;
}
public WxApiException(WxResultStatus wxResultStatus, Exception e) {
super(wxResultStatus.name(), e);
this.wxResultStatus = wxResultStatus;
}
public WxResultStatus getWxResultStatus() {
return wxResultStatus;
}
}
package top.iszsq.weixin.model;
/**
* 文章数据
* @author zsq
* @date 2021/3/31 - 21:54
*/
public class Article {
private String title;
//...还有很多参数
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return "Article{" +
"title='" + title + '\'' +
'}';
}
}
package top.iszsq.weixin.model;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 11:18
*/
public class BaseResp {
private String err_msg;
private Integer ret;
public String getErr_msg() {
return err_msg;
}
public void setErr_msg(String err_msg) {
this.err_msg = err_msg;
}
public Integer getRet() {
return ret;
}
public void setRet(Integer ret) {
this.ret = ret;
}
@Override
public String toString() {
return "BaseResp{" +
"err_msg='" + err_msg + '\'' +
", ret=" + ret +
'}';
}
}
package top.iszsq.weixin.model;
/**
* 公众号数据
* @author zsq
* @date 2021/3/31 - 21:38
*/
public class BizData {
private String fakeid;
private String nickname;
// ...还有很多参数
public String getFakeid() {
return fakeid;
}
public void setFakeid(String fakeid) {
this.fakeid = fakeid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Override
public String toString() {
return "BizData{" +
"fakeid='" + fakeid + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
package top.iszsq.weixin.model;
/**
* 微信接口返回内容
* @author zsq
* @version 1.0
* @date 2021/3/31 11:17
*/
public class WxResultBody<L> {
private Integer acct_size;
private String err_msg;
private String redirect_url;
private Integer ret;
private Integer status;
private Integer user_category;
private BaseResp base_resp;
private L list;
private L app_msg_list;
public BaseResp getBase_resp() {
return base_resp;
}
public void setBase_resp(BaseResp base_resp) {
this.base_resp = base_resp;
}
public Integer getAcct_size() {
return acct_size;
}
public void setAcct_size(Integer acct_size) {
this.acct_size = acct_size;
}
public String getErr_msg() {
return err_msg;
}
public void setErr_msg(String err_msg) {
this.err_msg = err_msg;
}
public Integer getRet() {
return ret;
}
public void setRet(Integer ret) {
this.ret = ret;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getUser_category() {
return user_category;
}
public void setUser_category(Integer user_category) {
this.user_category = user_category;
}
public String getRedirect_url() {
return redirect_url;
}
public void setRedirect_url(String redirect_url) {
this.redirect_url = redirect_url;
}
public L getList() {
return list;
}
public void setList(L list) {
this.list = list;
}
public L getApp_msg_list() {
return app_msg_list;
}
public void setApp_msg_list(L app_msg_list) {
this.app_msg_list = app_msg_list;
}
@Override
public String toString() {
return "WxResultBody{" +
"acct_size=" + acct_size +
", err_msg='" + err_msg + '\'' +
", redirect_url='" + redirect_url + '\'' +
", ret=" + ret +
", status=" + status +
", user_category=" + user_category +
", base_resp=" + base_resp +
", list=" + list +
", app_msg_list=" + app_msg_list +
'}';
}
}
package top.iszsq.weixin.okhttp;
import com.fasterxml.jackson.core.type.TypeReference;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import top.iszsq.weixin.utils.JsonUtils;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* cookie管理
* @author zsq
* @version 1.0
* @date 2021/3/31 16:17
*/
public class MyCookieStore implements CookieJar {
/**打印日志用**/
private static volatile boolean debug = false;
/**登录后拿到的token**/
private static String TOKEN = "";
/**管理cookie**/
private static ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>> cookieStore = new ConcurrentHashMap<>();
/**token资源文件位置**/
public static final String TOKEN_FILE_PATH = "/store/token.txt";
/**cookie资源文件位置**/
public static final String COOKIE_FILE_PATH = "/store/cookie.txt";
@Override
public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
log("-----保存cookie");
//保存cookie
log("httpUrl host: " + httpUrl.host());
ConcurrentHashMap<String, Cookie> cookieMap = cookieStore.get(httpUrl.host());
if (cookieMap == null) {
cookieMap = new ConcurrentHashMap<>();
cookieStore.put(httpUrl.host(), cookieMap);
}
for (Cookie cookie : list) {
cookieMap.put(cookie.name(), cookie);
}
if (list != null && list.size() > 0) {
//存到本地,需要自己写持久化的实现,可用redis,或本地
}
log("-----保存到cookie:" + cookieStore.toString());
log("------------------------:");
}
@Override
public List<Cookie> loadForRequest(HttpUrl httpUrl) {
log("---加载 cookie");
List<Cookie> cookies = new ArrayList<>();
Map<String, Cookie> cookieMap = cookieStore.get(httpUrl.host());
if (cookieMap != null) {
cookieMap.forEach((name, cookie)->{
log("--cookie:" + name + "=" + cookie.value());
cookies.add(cookie);
});
}
log("---load cookie");
return cookies;
}
public static void setToken(String token) {
TOKEN = token;
}
public static String getToken() {
return TOKEN;
}
/**
* 保存cookie
* @param resPath 资源文件目录
*/
public static void saveCookie (String resPath, ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>> cookieMap) {
}
/**
* 保存到文件
* @param resPath 资源文件目录
*/
public static void saveToFile (String resPath, String str) {
URL resource = MyCookieStore.class.getResource(resPath);
try {
IOUtils.write(str.getBytes(), new FileOutputStream(resource.getFile()));
} catch (IOException e) {
System.out.println("---保存数据到本地失败");
e.printStackTrace();
}
}
/**
* 加载cookie到内存
*/
public static void loadCookie() {
InputStream resourceAsStream = MyCookieStore.class.getResourceAsStream(COOKIE_FILE_PATH);
String cookieTxt = null;
try {
cookieTxt = IOUtils.toString(resourceAsStream);
if (StringUtils.isNotBlank(cookieTxt)) {
//转成对象
ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>> nativeCookie = JsonUtils.jsonToObj(cookieTxt,
new TypeReference<ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>>>() {});
cookieStore = nativeCookie;
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 加载token到内存
*/
public static void loadToken() {
InputStream resourceAsStream = MyCookieStore.class.getResourceAsStream(TOKEN_FILE_PATH);
String s = null;
try {
s = IOUtils.toString(resourceAsStream);
TOKEN = s;
} catch (IOException e) {
e.printStackTrace();
}
}
public static void log(String log) {
if (!debug) {
return;
}
System.out.println(log);
}
}
package top.iszsq.weixin.okhttp;
import okhttp3.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* 静态化一个okhttp实例
* @author zsq
* @version 1.0
* @date 2021/3/31 10:58
*/
public class MyOkHttpClient {
/**okhttp实例**/
public static OkHttpClient client;
private static String referer = "https://mp.weixin.qq.com/";
private static String userAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36";
private static String xRequestedWith = "XMLHttpRequest";
static {
//初始化一个okhttp实例
client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(5, 20, TimeUnit.SECONDS))
.readTimeout(15, TimeUnit.SECONDS)
//管理cookie
.cookieJar(new MyCookieStore())
//添加请求头
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
//添加请求头
Request request = chain.request().newBuilder()
.addHeader("referer", referer)
.addHeader("userAgent", userAgent)
.addHeader("xRequestedWith", xRequestedWith)
.build();
return chain.proceed(request);
}
})
.build();
}
}
package top.iszsq.weixin.utils;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import top.iszsq.weixin.okhttp.MyOkHttpClient;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 11:06
*/
public class HttpUtils {
/**okhttp 实例**/
private static OkHttpClient client = MyOkHttpClient.client;
/**解析键值对正则**/
public static final Pattern PAT_KEY_VALUE = Pattern.compile("[\\w]*=[\\w,/]*");
/**
* get请求
* @param url
* @param params
* @return
*/
public static String doGet(String url, Map<String, String> params) {
Request.Builder reqBuild = new Request.Builder();
HttpUrl.Builder urlBuilder = HttpUrl.parse(url)
.newBuilder();
if (params != null) {
params.forEach(urlBuilder::addQueryParameter);
}
reqBuild.url(urlBuilder.build());
Request request = reqBuild.build();
Response response = null;
try {
response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("请求不成功" + response.toString());
}
return response.body().string();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* post表单提交
* @return
*/
public static String doPost(String url, Map<String, String> params) {
FormBody.Builder formBuilder = new FormBody.Builder();
if (params != null) {
params.forEach(formBuilder::addEncoded);
}
Request request = new Request.Builder()
.url(url)
.post(formBuilder.build())
.build();
Response response = null;
try {
response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("请求不成功" + response.toString());
}
return response.body().string();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* get请求,返回流
* @param url
* @param params
* @return
*/
public static InputStream doGetStream(String url, Map<String, String> params) {
Request.Builder reqBuild = new Request.Builder();
HttpUrl.Builder urlBuilder = HttpUrl.parse(url)
.newBuilder();
if (params != null) {
params.forEach(urlBuilder::addQueryParameter);
}
reqBuild.url(urlBuilder.build());
Request request = reqBuild.build();
Response response = null;
try {
response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("请求不成功" + response.toString());
}
if (response.body() == null) {
throw new RuntimeException("返回内容body为空");
}
return response.body().byteStream();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* 字符解析成键值对参数
* @return
*/
public static Map<String, String> parseQueryParams (String path) {
Map<String, String> map = new HashMap<>();
if (StringUtils.isNotBlank(path)) {
Matcher matcher = PAT_KEY_VALUE.matcher(path);
while (matcher.find()) {
String group = matcher.group(0);
String[] split = group.split("=");
if (split.length > 1) {
map.put(split[0], split[1]);
} else {
map.put(split[0], "");
}
}
}
return map;
}
}
package top.iszsq.weixin.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 14:05
*/
public class JsonUtils {
private static ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
}
/**
* 对象转json字符串
* @param object
* @return
*/
public static String toJsonStr(Object object){
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new RuntimeException("json转换出错", e);
}
}
/**
* json字符转map
* @param jsonStr
* @return
*/
public static Map<String, Object> jsonToMap(String jsonStr) {
try {
return objectMapper.readValue(jsonStr, HashMap.class);
} catch (IOException e) {
throw new RuntimeException("json转换出错", e);
}
}
/**
* json转对象
* @param jsonStr
* @param clazz
* @param <T>
* @return
*/
public static <T> T jsonToObj(String jsonStr, Class<T> clazz) {
try {
return objectMapper.readValue(jsonStr, clazz);
} catch (IOException e) {
throw new RuntimeException("json转换出错", e);
}
}
/**
* json转对象
* @param jsonStr
* @param typeReference
* @param <T>
* @return
*/
public static <T> T jsonToObj(String jsonStr, TypeReference<T> typeReference) {
try {
return objectMapper.readValue(jsonStr, typeReference);
} catch (IOException e) {
throw new RuntimeException("json转换出错", e);
}
}
}
package top.iszsq.weixin;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import top.iszsq.weixin.okhttp.MyCookieStore;
import java.io.IOException;
import java.io.InputStream;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 16:33
*/
public class FileTest {
@Test
public void loadString() {
InputStream resourceAsStream = MyCookieStore.class.getResourceAsStream("/store/token.txt");
String s = null;
try {
s = IOUtils.toString(resourceAsStream);
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package top.iszsq.weixin;
import org.junit.Test;
import java.util.Scanner;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 16:05
*/
public class ScannerTest {
@Test
public void getLine() {
Scanner scanner = new Scanner(System.in);
}
}
package top.iszsq.weixin.utils;
import org.junit.Test;
import java.util.Map;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 15:56
*/
public class HttpUtilsTest {
/**
* 解析路径成键值对
*/
@Test
public void parseQueryParams() {
String path = "/cgi-bin/home?t=home/index&lang=zh_CN&token=2080662142";
Map<String, String> map = HttpUtils.parseQueryParams(path);
System.out.println(map);
}
}
package top.iszsq.weixin.utils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import top.iszsq.weixin.enums.WxResultStatus;
import top.iszsq.weixin.model.BaseResp;
import top.iszsq.weixin.model.WxResultBody;
import java.util.Map;
import static org.junit.Assert.*;
/**
* @author zsq
* @version 1.0
* @date 2021/3/31 14:17
*/
public class JsonUtilsTest {
/**
* 对象转json字符串
*/
@Test
public void toJsonStr() {
WxResultBody wxResultBody = new WxResultBody();
BaseResp baseResp = new BaseResp();
baseResp.setErr_msg("ok");
baseResp.setRet(0);
wxResultBody.setBase_resp(baseResp);
String s = JsonUtils.toJsonStr(wxResultBody);
System.out.println(s);
assert StringUtils.equals("{\"base_resp\":{\"err_msg\":\"ok\",\"ret\":0}}", s);
}
/**
* json转map
*/
@Test
public void jsonToMap() {
String str = "{\"base_resp\":{\"err_msg\":\"ok\",\"ret\":0}}";
Map<String, Object> map = JsonUtils.jsonToMap(str);
System.out.println(map);
assert map.get("base_resp") instanceof Map;
}
/**
* json转对象
*/
@Test
public void jsonToObj() {
String str = "{\"base_resp\":{\"err_msg\":\"ok\",\"ret\":0}}";
WxResultBody wxResultBody = JsonUtils.jsonToObj(str, WxResultBody.class);
System.out.println(wxResultBody);
assert wxResultBody != null && wxResultBody.getBase_resp() instanceof BaseResp;
}
@Test
public void testJsonToObj() {
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment