文章目录
- 项目背景、目的和意义
- 业务说明
- 代码实现:
- 1.GUI_main.py用户界面,用于运行程序
- 2.ourmain.py 工程主程序
- 3.encrypts0.py 进行文本加密
- 4.decrypts1.py 进行文本解密
- 5.directory.py 创建用户目录
- 6.shuoshuo_wzq.py 爬取说说
- 7.rizhi_neirong_wzq.py 爬取日志内容
- 8.rizhi_timu_wzq.py 爬取日志题目
- 9.information.py 爬取个人信息
- 10.friends.py 爬取好友列表
- 11.login.py 登录验证码识别
项目背景、目的和意义
随着科学技术的不断发展,互联网进展的不断加快,人工智能、大数据和云计算等新兴技术的不断涌现,目前每天都有上亿的数据在网络中流通。而人工收集数据的发法效率低,成本高。因此,本项目利用Python爬虫等技术,能够在数分钟内,实现自动登录QQ空间,抓取个人信息、好友列表、说说和日志等信息,同时能够及时对抓取的数据进行加密,保证了通信安全。本项目的成功实施,对办公自动化、信息检索、互联网信息安全等方面具有重要意义,同时加以GUI界面进行封装,提高了程序的普适性和交互性。
业务说明
启动程序后,提示用户可供选择的操作:
1.抓取信息:继续提示输入QQ号和密码(密码不能显示出来,用*号代替),然后登录QQ空间,抓取其中的①QQ个人信息;②好友列表;③说说和日志;把获取到的信息经过加密后存入csv文件中。
2.显示信息:用户输入QQ号码后,生成解密的csv文件,用户可查看:①QQ个人信息;②好友列表;③说说和日志;输入Quit或quit可以退出系统。
代码实现:
1.GUI_main.py用户界面,用于运行程序
每一次抓取,都会为当前QQ建立一个文件夹,方便分类收集QQ的QQ空间中信息。
如果重复抓取,则会提醒用户已经抓取过了,此时可以选择删除该QQ的文件夹重新抓取或者显示信息。
如果想查看未抓取的QQ,则会提醒当前用户还未抓取过信息,此时可以选择输入该QQ的面进行抓取
具体代码如下:
import tkinter as tk
import tkinter.messagebox as Msg
from directory import mkdir
import os
window = tk.Tk()
window.title('QQ空间,分享生活,留住感动')
window.geometry('450x350')
# 欢迎界面
canvas = tk.Canvas(window, height=500, width=500)
image_file = tk.PhotoImage(file='demo.gif')
image = canvas.create_image(0,0, anchor='nw', image=image_file)
canvas.pack(side='top')
# 用户信息
tk.Label(window, text='Q Q ').place(x=50, y= 200)
tk.Label(window, text='密码 ').place(x=50, y= 230)
tk.Label(window, text='加密/解密秘钥 ').place(x=10, y= 260)
var_usr_name = tk.StringVar()
var_usr_name.set('在这里输入qq号')
entry_usr_name = tk.Entry(window, textvariable=var_usr_name)
entry_usr_name.place(x=100, y=200)
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show='*')
entry_usr_pwd.place(x=100, y=230)
var_key = tk.StringVar()
entry_key = tk.Entry(window, textvariable=var_key)
entry_key.place(x=100, y=260)
var_key.set('请输入0-1000整数')
def get_all():
"""完成对内容的抓取和加密的过程"""
username = var_usr_name.get()
password = var_usr_pwd.get()
key = var_key.get()
file = username + "\\" + username + '_encrypted.csv'
# 为当前用户创建文件夹
if( not os.path.exists(username) or not os.path.exists(file)):
# *************************爬取信息的主程序
mkdir(username)
import ourmain
isSuccess = ourmain.main(username, password, key)
if isSuccess:
Msg.showinfo(message="信息已经抓取并加密完毕!")
else:
Msg.showinfo(message="账号或密码错误")
else:
Msg.showwarning(message="当前用户已经抓取过信息了!")
return
def show_all():
"""完成对内容的解密过程"""
username = var_usr_name.get()
path = username
key = var_key.get()
if(os.path.exists(path)):
# ********************显示信息的主程序
import decrypts1
file0 = username + "\\" + username + '_encrypted.csv'
file1 = username + "\\" + username + '_decrypted.csv'
decrypts1.save_file(file0, file1, key)
Msg.showinfo(message="信息解密完毕!")
else:
Msg.showerror(message="当前用户还未抓取过信息!")
return
pass
# 按钮
btn_get = tk.Button(window, text='抓取信息', activeforeground = "black",activebackground = 'blue',command=get_all)
btn_get.place(x=100, y=300)
btn_show = tk.Button(window, text='显示信息', activeforeground = "black",activebackground = 'blue',command=show_all)
btn_show.place(x=200, y=300)
btn_quit= tk.Button(window,text = 'Quit',activeforeground = "black",activebackground = 'blue',command=window.destroy)
btn_quit.place(x=300, y=300)
window.mainloop()
2.ourmain.py 工程主程序
# -*- coding: utf-8 -*-
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from login import login1 as login
from friends import friends_lis
from information import get_information
from shuoshuo_wzq import get_shuoshuo
from encrypts0 import save_file
from rizhi_neirong_wzq import get_rizhi as neirong
from rizhi_timu_wzq import get_rizhi as timu
def main(username,password,key):
login_url = 'https://qzone.qq.com/'
driver = webdriver.Chrome(ChromeDriverManager().install())
#driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get(login_url)
if login(driver,username,password) == None:
driver.quit()
return False
'''---------------------建立CSV文件--------------------'''
filename = username + "\\" + username + '.csv'
file = open(filename,'w+',encoding='utf-8')
'''---------------------爬取个人信息-------------------'''
try:
get_information(driver,file,username)
except Exception as e:
print(e)
file.write('!!!!!个人信息抓取失败!!!!!\n')
'''---------------------爬取好友列表-------------------'''
try:
friends_lis(driver,username,file)
except Exception as e:
print(e)
file.write('\n!!!!!好友列表抓取失败!!!!!\n')
'''----------------------爬取说说----------------------'''
try:
get_shuoshuo(driver,file,username)
except Exception as e:
print(e)
file.write('\n!!!!!说说抓取失败!!!!!\n')
'''----------------------爬取日志---------------------'''
try:
timu(driver,file)
except:
file.write('\n!!!!!日志题目抓取失败!!!!!\n')
try:
neirong(driver,file)
except Exception as e:
print(e)
file.write('\n!!!!!日志内容抓取失败!!!!!\n')
file.close()
'''----------------------文件加密---------------------'''
file0 = filename
jiami_file = username+ "\\" + username+ '_encrypted'+'.csv'
save_file(file0, jiami_file ,key)
driver.quit()
return True
if __name__ == '__main__':
username = input('请输入QQ号:')
password = input('请输入密码:')
key = int(input('key:'))
main(username,password,key)
3.encrypts0.py 进行文本加密
加密与解密原理:
使用ord()函数得道每个函数的编码值,将其与秘钥进行异或操作得到暗文
根据异或操作的性质,假设a是明文, k是秘钥, b是密文那么, a^k = b, b^k = a,只要加密和解密方的秘钥一致,就可以成功的加密解密。
例如,使用ord(‘我’) = 25105, 设置加密秘钥为123,那么25105123=25194,使用chr()函数可以得到编码值对应的字符,chr(25194)=‘扪’即为密文。解密时,如果秘钥为123,那么密文ord(’扪’)123 = 25194^ 123 = 25105, chr(25105)即为’我’,得到正确的明文。若秘钥不为123,则异或结果将得不到25105,因此解密之后得到的字符就会乱码了。
优点:
使用简单的异或操作即可实现,方法简单易实现、易理解,不需要导入额外的包,使用基本语法即可。解密即是加密的逆过程。
缺点:
由于异或操作即支持数值运算,因此秘钥只能为纯数字。
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 10 20:29:37 2020
@author: Administrator
"""
import csv
import os
"""
原理:
使用ord()函数得道每个函数的编码值,将其与秘钥进行异或操作得到暗文
根据异或操作的性质,假设a是明文, k是秘钥, b是密文
那么, a^k = b, b^k = a
只要加密和解密方的秘钥一致,就可以成功的加密解密
"""
def encode(l, key):
"""
l:列表,即明文,l:列表,即明文,例如['aa','bb','cc']
key: 秘钥(int型)
返回:暗文(列表)
"""
try:
key = eval(key)
except NameError:
print("Invalid Key!Encrypt with default key.")
key = 20
else:
if type(key)!= int:
print("Invalid Key!Encrypt with default key.")
key = 20
elif key < 0 | key >= 1000:
print("Invalid Key!Encrypt with default key.")
key = 20
encode_list = []
for i in l: # i 是一个字符串
i = list(i)
i = (chr(ord(j)^key) for j in i)
encode_list.append("".join(i))
return encode_list
def save_file(file0, file1 ,key):
f0 = open(file0, 'r', encoding='utf-8')
f1 = open(file1, "w", encoding="utf-8", newline='')
csv_reader = csv.reader(f0)
csv_writer = csv.writer(f1)
# reader与 writer都是以列表形式读出,并且可以以列表形式写入
for cont in csv_reader:
#print(cont)
encode_row = encode(cont, key)
csv_writer.writerow(encode_row)
f0.close()
os.remove(file0)
f1.close()
print("=======加密成功=======")
if __name__ == "__main__":
save_file("说说.csv","说说_加密.csv", 123)
4.decrypts1.py 进行文本解密
# -*- coding: utf-8 -*-
import csv
import random
def decode(l, key):
"""
l:列表,即暗文,例如['aa','bb','cc']
key: 秘钥(int型)
返回:明文(列表)
"""
try:
key = eval(key)
except NameError:
print("Invalid Key!Decrypt with random key.")
key = random.randint(0,100)
else:
if type(key)!= int:
print("Invalid Key!Decrypt with random key.")
key = random.randint(0,100)
elif key < 0 | key >= 1000:
print("Invalid Key!Decrypt with random key.")
key = random.randint(0,100)
5.directory.py 创建用户目录
""""创建目录,为每一个登陆的qq创建一个目录,用来保存其提取到的信息"""
def mkdir(path):
# 引入模块
import os
# 去除首位空格
path=path.strip()
# 去除尾部 \ 符号
path=path.rstrip("\\")
# 判断路径是否存在
# 存在 True
# 不存在 False
isExists=os.path.exists(path)
# 判断结果
if not isExists:
# 如果不存在则创建目录
os.makedirs(path)
print(path+' 创建成功')
return True
else:
# 如果目录存在则不创建,并提示目录已存在
print(path+' 目录已存在')
return False
# 定义要创建的目录
if __name__ == '__main__':
mkpath="123123"
# 调用函数
mkdir(mkpath)
6.shuoshuo_wzq.py 爬取说说
import time
from time import sleep
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from login import login1
import requests
import os
# 登录QQ空间
def get_shuoshuo(driver,f,username):
driver.get('https://qzone.qq.com/')
sleep(1)
headers = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36',
'Connection':'close',
}
requests.adapters.DEFAULT_RETRIES = 5
s = requests.session()
s.keep_alive = False
path = username + '\\' + 'piclibs'
if not os.path.exists(path):
os.mkdir(path)
print('----------------------------------------------')
print('-----------------正在爬取说说------------------')
#进入说说主界面
driver.find_element_by_xpath('//*[@id="menuContainer"]/div/ul/li[5]/a').click()
sleep(3)
#创建新文件,记得要把之前生成的删掉
f.write('\n==============说说==============\n')
for j in range(2):
driver.execute_script("window.scrollBy(0,20000)")
time.sleep(1)
num = 0
while True:
#下拉页面,以便获取数据与点击翻页
num += 1
for j in range(2):
driver.execute_script("window.scrollBy(0,20000)")
time.sleep(1)
#切换到读说说的架构当中
iframe = driver.find_element_by_xpath('//*[@id="app_container"]/iframe')
driver.switch_to.frame(iframe)
#进行读取
content = driver.find_elements_by_css_selector('.content')
for con in content:
data = con.text
#print(data)
f.write(data+'\n')
imgs = driver.find_elements_by_css_selector('a[title="查看大图"]')
for i,img in enumerate(imgs):
imgscr = img.get_attribute("href")
img_data = requests.get(url = imgscr,headers = headers).content
img_name = str(num) + 'page' + str(i) + '.jpg'
img_path = path + '\\' + img_name
#print(imgscr)
with open(img_path,'wb') as fp:
fp.write(img_data)
#进行翻页,如果不能翻页则默认程序完成,说说爬取完毕
try:
driver.find_element_by_link_text(u'下一页').click()#点击下一页
time.sleep(1)
#该页说说爬取完毕后,要切换回默认值以便进行下拉页面
driver.switch_to.default_content()
except:
print('-----------------说说爬取完成------------------')
break
7.rizhi_neirong_wzq.py 爬取日志内容
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from time import sleep
def get_rizhi(driver,f):
driver.get('https://qzone.qq.com/')
sleep(1)
print('----------------------------------------')
print('----------正在爬取日志内容---------------')
#进入说说主界面
driver.find_element_by_xpath('//*[@id="menuContainer"]/div/ul/li[2]/a').click()
sleep(3)
try:
#进入第一篇页面
iframe = driver.find_element_by_xpath('//*[@id="tblog"]')
driver.switch_to.frame(iframe)
driver.find_element_by_xpath('//*[@id="listArea"]/ul/li[1]/div[1]/span/a').click()
sleep(3)
#创建新文件,记得要把之前生成的删掉
f.write('\n=============日志内容=============\n')
while True:
try:
#切换frame到日志内容
driver.switch_to.default_content()
iframe = driver.find_element_by_css_selector('.app_canvas_frame')
driver.switch_to.frame(iframe)
#爬取日志题目和内容
title = driver.find_element_by_css_selector('.blog_tit_detail').text
content = driver.find_element_by_css_selector('div[id = "blogDetailDiv"]').text
#print(title+'\n'+content+'\n')
f.write(title+'\n'+content+'\n\n')
#进行翻页,没有下一页则执行except同时爬取结束
pages = driver.find_element_by_css_selector('a[rel="nextBlog"]')
driver.execute_script("arguments[0].click();", pages)
sleep(3)
except:
print('----------日志内容爬取完成------------')
break
except:
print('-----------------日志为空------------------')
8.rizhi_timu_wzq.py 爬取日志题目
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time
from time import sleep
# 登录QQ空间
def get_rizhi(driver,f):
driver.get('https://qzone.qq.com/')
sleep(1)
print('---------------------------------------')
print('----------正在爬取日志题目--------------')
#进入日志主界面
driver.find_element_by_xpath('//*[@id="menuContainer"]/div/ul/li[2]/a').click()
sleep(3)
#创建新文件,记得要把之前生成的删掉
f.write('\n=============日志题目=============\n')
while True:
#下拉页面,以便获取数据与点击翻页
for j in range(2):
driver.execute_script("window.scrollBy(0,5000)")
time.sleep(2)
#切换到读日志的架构当中
iframe = driver.find_element_by_xpath('//*[@id="tblog"]')
driver.switch_to.frame(iframe)
#进行读取
content = driver.find_elements_by_css_selector('a[rel="blog-detail-link"]')
for con in content:
data = con.text
#print(data)
f.write(data+'\n')
#进行翻页,如果不能翻页则默认程序完成,日志爬取完毕
try:
time.sleep(2)
driver.find_element_by_link_text(u'下一页').click()#点击下一页
time.sleep(2)
#该页日志爬取完毕后,要切换回默认值以便进行下拉页面
driver.switch_to.default_content()
except:
print('------------日志题目爬取完成--------------')
break
9.information.py 爬取个人信息
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from login import login1 as login
from time import sleep
def get_information(driver,information_file,username):
sleep(1)
driver.get('https://user.qzone.qq.com/'+username+'/1')
sleep(2)
driver.switch_to.frame('ttinfo')#
sleep(1)
biaoti = ['性别','年龄','生日','星座','现居地','婚姻状况','血型','故乡','职业','公司名称','公司所在地','详细地址']
neirong = driver.find_elements_by_css_selector('.preview_option')
information_file.write('\n=============个人信息==============\n')
information = []
for biao,nei in zip(biaoti,neirong):
information.append((biao,nei.text))
information_file.write(biao+':'+nei.text+'\n')
return information
10.friends.py 爬取好友列表
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from login import login1 as login
from time import sleep
def friends_lis(driver,user,haoyou_file):
sleep(1)
#使用了url方法找到好友页面
haoyou_url = 'https://user.qzone.qq.com/'+user+'/myhome/friends'
driver.get(haoyou_url)
#转换iframe
iframe = driver.find_element_by_xpath('//iframe')
sleep(2) # 等待资源加载
driver.switch_to.frame(iframe)
sleep(1)
#获取好友信息,转化为列表
haoyou_file.write('\n=============好友列表=============\n')
lis = (driver.find_element_by_xpath('//*[@id="mecarewho_list"]').text).split('\n')
haoyou_lis = [lis[i] for i in range(1,len(lis),4)]
for item in haoyou_lis:
haoyou_file.write(item+'\n')
before = haoyou_lis
#存在多页情况#mecarewho_pager > a.qz-button.btn-pager-next
while(True):
try:
next_page = driver.find_element_by_css_selector('#mecarewho_pager > a.qz-button.btn-pager-next')
next_page.click()
sleep(1)
lis = (driver.find_element_by_xpath('//*[@id="mecarewho_list"]').text).split('\n')
haoyou_lis = [lis[i] for i in range(1,len(lis),4)]
if haoyou_lis == before:
break
else:
before = haoyou_lis
for item in haoyou_lis:
haoyou_file.write(item+'\n')
except:
break
sleep(1)
return haoyou_lis
11.login.py 登录验证码识别
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from time import sleep
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
def login1(driver,username,password):
# username = input('请输入QQ号:')
# password = getpass.getpass('请输入密码:')
driver.switch_to.frame('login_frame')
sleep(3)
driver.find_element_by_id('switcher_plogin').click()
driver.find_element_by_id('u').clear()
driver.find_element_by_id('u').send_keys(username)
driver.find_element_by_id('p').clear()
driver.find_element_by_id('p').send_keys(password)
sleep(2)
driver.find_element_by_xpath('//*[@id="login_button"]').click()
sleep(2)
try:#点击‘主页’,验证是不是登录成功
driver.find_element_by_xpath('//*[@id="menuContainer"]/div/ul/li[1]/a').click()
print('=========登录成功=========')
except:#账号密码正确的前提下,未登录成功,说明有验证过程
try:
#需要转换frame
iframe = driver.find_element_by_xpath('//iframe')
sleep(2) # 等待资源加载
driver.switch_to.frame(iframe)
# 等待图片加载出来
WebDriverWait(driver, 5, 0.5).until(
EC.presence_of_element_located((By.ID, "tcaptcha_drag_button"))
)
button = driver.find_element_by_id('tcaptcha_drag_button')
sleep(1)
#按照偏移量循环调整滑块拖动距离
bias = [0,10,-10,5,-5,3,-3,-1,1]
for i in bias:
action = ActionChains(driver)
action.click_and_hold(button).perform()
action.move_by_offset(xoffset=i+173, yoffset=0).perform()
action.reset_actions()
sleep(0.5)
action.release().perform()
sleep(5)
try:#点击‘主页’,验证是不是登录成功
driver.find_element_by_xpath('//*[@id="menuContainer"]/div/ul/li[1]/a').click()
print('=========登录成功=========')
break
except:
continue
except:
print('=========账号或密码错误,请重新输入=======')
username = None
#print(username)
return username