java 網頁版 找出刪除你的微信好友(翻譯修改自python指令碼)
阿新 • • 發佈:2019-01-04
使用的微信網頁版介面來源自 gaosen的python 指令碼 ,地址: https://github.com/0x5e/wechat-deleted-friends
gaosen的python程式碼中在拉取微信通訊錄的好友介面上沒有加上相關的認證引數,導致該python程式碼查詢結果不正確,讀取不了微信通訊錄,始終顯示 “通訊錄0個好友”
此java版改正了這個錯誤
同時為了方便使用,避免安裝java環境的限制,做成了網頁版 ,PC上開啟網頁掃碼就可以使用(查詢時間較長,前端使用ajax輪詢來更新後臺的查詢資訊)
查詢原理為通過微信網頁版介面新建群聊並自動拉取好友,加不進來就是刪除了你
(不在群聊裡講話,別人是看不見的~並不打擾好友)
主要介面通訊原始碼:
package com.toltech.wchat.process; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.http.client.ClientProtocolException; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.toltech.wchat.bean.Member; import com.toltech.wchat.utils.HttpUtils; public class Client { private final static int MAX_GROUP_NUM = 35; // 每組人數 private final static int INTERFACE_CALLING_INTERVAL = 30000; // 介面呼叫時間間隔, // 間隔太短容易出現"操作太頻繁", // 會被限制操作半小時左右 private final static int MAX_PROGRESS_LEN = 50; static int tip = 0; static String uuid; static String base_uri; static String redirect_uri; static String push_uri; static String skey; static String wxsid; static String wxuin; static String pass_ticket; static String deviceId = "e000000000000000"; static String baserequest; static List<Member> memberList; static String my; static List<Member> allDeletedList =new ArrayList<Member>(); public static void main(String[] args) throws Exception { try { if (getUUID()) { showQRImage(); waitForLogin(); while (!"200".equals(waitForLogin())) { } if (login()) { if (webwxinit()) { webwxgetcontact(); int memberCount =memberList.size(); System.err.println("通訊錄共有"+memberCount+"好友"); System.out.println("開始查詢..."); String chatRoomName =null; int group_num =memberCount/MAX_GROUP_NUM; if(memberCount% MAX_GROUP_NUM !=0) group_num+=1; for (int i=0;i<group_num;i++) { Map<String, Object> map=null; List<Member> userNames =new ArrayList<Member>(); for(int j=0;j<MAX_GROUP_NUM;j++){ if (i * MAX_GROUP_NUM + j >= memberCount) break; Member member = memberList.get(i * MAX_GROUP_NUM + j); userNames.add(member); } //新建群組/新增成員 if(chatRoomName ==null){ map = createChatroom(userNames); chatRoomName = map.get("chatRoomName").toString(); } else map =addMember(chatRoomName, userNames); List<Member> deletedList = (List<Member>) map.get("deletedList"); allDeletedList.addAll(deletedList); // 刪除成員 deleteMember(chatRoomName, userNames); // 進度條 System.out.println("新發現你被" +deletedList.size()+"人刪除"); if (i != group_num - 1){ System.out.println("正在繼續查詢,請耐心等待..."); //下一次進行介面呼叫需要等待的時間 Thread.sleep(INTERFACE_CALLING_INTERVAL); } } int deleteCount =allDeletedList.size(); System.out.println("結果彙總完畢,20s後可以重試"); System.out.println("被刪除的好友列表,共"+deleteCount +"人"); for (Member member : allDeletedList) { for (Member mem : memberList) { if(member.getUserName().equals(mem.getUserName())) System.err.println(mem.getNickName()+"("+mem.getRemarkName()+")"); } } } } } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static boolean getUUID() throws Exception { StringBuffer url = new StringBuffer(); url.append("https://login.weixin.qq.com/jslogin?"); url.append("appid=wx782c26e4c19acffb"); url.append("&fun=new"); url.append("&lang=zh_CN"); url.append("&_=" + String.valueOf(System.currentTimeMillis())); String data = HttpUtils.httpGet(url.toString()); if (StringUtils.isNotBlank(data)) { String code = data.substring(data.indexOf("= ") + 1, data.indexOf(";")); uuid = data.substring(data.indexOf("\"") + 1, data.lastIndexOf("\"")); System.out.println("code:" + code + ";uuid:" + uuid); if ("200".equals(code.trim())) return true; } return false; } public static void showQRImage() throws IOException { String url = "https://login.weixin.qq.com/qrcode/" + uuid; url = url + "?t=webwx&_="; url = url + String.valueOf(System.currentTimeMillis()); String filename = HttpUtils.getImage(url); tip = 1; Runtime.getRuntime().exec( "rundll32 c:\\Windows\\System32\\shimgvw.dll,ImageView_Fullscreen " + filename); } public static String waitForLogin() throws Exception { StringBuffer url = new StringBuffer(); url.append("https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?"); url.append("tip=" + tip); url.append("&uuid=" + uuid); url.append("&_=" + String.valueOf(System.currentTimeMillis())); String data = HttpUtils.httpGet(url.toString()); String code = data.substring(data.indexOf("=") + 1, data.indexOf(";")) .trim(); System.err.println(code); if ("201".equals(code)) { System.out.println("成功掃描,請在手機上點選確認以登入"); } else if ("200".equals(code)) { System.out.println("正在登陸..."); redirect_uri = data.substring(data.indexOf("\"") + 1, data.lastIndexOf("\"")) + "&fun=new"; base_uri = redirect_uri.substring(0, redirect_uri.lastIndexOf("/")); String[][] services = { { "wx2.qq.com", "webpush2.weixin.qq.com" }, { "qq.com", "webpush.weixin.qq.com" }, { "web1.wechat.com", "webpush1.wechat.com" }, { "web2.wechat.com", "webpush2.wechat.com" }, { "wechat.com", "webpush.wechat.com" }, { "web1.wechatapp.com", "webpush1.wechatapp.com" } }; push_uri = base_uri; for (String[] strings : services) { if (base_uri.indexOf(strings[0]) > -1) { push_uri = "https://" + strings[1] + "/cgi-bin/mmwebwx-bin"; break; } } } return code; } public static boolean login() throws Exception { System.out.println("登入:" + redirect_uri); String data = HttpUtils.httpGet(redirect_uri); SAXBuilder saxBuilder = new SAXBuilder(); StringReader reader = new StringReader(data); Document document = saxBuilder.build(reader); Element root = document.getRootElement(); Element ret = root.getChild("ret"); if ("0".equals(ret.getText())) { wxuin = root.getChild("wxuin").getText(); wxsid = root.getChild("wxsid").getText(); skey = root.getChild("skey").getText(); pass_ticket = root.getChild("pass_ticket").getText(); JSONObject j = new JSONObject(); j.put("Uin", wxuin); j.put("Sid", wxsid); j.put("Skey", skey); j.put("DeviceID", deviceId); baserequest = j.toString(); return true; } return false; } public static boolean webwxinit() throws Exception { String json = "{\"BaseRequest\":" + baserequest + "}"; StringBuffer url = new StringBuffer(); url.append(base_uri); url.append("/webwxinit?pass_ticket=" + pass_ticket); url.append("&skey=" + skey); url.append("&r=" + String.valueOf(System.currentTimeMillis())); String data = HttpUtils.postJson(url.toString(), json); System.out.println(data); JSONObject result = JSON.parseObject(data); my = result.getString("User"); if ("0".equals(JSON.parseObject(result.getString("BaseResponse")) .getString("Ret"))) return true; return false; } public static void webwxgetcontact() throws ClientProtocolException, IOException { String json = "{\"BaseRequest\":" + baserequest + "}"; StringBuffer url = new StringBuffer(); url.append(base_uri); url.append("/webwxgetcontact?pass_ticket=" + pass_ticket); url.append("&skey=" + skey); url.append("&r=" + String.valueOf(System.currentTimeMillis())); String data = HttpUtils.postJson(url.toString(), json); String memberListString = JSONObject.parseObject(data).getString( "MemberList"); memberList = JSON.parseArray(memberListString, Member.class); // 倒序遍歷,不然刪除的時候出問題.. String[] specialUsers = { "newsapp", "fmessage", "filehelper", "weibo", "qqmail", "tmessage", "qmessage", "qqsync", "floatbottle", "lbsapp", "shakeapp", "medianote", "qqfriend", "readerapp", "blogapp", "facebookapp", "masssendapp", "meishiapp", "feedsapp", "voip", "blogappweixin", "weixin", "brandsessionholder", "weixinreminder", "wxid_novlwrv3lqwv11", "gh_22b87fa7cb3c", "officialaccounts", "notification_messages", "wxitil", "userexperience_alarm" }; Iterator<Member> it = memberList.iterator(); while(it.hasNext()){ Member member = it.next(); if((member.getVerifyFlag() & 8) != 0)//# 公眾號/服務號 it.remove(); else if(member.getUserName().indexOf("@@")>-1)//# 群聊 it.remove(); else if(member.getUserName().equals(JSONObject.parseObject(my).getString("UserName")))//自己 it.remove(); else{ for (String string : specialUsers) { if(member.getUserName().equals(string)){ it.remove(); break; } } } } } public static Map<String,Object> createChatroom(List<Member> userNames) throws ClientProtocolException, IOException{ Map<String,Object> map = new HashMap<String,Object>(); StringBuffer memberList=new StringBuffer(); for (Member member : userNames) { memberList.append("{\"UserName\":\""+ member.getUserName()+"\"},"); } StringBuffer url = new StringBuffer(); url.append(base_uri); url.append("/webwxcreatechatroom?pass_ticket=" + pass_ticket); url.append("&skey=" + skey); url.append("&r=" + String.valueOf(System.currentTimeMillis())); String json = "{\"BaseRequest\":" + baserequest + "," + "\"MemberCount\":"+userNames.size() +",\"MemberList\":["+ memberList.toString().substring(0, memberList.toString().length()-1) +"],\"Topic\": \"\"}"; System.err.println(json); String data = HttpUtils.postJson(url.toString(), json); String chatRoomName = JSONObject.parseObject(data).getString("ChatRoomName"); System.out.println(data); map.put("chatRoomName", chatRoomName); List<Member> memlists = JSON.parseArray(JSONObject.parseObject(data).getString("MemberList"),Member.class); List<Member> deletedList = new ArrayList<Member>(); List<Member> blockedList = new ArrayList<Member>(); if(memlists!=null && memlists.size()>0){ for (Member member : memlists) { if(member.getMemberStatus()==4)// 被對方刪除了 deletedList.add(member); else if(member.getMemberStatus()==3)// 被加入黑名單 blockedList.add(member); } } map.put("deletedList", deletedList); map.put("blockedList", blockedList); return map; } public static boolean deleteMember(String chatRoomName, List<Member> userNames) throws ClientProtocolException, IOException{ StringBuffer url = new StringBuffer(); url.append(base_uri); url.append("/webwxupdatechatroom?fun=delmember&pass_ticket=" + pass_ticket); StringBuffer members = new StringBuffer(); for (Member member : userNames) { members.append(userNames+","); } String memberlist = members.toString().substring(0,members.toString().length()-1); String json = "{\"BaseRequest\":" + baserequest + "," + "\"ChatRoomName\":" +chatRoomName +",\"DelMemberList\":" +memberlist +"}"; String data = HttpUtils.postJson(url.toString(), json); JSONObject result = JSON.parseObject(data); if ("0".equals(JSON.parseObject(result.getString("BaseResponse")) .getString("Ret"))) return true; return false; } public static Map<String,Object> addMember(String chatRoomName, List<Member> userNames) throws ClientProtocolException, IOException{ Map<String,Object> map = new HashMap<String,Object>(); StringBuffer url = new StringBuffer(); url.append(base_uri); url.append("/webwxupdatechatroom?fun=addmember&pass_ticket=" + pass_ticket); StringBuffer members = new StringBuffer(); for (Member member : userNames) { members.append(member.getUserName()+","); } String memberlist = members.toString().substring(0,members.toString().length()-1); String json = "{\"BaseRequest\":" + baserequest + "," + "\"ChatRoomName\":" +chatRoomName +",\"AddMemberList\":" +memberlist +"}"; String data = HttpUtils.postJson(url.toString(), json); List<Member> memlists = JSON.parseArray(JSONObject.parseObject(data).getString("MemberList"),Member.class); List<Member> deletedList = new ArrayList<Member>(); List<Member> blockedList = new ArrayList<Member>(); if(memlists!=null && memlists.size()>0){ for (Member member : memlists) { if(member.getMemberStatus()==4)// 被對方刪除了 deletedList.add(member); else if(member.getMemberStatus()==3)// 被加入黑名單 blockedList.add(member); } } map.put("deletedList", deletedList); map.put("blockedList", blockedList); return map; } }
介面通訊用到的http post 傳送josn資料方法
public static String postJson(String url, String parameters) throws ClientProtocolException, IOException { DefaultHttpClient client = new DefaultHttpClient() ; client.getParams() .setParameter( CoreProtocolPNames.USER_AGENT, "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.2) Gecko/20090803 Fedora/3.5.2-2.fc11 Firefox/3.5.2"); HttpPost httpPost = new HttpPost(url); System.out.println(url); if(parameters!=null){ StringEntity s = new StringEntity(parameters); s.setContentEncoding("UTF-8"); s.setContentType("application/json");//傳送json資料需要設定contentType httpPost.setEntity(s); } HttpResponse response = client.execute(httpPost); HttpEntity entity = response.getEntity(); return EntityUtils.toString(entity,"utf-8"); }
http get請求方法
public static String httpGet(String url) throws Exception {
DefaultHttpClient client = new DefaultHttpClient() ;
client.getParams()
.setParameter(
CoreProtocolPNames.USER_AGENT,
"Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.2) Gecko/20090803 Fedora/3.5.2-2.fc11 Firefox/3.5.2");
HttpGet get = new HttpGet(url);
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity,"utf-8");
}