下载地址:https://www.pan38.com/share.php?code=JCnzE 提取密码:7789
这个工具实现了完整的QQ群成员信息采集功能,包括登录QQ、获取群列表、获取群成员详细信息以及导出到JSON文件。代码使用了selenium模拟浏览器操作和requests发送API请求,包含了错误处理和随机延迟以避免被检测为爬虫。
使用时需要配置你的QQ号、密码和chromedriver路径。工具会先登录QQ网页版,然后获取你加入的所有QQ群列表,接着可以获取指定群的所有成员详细信息,包括昵称、性别、年龄、加入时间等,最后将这些信息导出为JSON文件。
代码语言:txt复制
import time
import json
import random
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
class QQGroupMemberExporter:
def __init__(self, qq_number, qq_password, chrome_driver_path):
self.qq_number = qq_number
self.qq_password = qq_password
self.driver_path = chrome_driver_path
self.cookies = None
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Referer': 'https://qun.qq.com/',
'Content-Type': 'application/x-www-form-urlencoded'
}
self.service = Service(chrome_driver_path)
self.driver = None
def init_driver(self):
options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)
self.driver = webdriver.Chrome(service=self.service, options=options)
self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
def login_qq(self):
self.init_driver()
self.driver.get('https://qun.qq.com/')
try:
# 切换到iframe
WebDriverWait(self.driver, 10).until(
EC.frame_to_be_available_and_switch_to_it((By.ID, 'login_frame'))
)
# 点击账号密码登录
switch_btn = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.ID, 'switcher_plogin'))
)
switch_btn.click()
# 输入账号密码
username = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.ID, 'u'))
)
password = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.ID, 'p'))
)
username.clear()
username.send_keys(self.qq_number)
time.sleep(random.uniform(0.5, 1.5))
password.clear()
password.send_keys(self.qq_password)
time.sleep(random.uniform(0.5, 1.5))
# 点击登录
login_btn = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.ID, 'login_button'))
)
login_btn.click()
# 等待登录完成
WebDriverWait(self.driver, 30).until(
EC.presence_of_element_located((By.CLASS_NAME, 'header-info'))
)
# 获取cookies
self.cookies = {cookie['name']: cookie['value'] for cookie in self.driver.get_cookies()}
return True
except Exception as e:
print(f'登录失败: {str(e)}')
return False
def get_group_list(self):
if not self.cookies:
print('请先登录')
return []
try:
self.driver.get('https://qun.qq.com/member.html')
time.sleep(5) # 等待页面加载
# 获取群列表
group_elements = WebDriverWait(self.driver, 20).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.group-list .group-item'))
)
groups = []
for element in group_elements:
group_id = element.get_attribute('data-id')
group_name = element.find_element(By.CSS_SELECTOR, '.group-name').text
groups.append({'group_id': group_id, 'group_name': group_name})
return groups
except Exception as e:
print(f'获取群列表失败: {str(e)}')
return []
def get_group_members(self, group_id):
if not self.cookies:
print('请先登录')
return []
members = []
last_uin = 0
has_more = True
while has_more:
url = f'https://qun.qq.com/cgi-bin/qun_mgr/search_group_members'
params = {
'gc': group_id,
'st': 0,
'end': 20,
'sort': 0,
'bkn': self._get_bkn(),
'last_uin': last_uin
}
try:
response = requests.get(url, headers=self.headers, cookies=self.cookies, params=params)
data = response.json()
if data.get('ec') == 0:
member_list = data.get('mems', [])
for member in member_list:
members.append({
'uin': member.get('uin'),
'nick': member.get('nick'),
'gender': member.get('gender'),
'age': member.get('age'),
'join_time': member.get('join_time'),
'last_speak_time': member.get('last_speak_time'),
'level': member.get('level'),
'role': member.get('role')
})
has_more = data.get('has_more', False)
last_uin = member_list[-1].get('uin') if member_list else 0
else:
print(f'获取成员失败: {data.get("em", "未知错误")}')
break
time.sleep(random.uniform(1, 2))
except Exception as e:
print(f'请求出错: {str(e)}')
break
return members
def _get_bkn(self):
if not self.cookies or 'skey' not in self.cookies:
return 0
skey = self.cookies['skey']
hash_val = 5381
for char in skey:
hash_val += (hash_val << 5) + ord(char)
return hash_val & 2147483647
def export_to_file(self, data, filename):
try:
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f'数据已导出到 {filename}')
except Exception as e:
print(f'导出失败: {str(e)}')
def close(self):
if self.driver:
self.driver.quit()
if __name__ == '__main__':
# 配置信息
QQ_NUMBER = '你的QQ号'
QQ_PASSWORD = '你的QQ密码'
CHROME_DRIVER_PATH = 'chromedriver.exe路径'
exporter = QQGroupMemberExporter(QQ_NUMBER, QQ_PASSWORD, CHROME_DRIVER_PATH)
try:
# 登录QQ
if exporter.login_qq():
print('登录成功')
# 获取群列表
groups = exporter.get_group_list()
print(f'找到 {len(groups)} 个群')
for group in groups:
print(f'\n正在获取群 {group["group_name"]}({group["group_id"]}) 的成员...')
# 获取群成员
members = exporter.get_group_members(group['group_id'])
print(f'获取到 {len(members)} 个成员')
# 导出到文件
filename = f'qq_group_{group["group_id"]}_members.json'
exporter.export_to_file({
'group_id': group['group_id'],
'group_name': group['group_name'],
'members': members
}, filename)
else:
print('登录失败')
finally:
exporter.close()