挖财账单导出
挖财账单接口数据转换为markdown文件。
挖财记账数据不能免费导出,需要¥50升级为vip才能导出。自己记账的数据,自己都不能导出,相当可恶。因此用程序员的方法将自己的数据导出来。主要是两步,通过挖财pc端接口获取数据,然后将这些数据转换一下。
1、获取账单明细
1、挖财网站 https://user.wacai.com/reform/web/login
2、时间戳在线工具 https://tool.lu/timestamp/
时间 毫秒值
2013-01-01 00:00:00 1356969600000
2020-01-01 00:00:00 1577808000000
3、挖财数据明细
接口
https://www.wacai.com/activity/bkk-frontier/api/v2/flow/list/web?___t=1616121710537 POST
传参
Headers
Content-Type application/json
Cookie --
Body
{"bkId":123456,"startTime":1356969600000,"endTime":1577808000000,"queryFlowCount":true,"recTypeList":null,"mainTypeIdList":null,
"subTypeIdList":null,"accountIdList":null,"projectIdList":null,"tradetgtIdList":null,"memberIdList":null,"reimburseList":null,"comment":"",
"amountStart":null,"amountEnd":null,"pageSize":9000,"pageIndex":1}
2、java解析数据
package com.xu.spring.test.common.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.*;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
/**
* 挖财账单接口数据转换为markdown文件
*
* @date 2021/3/19 11:22
*/
public class WaiCaiDataParseUtil {
/**
*
1、挖财网站 https://user.wacai.com/reform/web/login
2、时间戳在线工具 https://tool.lu/timestamp/
时间 毫秒值
2013-01-01 00:00:00 1356969600000
2020-01-01 00:00:00 1577808000000
3、挖财数据明细
接口
https://www.wacai.com/activity/bkk-frontier/api/v2/flow/list/web?___t=1616121710537 POST
传参
Headers
Content-Type application/json
Cookie --
Body
{"bkId":123456,"startTime":1356969600000,"endTime":1577808000000,"queryFlowCount":true,"recTypeList":null,"mainTypeIdList":null,
"subTypeIdList":null,"accountIdList":null,"projectIdList":null,"tradetgtIdList":null,"memberIdList":null,"reimburseList":null,"comment":"",
"amountStart":null,"amountEnd":null,"pageSize":9000,"pageIndex":1}
*/
/*** 时间格式化*/
public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");
private static Integer year = 0;
private static Integer categoryNameLength = 4;
public static void main(String[] args) throws IOException {
String filePath = "D:\\waicai_data.txt";
parse(filePath);
}
private static void parse(String filePath) throws IOException {
String text = importFile2String(filePath);
File file = new File("D:\\挖财账单" + System.currentTimeMillis() + ".md");
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file, true);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
JSONObject object = JSONObject.parseObject(text);
JSONObject data = object.getJSONObject("data");
Integer flowCount = data.getInteger("flowCount");
JSONArray dailyItems = data.getJSONArray("dailyItems");
System.out.println(String.format("flowCount=%s,dailyItems_size=%s", flowCount, dailyItems.size()));
bw.write("## 挖财账单");
bw.newLine();
for (int i = 0; i < dailyItems.size(); i++) {
JSONObject item = dailyItems.getJSONObject(i);
JSONArray flowList = item.getJSONArray("flowList");
for (int j = 0; j < flowList.size(); j++) {
JSONObject flow = flowList.getJSONObject(j);
String comment = flow.getString("comment");
String currencyFlag = flow.getString("currencyFlag");
Integer amount = flow.getInteger("amount");
String bizTime = flow.getString("bizTime");
isNewYear(bizTime, bw);
String categoryName = flow.getString("categoryName");
String tradetgtName = flow.getString("tradetgtName");
StringBuilder builder = new StringBuilder();
builder.append("|").append(assembleTime(bizTime)).append("|").append(assembleCategory(categoryName)).append("|")
.append(assembleAmount(currencyFlag, amount)).append("|").append(Optional.ofNullable(tradetgtName).orElse(" - "))
.append("|").append(comment.replaceAll("\\n", "。")).append("|");
bw.write(builder.toString());
bw.newLine();
bw.flush();
}
}
bw.close();
osw.close();
fos.close();
}
private static void isNewYear(String bizTime, BufferedWriter bw) throws IOException {
String yearText = SIMPLE_DATE_FORMAT.format(new Date(Long.valueOf(bizTime))).substring(0, 4);
Integer currentYear = Integer.parseInt(yearText);
if (year == 0 || !currentYear.equals(year)) {
bw.newLine();
bw.write("### " + yearText);
bw.newLine();
year = currentYear;
titleRow(bw);
}
}
private static String assembleAmount(String currencyFlag, Integer amount) {
String s = currencyFlag + new BigDecimal(amount).divide(new BigDecimal(100)).toEngineeringString();
return s.length() == 6 ? s : blankText(6 - s.length()) + s;
}
private static String assembleCategory(String categoryName) {
return categoryName.length() == categoryNameLength ? categoryName : blankText((categoryNameLength - categoryName.length()) * 2) + categoryName;
}
private static String blankText(int n) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < n; i++) {
builder.append(" ");
}
return builder.toString();
}
private static String assembleTime(String bizTime) {
return SIMPLE_DATE_FORMAT.format(new Date(Long.valueOf(bizTime)));
}
private static void titleRow(BufferedWriter bw) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("|时间").append(blankText(16)).append("|").append("类别").append(blankText(4)).append("|")
.append("金额").append(blankText(2)).append("|").append("商家").append(blankText(2)).append("|").append("内容").append("|");
bw.write(builder.toString());
bw.newLine();
bw.write("| ------------------ | ------ | ---- | ---- | ---- |");
bw.newLine();
}
/**
* 文件导入为字符串
*
* @param filePath
* @return
*/
private static String importFile2String(String filePath) {
StringBuffer sb = new StringBuffer();
try {
long time = System.currentTimeMillis();
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException("file not found");
}
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel cha = raf.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int size = 0;
while ((size = cha.read(buf)) != -1) {
buf.flip();
byte[] buff = new byte[size];
buf.get(buff);
sb.append(new String(buff, 0, size));
}
// System.out.println(System.currentTimeMillis() - time);
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
}