Initial commit

This commit is contained in:
Qiea
2024-12-22 01:07:54 +08:00
commit 798e299d04
7 changed files with 406 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

162
.gitignore vendored Normal file
View File

@@ -0,0 +1,162 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
/.idea
/img

2
README.md Normal file
View File

@@ -0,0 +1,2 @@
# GetQQInfo
我超,盒

73
Thread.py Normal file
View File

@@ -0,0 +1,73 @@
import threading
import pymysql
from tools import *
class UploadThread(threading.Thread):
def __init__(self, uploadqqnumber):
super().__init__()
self.uploadqqnumber = uploadqqnumber
self.conn = pymysql.connect(
host='192.168.9.1', # 你的 MySQL 主机
user='root', # 你的 MySQL 用户
password='123456', # 你的 MySQL 密码
database='qqinfo' # 你要连接的数据库
)
def conn_close(self):
self.conn.close()
def run(self):
print(f'我是上传线程{self.uploadqqnumber}')
if download_image(self.uploadqqnumber):
Hash(self.conn).tomysql(self.uploadqqnumber)
print('上传成功')
remove_image(self.uploadqqnumber)
class FindThread(threading.Thread):
def __init__(self, TargetImageHash):
super().__init__()
self.TargetImageHash = TargetImageHash
self.conn = pymysql.connect(
host='192.168.9.1', # 你的 MySQL 主机
user='root', # 你的 MySQL 用户
password='123456', # 你的 MySQL 密码
database='qqinfo' # 你要连接的数据库
)
def conn_close(self):
self.conn.close()
def run(self):
print(f'我是查询线程{self.TargetImageHash}')
res = Hash(self.conn).getqq(self.TargetImageHash)
if res != 'error':
print(f'查询成功QQ号是: {res}')
exit()
class ByNetFindThread(threading.Thread):
def __init__(self, TargetImageHash, findqqnumber):
super().__init__()
self.TargetImageHash = TargetImageHash
self.findqqnumber = findqqnumber
def run(self):
if download_image(self.findqqnumber):
FindImage = Image.open(str(f'./img/{self.findqqnumber}.jpg'))
FindImageHash = bytes.fromhex(str(imagehash.average_hash(FindImage)))
res = compare(self.TargetImageHash, FindImageHash)
if res-99.9 >= 0 :
print(f'找到QQ号了:{self.findqqnumber}')
os.rename(f'./img/{self.findqqnumber}.jpg',f'./img/congratulations_{self.findqqnumber}.jpg')
exit()
print(f'[{self.findqqnumber}]的相似度是:{res}')
remove_image(self.findqqnumber)

24
main.py Normal file
View File

@@ -0,0 +1,24 @@
from Thread import pymysql, UploadThread, FindThread, ByNetFindThread , threading
from tools import imagehash, Image, download_image
# download_image(1310371422)
TargetRange = [1310372220, 1310372400]
TargetImage = Image.open(str(f'./img/target3.jpg'))
TargetImageHash = bytes.fromhex(str(imagehash.average_hash(TargetImage)))
baseArr = TargetRange[0]
if __name__ == '__main__':
Thread = FindThread(TargetImageHash)
Thread.start()
# while baseArr<TargetRange[1]:
# Thread = ByNetFindThread(TargetImageHash, baseArr)
# Thread.start()
# baseArr += 1
# while baseArr<=TargetRange[1]:
# Thread = UploadThread(baseArr)
# Thread.start()
# baseArr += 1

16
test.py Normal file
View File

@@ -0,0 +1,16 @@
def hamming_distance(hash1, hash2):
# 将哈希值转换为二进制字符串
bin1 = bin(int(hash1, 16))[2:].zfill(len(hash1) * 4) # 16进制转二进制
bin2 = bin(int(hash2, 16))[2:].zfill(len(hash2) * 4)
# 计算汉明距离
return sum(c1 != c2 for c1, c2 in zip(bin1, bin2))
# 给定的两个哈希值
hash1 = 'ffffff7060606000'
hash2 = '000034e3ffffffbf'
# 计算汉明距离
distance = hamming_distance(hash1, hash2)
print(f'汉明距离: {distance}')

127
tools.py Normal file
View File

@@ -0,0 +1,127 @@
import os
import requests
from PIL import Image
import imagehash
class Hash:
def __init__(self, conn):
self.conn = conn
def gethash(self, _qqnumber):
"""
根据传入的qq号获取数据库里的hash值
:param: _qqnumber: QQ号
:return: 字节类型Hash值
"""
_cursor = self.conn.cursor()
_cursor.execute('SELECT hash FROM image_hashes WHERE id = (%s)', (_qqnumber,))
byte_data_from_db = _cursor.fetchone()
if byte_data_from_db is None:
print(f'{_qqnumber}不在数据库内')
else:
print(f'从数据库获取的Hash号: {byte_data_from_db[0]}')
_cursor.close()
return byte_data_from_db[0]
def getqq(self, _hash):
"""
根据传入的{字节类型Hash值}获取数据库里的QQ号
:param: _hash: 字节类型Hash值
:return: QQ号
"""
_cursor = self.conn.cursor()
_cursor.execute('SELECT id FROM image_hashes WHERE hash = (%s)', (_hash,))
byte_data_from_db = _cursor.fetchone()
if byte_data_from_db is None:
print('Hash值不存在')
return 'error'
else:
print(f'从数据库获取的QQ号: {byte_data_from_db[0]}')
_cursor.close()
return byte_data_from_db[0]
def tomysql(self, _qqnumber):
"""
根据传入的qq号下载并解析qq头像中的哈希值最后上传到Mysql
:param: _qqnumber: QQ号
"""
_img = Image.open(str(f'./img/{_qqnumber}.jpg'))
_byte_data = bytes.fromhex(str(imagehash.average_hash(_img)))
_cursor = self.conn.cursor()
_cursor.execute("""
INSERT INTO image_hashes (id, hash)
VALUES (%s, %s)
ON DUPLICATE KEY UPDATE
hash = VALUES(hash)
""", (_qqnumber, _byte_data))
print(f'[{_qqnumber}]:{_byte_data}')
self.conn.commit()
_cursor.close()
def compare(hash1, hash2):
"""
根据{字节类型Hash值},比较两个图片的相似度
:param hash1: {字节类型Hash值}
:param hash2: {字节类型Hash值}
:return: 相似度百分比
"""
hash1 = hash1.hex()
hash2 = hash2.hex()
# 将哈希值转换为二进制字符串
bin1 = bin(int(hash1, 16))[2:].zfill(len(hash1) * 4) # 16进制转二进制
bin2 = bin(int(hash2, 16))[2:].zfill(len(hash2) * 4)
# 计算汉明距离
hamming_distance = sum(c1 != c2 for c1, c2 in zip(bin1, bin2))
# 计算相似度百分比
return (1 - hamming_distance / 64) * 100
def download_image(_qqnumber):
"""
根据传入的 _qqnumber 下载 QQ 图片并保存到 img 文件夹中。
:param _qqnumber: QQ号
:return: 成功1 失败0
"""
if not os.path.exists('img'):
os.makedirs('img')
# 构建图片 URL 和文件名
image_url = f'https://q1.qlogo.cn/g?b=qq&nk={_qqnumber}&s=0'
image_name = os.path.join('img', f'{_qqnumber}.jpg')
# 发送请求获取图片
response = requests.get(image_url)
if response.status_code == 200:
# 保存图片
with open(image_name, 'wb') as f:
f.write(response.content)
print(f'图片已保存为 {image_name}')
return 1
else:
print(f'下载图片失败,错误码:{response.status_code}')
return 0
def remove_image(_qqnumber):
"""
根据传入的 _qqnumber 删除对于图片
:param _qqnumber: QQ号
:return: 成功1 失败0
"""
if os.path.exists(f'./img/{_qqnumber}.jpg'):
os.remove(f'./img/{_qqnumber}.jpg')
return 1
else:
print(f'没有找到这个QQ号的图片:{_qqnumber}')