// ==UserScript==
// @name 微信公众号粉丝查看工具
// @namespace https://mp.weixin.qq.com/cgi-bin/user_tag?action=get_all_data
// @version 0.1.4
// @description 微信公众号粉丝查看工具,可查看用户关注时间和可导出每页用户数据
// @author Wilson
// @match https://mp.weixin.qq.com/cgi-bin/user_tag?action=get_all_data*
// @icon https://img.icons8.com/fluent/48/000000/user-male-circle.png
// @require https://cdn.jsdelivr.net/npm/[email protected]/jquery.min.js
// @run-at document-start
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// ==/UserScript==
(function() {
'use strict';
//用户数据,记录每次变更的数据
unsafeWindow.userData = [];
unsafeWindow.allUserData = [];
//添加关注信息
function addFllowInfo(userList) {
for (let i in userList) {
//添加关注时间
let user = userList[i];
user.user_openid = user.user_openid || user.id;
user.user_create_time = user.user_create_time || user.create_time;
let localDate = new Date(user.user_create_time * 1000).toLocaleString();
//console.log(user.user_create_time, user.user_openid);
let userName = document.querySelector(".user_info a[data-fakeid=" + user.user_openid + "]");
//console.log(userName, user.user_openid);
if (userName) userName.innerHTML += ' <span style="color:#9a9a9a;">(' + localDate + ')</span>';
}
//导出按钮
$(".tool_area .pagination").append('<span><a href="javascript:;" onclick="wx_user_export()" style="margin-top:4px;margin-left:15px;display:inline-block;">导出本页</a></span>');
let btnstyle = 'background-color: #fff;background-image: linear-gradient(to bottom,#fff 0,#fff 100%);border-color: #e7e7eb;color: #353535;height: 30px; line-height: 30px;padding-left: 10px; padding-right: 10px;width: auto;';
$(".tool_area .pagination").append('<span style="margin-left:20px;">导出前<input id="wx_export_num" type="text" value="'+(unsafeWindow.exportNum||'')+'" style="width:40px;border:1px solid #e7e7eb;height:20px;text-align:center;">页<a id="wx_export_all" href="javascript:;" onclick="wx_user_export_all()" class="btn" style="margin-left:6px;display:inline-block;'+btnstyle+'">导出</a></span>');
}
//错误提示
function errorTips(str, delay) {
$(".page_tips .inner").html(str);
$(".page_tips").show();
setTimeout(function(){
$(".page_tips").hide();
$(".page_tips .inner").html("将浏览器更新为QQ浏览器或Chrome浏览器,以获得更好的体验");
}, delay||3000);
}
//监听分页用户(ajax)
//var lastUserUrl = "";
(function(open) {
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
this.addEventListener("readystatechange", function() {
//console.log(this.readyState, this.status, this);
if (this.readyState==4 && this.status==200 && url.indexOf("ction=get_user_list") !== -1) {
let json = JSON.parse(this.response);
//console.log(this.readyState, this.status, json);
let userList = json.user_list.user_info_list || [];
setTimeout(function(){
addFllowInfo(userList);
}, 400);
unsafeWindow.userData = userList;
unsafeWindow.wx_user_export_page++;
if(unsafeWindow.isExporting) {
for(let j in userList) {
if(userList[j]) {
unsafeWindow.allUserData.push(userList[j]);
}
}
}
}
/*
let userUrl = document.location.origin + url;
if (lastUserUrl != userUrl && url.indexOf("ction=get_user_list") !== -1) {
console.log(userUrl);
GM_xmlhttpRequest({
method: "get",
url: userUrl,
onload: function(res){
if(res.status === 200){
console.log('sucess')
let json = JSON.parse(res.response);
let userList = json.user_list.user_info_list || [];
addFllowInfo(userList);
unsafeWindow.userData = userList;
unsafeWindow.wx_user_export_page++;
}else{
console.log('error')
console.log(res)
}
},
onerror : function(err){
console.log('error')
console.log(err)
}
});
//$.getJSON(userUrl, function(data){
//console.log(data);
//$.each(data.items, function(i,item){
// });
//});
lastUserUrl = userUrl;
}
*/
}, false);
open.call(this, method, url, async, user, pass);
};
})(XMLHttpRequest.prototype.open);
//全部导出
unsafeWindow.isExporting = false;
unsafeWindow.exportNum = '';
unsafeWindow.isStop = 0;
unsafeWindow.wx_user_export_all = function() {
if(unsafeWindow.isExporting) return false;
unsafeWindow.isExporting = true;
let total = parseInt($(".page_num label:last").text()-0);
let currpage = parseInt($(".page_num label:first").text()-0);
if(currpage > 1){
errorTips("请先跳转到第1页");
unsafeWindow.isExporting = false;
return false;
}
unsafeWindow.allUserData = wx.cgiData.user_list || [];
let count = unsafeWindow.allUserData.length;
let begin_openid = unsafeWindow.allUserData[count-1].id;
let begin_create_time = unsafeWindow.allUserData[count-1].create_time;
unsafeWindow.exportNum = parseInt($("#wx_export_num").val()-0);
if(unsafeWindow.exportNum <= 0){
errorTips("请填写页数");
unsafeWindow.isExporting = false;
return false;
}
$(".tool_area").append('<div id="wx_export_tips" style="margin-top:10px;"></div>');
let sleep = function (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let doGetUsers = async function() {
for(let i = 2;i<=total;i++){
//停止
if(unsafeWindow.isStop == 1) {
unsafeWindow.isStop = 0;
break;
}
//超过页数
if(i > unsafeWindow.exportNum || i > total) break;
//console.log('page ' + i, 1111, unsafeWindow.isExporting);
$("#wx_export_tips").html("正在导出第"+i+"页... <a href='javascript:;' onclick='isStop = 1;'>停止</a>");
document.querySelector("a.page_next").click();
/*
let userUrl = "https://mp.weixin.qq.com/cgi-bin/user_tag?action=get_user_list&groupid=-2&begin_openid="+begin_openid+"&begin_create_time="+begin_create_time+"&limit=20&offset=20&backfoward=1&token=" + wx.data.t + "&lang=zh_CN&f=json&ajax=1&random="+Math.random();
console.log(2222, userUrl);
GM_xmlhttpRequest({
method: "get",
url: userUrl,
onload: function(res){
if(res.status === 200){
console.log('sucess')
console.log(333, res);
let json = JSON.parse(res.response);
let userList = json.user_list.user_info_list || [];
console.log(4444, userList);
for(let j in userList) {
if(userList[j]) {
unsafeWindow.allUserData.push(userList[j]);
begin_openid = userList[j].user_openid;
begin_create_time = userList[j].user_create_time;
}
}
}else{
console.log('error')
console.log(res)
}
},
onerror : function(err){
console.log('error')
console.log(err)
}
});
*/
await sleep(2000);
}
wx_user_export(unsafeWindow.allUserData, "微信公众号粉丝前"+unsafeWindow.exportNum+"页");
$("#wx_export_tips").html("");
unsafeWindow.isExporting = false;
}
doGetUsers();
}
//导出用户数据
unsafeWindow.wx_user_export_page = 1;
unsafeWindow.wx_user_export = function(data, name) {
//console.log(data,6666);
let jsonData = data || unsafeWindow.userData;
//列标题,逗号隔开,每一个逗号就是隔开一个单元格
let str = `昵称,关注时间,openid,头像图片\n`;
for (let i in jsonData) {
let user = jsonData[i];
user.user_openid = user.user_openid || user.id;
if (!user.user_openid) continue;
user.user_create_time = user.user_create_time || user.create_time;
let localDate = new Date(user.user_create_time * 1000).toLocaleString();
user.user_name = user.user_name || user.nick_name;
user.user_head_img = user.user_head_img || document.querySelector(".user_info img[data-id=" + user.user_openid + "]").src;
str += `${user.user_name},${localDate},${user.user_openid},${user.user_head_img}\n`;
}
//encodeURIComponent解决中文乱码
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str);
//通过创建a标签实现
var link = document.createElement("a");
link.href = uri;
//对下载的文件命名
link.download = (name || "微信公众号粉丝第" + unsafeWindow.wx_user_export_page + "页") + ".csv";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
//第一页用户数据(从js变量获取)
window.addEventListener("load", function() {
if (wx && wx.cgiData && wx.cgiData.user_list) {
let userList = wx.cgiData.user_list || [];
addFllowInfo(userList);
unsafeWindow.userData = userList;
//首页获取图片地址
setTimeout(function(){
for (let i in wx.cgiData.user_list) {
let item = wx.cgiData.user_list[i];
if (!item.user_head_img) {
let imgsrc = document.querySelector(".user_info img[data-id=" + item.id + "]");
if(imgsrc) {
item.user_head_img = imgsrc.src;
} else {
item.user_head_img = '';
}
}
wx.cgiData.user_list[i] = item;
}
}, 500);
}
});
})();