1. 程式人生 > >java 網頁版 找出刪除你的微信好友(翻譯修改自python指令碼)

java 網頁版 找出刪除你的微信好友(翻譯修改自python指令碼)

使用的微信網頁版介面來源自 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");
	}