下载地址:https://www.pan38.com/share.php?code=JCnzE 提取密码:7789
基于C++实现的QQ群成员提取工具完整代码,包含Windows桌面端和Android移动端两个版本的核心模块。代码整合了HTTP协议请求、数据库操作和跨平台适配功能,采用多线程技术提升采集效率
该工具实现原理是通过模拟QQ网页端接口请求获取群成员数据12,主要技术特点包括:
Windows版本使用libcurl进行HTTP请求,Android版本使用HttpURLConnection
采用SQLite数据库缓存采集结果
多线程处理提升采集效率
支持CSV格式导出便于数据分析
pragma once
include
include
include
include
include
include
include
include
struct GroupMember {
std::string qq_number;
std::string nick_name;
int qq_level;
std::string role;
};
class QQGroupCrawler {
public:
QQGroupCrawler(const std::string& cookie);
~QQGroupCrawler();
bool fetchGroupList(std::vector<std::string>& group_list);
bool fetchMembers(const std::string& group_id,
std::vector<GroupMember>& members);
void exportToCSV(const std::vector<GroupMember>& members,
const std::string& filename);
private:
static size_t writeCallback(void contents, size_t size,
size_t nmemb, std::string s);
std::string getBkn(const std::string& skey);
bool parseMemberJson(const std::string& json_str,
std::vector& members);
std::string cookies_;
std::mutex db_mutex_;
sqlite3* db_;
};
include "QQGroupCrawler.h"
include
include
include
// 构造函数初始化数据库连接
QQGroupCrawler::QQGroupCrawler(const std::string& cookie) : cookies_(cookie) {
sqlite3_open("qqmembers.db", &db);
sqlite3exec(db, "CREATE TABLE IF NOT EXISTS members("
"qq TEXT PRIMARY KEY, nick TEXT, level INT, role TEXT);",
NULL, NULL, NULL);
}
// HTTP响应回调函数
size_t QQGroupCrawler::writeCallback(void contents, size_t size,
size_t nmemb, std::string s) {
size_t new_length = size nmemb;
try {
s->append((char)contents, new_length);
} catch(std::bad_alloc& e) {
return 0;
}
return new_length;
}
// 获取BKN参数
std::string QQGroupCrawler::getBkn(const std::string& skey) {
int hash = 5381;
for(size_t i = 0; i < skey.length(); ++i) {
hash += (hash << 5) + skey[i];
}
return std::to_string(hash & 2147483647);
}
// 解析成员JSON数据
bool QQGroupCrawler::parseMemberJson(const std::string& json_str,
std::vector& members) {
Json::Value root;
Json::Reader reader;
if(!reader.parse(json_str, root)) return false;
if(!root["mems"].isArray()) return false;
for(const auto& mem : root["mems"]) {
GroupMember member;
member.qq_number = mem["uin"].asString();
member.nick_name = mem["nick"].asString();
member.qq_level = mem["level"].asInt();
member.role = mem["role"].asString();
members.push_back(member);
}
return true;
}
// 导出到CSV文件
void QQGroupCrawler::exportToCSV(const std::vector& members,
const std::string& filename) {
std::ofstream out(filename);
out << "QQ号,昵称,等级,身份\n";
for(const auto& m : members) {
out << m.qq_number << ","
<< m.nick_name << ","
<< m.qq_level << ","
<< m.role << "\n";
}
out.close();
}
com.example.qqcrawler;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
public class AndroidCrawler {
private Context context;
private SQLiteDatabase db;
private String cookies;
public AndroidCrawler(Context ctx, String cookie) {
this.context = ctx;
this.cookies = cookie;
this.db = context.openOrCreateDatabase("qq_members.db",
Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS members(" +
"qq TEXT PRIMARY KEY, nick TEXT, level INT, role TEXT)");
}
private String httpGet(String urlStr) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Cookie", cookies);
BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
return sb.toString();
}
public ArrayList<HashMap<String,String>> parseMembers(String jsonStr)
throws Exception {
ArrayList<HashMap<String,String>> members = new ArrayList<>();
JSONObject json = new JSONObject(jsonStr);
JSONArray mems = json.getJSONArray("mems");
for(int i=0; i<mems.length(); i++) {
JSONObject mem = mems.getJSONObject(i);
HashMap<String,String> member = new HashMap<>();
member.put("qq", mem.getString("uin"));
member.put("nick", mem.getString("nick"));
member.put("level", mem.getString("level"));
member.put("role", mem.getString("role"));
members.add(member);
}
return members;
}
public void exportToCSV(ArrayList<HashMap<String,String>> members,
String filename) throws Exception {
FileOutputStream out = context.openFileOutput(filename,
Context.MODE_PRIVATE);
String header = "QQ号,昵称,等级,身份\n";
out.write(header.getBytes());
for(HashMap<String,String> m : members) {
String line = String.format("%s,%s,%s,%s\n",
m.get("qq"), m.get("nick"),
m.get("level"), m.get("role"));
out.write(line.getBytes());
}
out.close();
}
}
include "QQGroupCrawler.h"
include
include
int main() {
std::string cookie = "uin=o123456; skey=@abcdefg;";
QQGroupCrawler crawler(cookie);
std::vector<std::string> groups;
if(!crawler.fetchGroupList(groups)) {
std::cerr << "获取群列表失败" << std::endl;
return 1;
}
for(const auto& group : groups) {
std::vector<GroupMember> members;
auto start = std::chrono::steady_clock::now();
if(crawler.fetchMembers(group, members)) {
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<
std::chrono::milliseconds>(end - start);
std::string filename = "group_" + group + ".csv";
crawler.exportToCSV(members, filename);
std::cout << "成功导出群 " << group << " 的 "
<< members.size() << " 个成员数据,耗时 "
<< duration.count() << " 毫秒" << std::endl;
} else {
std::cerr << "获取群 " << group << " 成员失败" << std::endl;
}
}
return 0;
}