Pull to refresh

Получаем ссылки на профили Vk из выдачи SearchFace с помощью Python (но это не точно)

Reading time9 min
Views53K
Картинка для привлечения внимания:


Кадр из сериала Person Of Interest

Сегодня мы поговорим о лёгком распознавании лиц с помощью доступных инструментов.
Используются: Python 3.6, searchface.ru, внешний сервис для преобразования ссылок на фото в id (бот в телеграме, на текущий момент)


Итак, у нас есть сайт, который ищет по лицам.
Заглянем внутрь.

Внутри обычная форма, которая отправляет Post запрос, который в ответ возвращает json.

пример
Отправляем фото, к примеру, Гарольда Финча из сериала Person Of Interest (Майкл Эмерсон):


Получаем:

[[0.991, [['https://pp.userapi.com/h2ViUULg76AaNRw9XBBJOkBMOhQbphQivldE8A/wledD6KFj7I.jpg', 310, 136, 122]]], [0.984, [['https://pp.userapi.com/c622531/v622531393/4fa11/x-N_Rv4lUp0.jpg', 251, 178, 99]]], [0.972, [['https://pp.userapi.com/c840426/v840426427/5f090/m9XVCm9Zd4k.jpg', 200, 143, 78]]], [0.918, [['https://pp.userapi.com/c840339/v840339996/30f51/h_HS2peh0Hs.jpg', 80, 100, 75], ['https://pp.userapi.com/c840138/v840138996/52746/lgYobQh0EIo.jpg', 281, 201, 112], ['https://pp.userapi.com/c840420/v840420996/32a0e/MsauPmM6obU.jpg', 293, 137, 80]]], [0.906, [['https://pp.userapi.com/uacyJQkkoESbTNhRAo6JcqfyKVsPMwZYqTEzfw/GZKQ9rLNlpA.jpg', 310, 122, 127], ['https://pp.userapi.com/QQJWVDF2YT1MvkupPgahB2Uz3_vkZ7-FAhIucw/tva0l9dBAj8.jpg', 642, 325, 257], ['https://pp.userapi.com/LI5hCDYqB8Ju9KA8hQjf1yzYVmuliA7uBXuJoA/_4q-yoLXCRI.jpg', 293, 277, 170]]], [0.893, [['https://pp.userapi.com/xvSllwTcM3tJ8bwi8yhn10fnCgT68X_24Q3peQ/yY8N1DxpQ5o.jpg', 324, 340, 194], ['https://pp.userapi.com/h2ViUULg76AaNRw9XBBJOkBMOhQbphQivldE8A/wledD6KFj7I.jpg', 310, 136, 122], ['https://pp.userapi.com/HJeMSYoCLGdub2ueloZA7pqOin9QVkLhnHCRUw/49ngz53y4gw.jpg', 306, 347, 140], ['https://pp.userapi.com/SpuLGp49INoN0mr0J1cs5uQD6G9Zqb8boABlpQ/Zfh9Ay8zHvc.jpg', 235, 254, 66]]], [0.891, [['https://pp.userapi.com/c628825/v628825986/ac15/ucROr8sUVto.jpg', 304, 120, 90]]], [0.886, [['https://pp.userapi.com/nxyVWitUFsvxOP1bAbabmGGEg8GPrjEryvFRRQ/NOjnG-Oxl_Q.jpg', 142, 192, 121], ['https://pp.userapi.com/L-40BbkBjFiy4BZJNIlFBqASysOPldnZEqzraA/HM9rgh9hKpo.jpg', 813, 383, 172], ['https://pp.userapi.com/tJpeoXXZzm2EIgajpUxh8AuXHDtBcF1NJ1OefA/TMrMSuLb9eE.jpg', 497, 357, 199]]], [0.879, [['https://pp.userapi.com/c836527/v836527332/5212c/pz-mv3JoSoY.jpg', 298, 216, 161]]], [0.877, [['https://pp.userapi.com/c637416/v637416770/60691/dfGmo0NzQxE.jpg', 298, 215, 156]]], [0.871, [['https://pp.userapi.com/c636926/v636926559/35798/8VjR2jNfPfU.jpg', 399, 381, 216], ['https://pp.userapi.com/c636927/v636927559/33577/vFJobCuXEAw.jpg', 199, 150, 65], ['https://pp.userapi.com/c636927/v636927559/337d5/OAeQ3Hw2mb4.jpg', 506, 139, 65], ['https://pp.userapi.com/c841334/v841334162/799ce/R0XkD7T4B44.jpg', 521, 288, 293], ['https://pp.userapi.com/c824204/v824204162/f0dec/q_cZvfXl8Wc.jpg', 317, 407, 246]]], [0.869, [['https://pp.userapi.com/QJ1FU4eGuSes4UxeitONvx3uolZvNDXq61JDcg/9bBDAO3RKwo.jpg', 330, 236, 170]]], [0.861, [['https://pp.userapi.com/c305901/v305901469/57ed/y3u2vHkdbLY.jpg', 235, 192, 197], ['https://pp.userapi.com/c622124/v622124469/51cc/sCsVgsWILT8.jpg', 234, 202, 223], ['https://pp.userapi.com/c625321/v625321469/1093d/RL1x2C9ZXXo.jpg', 255, 154, 135], ['https://pp.userapi.com/c630924/v630924469/3baf2/wUNtCyOtxkk.jpg', 311, 264, 561], ['https://pp.userapi.com/c630924/v630924469/3bb6c/gCq6-DJMrxw.jpg', 466, 170, 211]]], [0.849, [['https://pp.userapi.com/c604631/v604631165/12043/vFf7H0_YMn8.jpg', 300, 145, 223], ['https://pp.userapi.com/c636625/v636625165/3ebc1/xNAwmB38DLM.jpg', 989, 223, 156], ['https://pp.userapi.com/c636625/v636625165/3ebcb/BoFgWTDlNt4.jpg', 725, 381, 247]]], [0.847, [['https://pp.userapi.com/c621930/v621930615/1fee3/mxs1ujqVJNw.jpg', 797, 362, 345], ['https://pp.userapi.com/c625428/v625428615/391fa/czEn2oj77kQ.jpg', 462, 205, 152], ['https://pp.userapi.com/c623928/v623928615/344b0/fntYJm5VtWw.jpg', 744, 789, 461]]], [0.841, [['https://pp.userapi.com/rw-gkzZmq2p_HqVCFmUKcY6DWveJFqS6P4mqTA/uLsYHKv1u2E.jpg', 332, 179, 135], ['https://pp.userapi.com/ObAY2Vt1s1xF7MacRbdMEDtOoQ8mvdIPZpMPtA/e8jJydqmyRM.jpg', 303, 369, 240], ['https://pp.userapi.com/TWNCYtNxiq1KadoXtILhiKIx2XKcmg-56Ks8ow/siomQIkxTiU.jpg', 174, 249, 141], ['https://pp.userapi.com/3kDEgo6u3pnVfDq5wj3FLYJtDVPJReTpuL_cPg/o-pZesCYX3s.jpg', 357, 238, 111], ['https://pp.userapi.com/xaPb0xwcLy9NPVfujOv8EmZJnscQeKhiITWvyg/rCAfnO81Mco.jpg', 426, 292, 288]]]]


Своего рода API, с единственным(?) методом.

Я автоматизировал этот процесс на Python, с сохранением ссылок в файл для последующего анализа:

Пример
Отправляем фото photo.jpg, результат сохраняем в file.txt

import requests
import os
import sys
import re
photo = 'photo.jpg'
file = 'file.txt'
url = 'http://searchface.ru/request/'
proxies = {
  'http': '46.101.1.221:80',
  'https': '46.101.1.221:80',
}

def request_page(filename):
	try:
		files = {
		    'upl': (filename, open(filename, 'rb')),
		}
		r = requests.post(url, files=files,  proxies=proxies)
		return r
	except:
		print("no file")
		r = {}
		return r

def save_image_links(r, filename):
	try:
		j = r.json()	
		# print(j)		
	except:
		print("no json")
		return False
	print("Save images links:")		
	img_file = open(filename, 'w')
	for i in r.json():
		# print(i[1][0][0])
		print(i[0])
		img_file.write(str(i[0]) + '\n')

		for k in i[1]:
			# print(str(k))
			print(str(k[0]))
			img_file.write(str(k[0])+ '\n')

	img_file.close() 
	return True


def main():  
	r = request_page(photo)
	print(r)
	save_image_links(r, file)

if __name__ == '__main__':  
	try:
		main()
	except KeyboardInterrupt:
		exit()


Идея практического применения простая: Отправляем фото нужных людей, заносим ссылки (или хэши ссылок) в базу, отправляем по очереди кучу фото, если человек интересующий нас на фото один и не будет ошибок, ссылка при проверке по базе укажет нам на него.


Кадр из сериала Person Of Interest

Остается узнать id в vk.

Тут есть несколько вариантов:

1. Вытащить id из некоторых старых ссылок

пример кода
import re
def id_in_string(s):
	result = re.findall(r'/u\d+/', s)
	a = s.find('/u')
	if(len(result) > 0):
		b = str(result).find("/']")
		return 'https://vk.com/id' + str(result)[4:b]

2. Создать свою базу из людей с известными id (друзья, знакомые, знаменитости..)

3. Воспользоваться внешним сервисом, т.к. задача парсинга базы фото вк тривиальна, просто на нее спросу раньше не было. Сейчас такие сервисы появляются.

Для примера, воспользуемся ботом в телеграме @VkUrlBot.

База бота ограничена, ищет не все id, поэтому, для ручного поиска он неудобен, зато, бесплатен (на момент публикации).

Т.к телеграм не разрешает ботам общаться между собой, во избежание зацикливания, прикинемся пользователем. Для этого, устанавливаем telethon, регистрируем новое приложение телеграм, вбиваем полученные учетные данные (id и hash).

Пример

import socks
import time
import re
from telethon import TelegramClient, sync
from telethon.tl.functions.messages import SendMessageRequest

api_id = #int
api_hash = ''

phone = ''
username = ''

file = "file.txt"

def string_to_vk_id(s):
	return re.findall(r'(https?://[^\s]+)', s) 

def main():  
	with TelegramClient(username, api_id, api_hash, proxy=(socks.SOCKS5, '127.0.0.1', 9150)) as client:
		print("Client OK")	

		'''Обратите внимание, что 'some_name'будет использоваться для сохранения вашего сеанса
		(постоянная информация, такая как ключ доступа и другие), 
		как 'some_name.session'на вашем диске. 
		По умолчанию это файл базы данных с использованием Python sqlite3.

		Важно, чтобы библиотека всегда обращалась к одному и тому же файлу сеанса,
		чтобы вам не приходилось повторно отправлять код снова и снова. 
		По умолчанию он создает файл в вашем рабочем каталоге, но абсолютные пути тоже работают.'''


		# Ensure you're authorized
		if not client.is_user_authorized():
			client.send_code_request(phone)
			try:
				client.sign_in(phone, input('Enter the code: '))
			except SessionPasswordNeededError:
				client.sign_in(password=input('Password: '))

		me = client.get_me()
		print(me)

		from telethon.tl.functions.messages import GetDialogsRequest
		from telethon.tl.types import InputPeerEmpty

		message_id_prev = 0
		
		get_dialogs = GetDialogsRequest(
			offset_date=None,
			offset_id=0,
			offset_peer=InputPeerEmpty(),
			limit=30,
			hash=0
		)
		
		f = open(file, 'r')

		for line in f:
			line = str(line)
			line = line[:line.find('\n')]
			if len(str(line)) > 10:
				print("read line:", line)
				dialogs = client(get_dialogs)
				print()
				print("------")
				print()
				print("------")
				print()
				print(dialogs.messages[0])	
				print("***")
				print('Message: ', dialogs.messages[0].id)
				if message_id_prev != dialogs.messages[0].id:
					if int(dialogs.messages[0].from_id) ==  758548535: #id=758548535, username='VkUrlBot'
						print("------")
						print(dialogs.messages[0].message)
						print("------")
						print(string_to_vk_id(str(dialogs.messages[0].message)))
						# print(dialogs.messages[0].media)
						print("...sleep")
						time.sleep(4) # Пауза
						print(".........")
						message_str = str(line)
						try:
							result = client(SendMessageRequest(client.get_input_entity('VkUrlBot'), message_str))
						except:
							print("Exception")

				time.sleep(1)

		print("------")
		time.sleep(1)
		print("------")
		dialogs = client(get_dialogs)
		print(dialogs.messages[0].message)


if __name__ == '__main__':  
	try:
		main()
	except KeyboardInterrupt:
		exit()


Я использовал Telegram Portable + левый аккаунт, на случай возможной блокировки. Так же, в приложении удобно наблюдать за ходом выполнения:


данные замазаны для приличия, особого смысла в этом мало.

Бот не всегда выдает правильный результат, может выдать несколько.

Комментарий разработчика по этому поводу:


Можно этот процесс улучшить, например, писать в виртуальный файл и сразу его проверять.
Это можно сделать различными способами: например, создать виртуальный файл в ОЗУ c помощью tempfile.SpooledTemporaryFile, либо, записать в переменную типа String c помощью StringIO.
Это может быть удобно при скачивании фото с того же вк и последующей обработки.

Также, я объединил два примера в один, для большего удобства. Пример не идеален, но рабочий.

Полагаю, каждый его сможет поправить для своих нужд.

код
import requests
import socks
import time
import re
from telethon import TelegramClient, sync
from telethon.tl.functions.messages import SendMessageRequest

api_id = 
api_hash = ''

phone = ''
username = ''


file = "file.txt"
photo = 'photo.jpg'

url = 'http://searchface.ru/request/'

proxies = {
  'http': '46.101.1.221:80',
  'https': '46.101.1.221:80',
}

def request_page(filename): 
	#здесь я убрал обработку исключений, чтобы процесс сразу завершался

	files = {
	    'upl': (filename, open(filename, 'rb')),
	}

	r = requests.post(url, files=files,  proxies=proxies)

	return r


def id_in_string(s):
	result = re.findall(r'/u\d+/', s)
	a = s.find('/u')
	if(len(result) > 0):
		b = str(result).find("/']")
		return 'https://vk.com/id' + str(result)[4:b]
	else:
		return ''


def save_image_links(r, filename):

	try:
		j = r.json()	
		# print(j)		
	except:
		print("no json")
		return False
	print("Save images links:")		

	img_file = open(filename, 'w')

	imagename = 0
	for i in r.json():
		# print(i[1][0][0])
		print(i[0])
		img_file.write(str(i[0]) + '\n')

		for k in i[1]:
			# print(str(k))
			print(str(k[0]))
			img_file.write(str(k[0])+ '\n')

	img_file.close() 
	return True

def string_to_vk_id(s):
	return re.findall(r'(https?://[^\s]+)', s) 

def main(): 

	r = request_page(photo) #отправляем фото
	#если возникнет проблема - выкинет исключение и завершится
	print(r)
	save_image_links(r, file)
	# на всякий случай, сохранякм ссылки в файл


	# Запускаем телеграм клиент
	with TelegramClient(username, api_id, api_hash, proxy=(socks.SOCKS5, '127.0.0.1', 9150)) as client:
		print("Client OK")	


		'''Обратите внимание, что 'some_name'будет использоваться для сохранения вашего сеанса
		(постоянная информация, такая как ключ доступа и другие), 
		как 'some_name.session'на вашем диске. 
		По умолчанию это файл базы данных с использованием Python sqlite3.

		Важно, чтобы библиотека всегда обращалась к одному и тому же файлу сеанса,
		чтобы вам не приходилось повторно отправлять код снова и снова. 
		По умолчанию он создает файл в вашем рабочем каталоге, но абсолютные пути тоже работают.'''


		# Ensure you're authorized
		if not client.is_user_authorized():
			client.send_code_request(phone)
			try:
				client.sign_in(phone, input('Enter the code: '))
			except SessionPasswordNeededError:
				client.sign_in(password=input('Password: '))

		me = client.get_me()
		print(me)

		from telethon.tl.functions.messages import GetDialogsRequest
		from telethon.tl.types import InputPeerEmpty

		message_id_prev = 0
		
		get_dialogs = GetDialogsRequest(
			offset_date=None,
			offset_id=0,
			offset_peer=InputPeerEmpty(),
			limit=30,
			hash=0
		)
		
		for i in r.json():
			# print(i[1][0][0])
			print(i[0])
			for k in i[1]:
				# print(str(k))
				# print(str(k[0]))

				print("link to image: ", str(k[0]))
				dialogs = client(get_dialogs)
				print()
				print("---------")
				print()
				print(dialogs.messages[0])	
				print("---------")
				print('Message: ', dialogs.messages[0].id)
				if message_id_prev != dialogs.messages[0].id:
						if int(dialogs.messages[0].from_id) ==  758548535: #id=758548535, username='VkUrlBot'
							print("---------")
							print(dialogs.messages[0].message)
							print("---------")
							print("vk id list: ",string_to_vk_id(str(dialogs.messages[0].message)))
							# print(dialogs.messages[0].media)
							print("...sleep")
							time.sleep(4) # Пауза
							print(".........")
							message_str = str(k[0])
							try:
								result = client(SendMessageRequest(client.get_input_entity('VkUrlBot'), message_str))
							except:
								print("Exception")

				time.sleep(1)

		print("---------")
		time.sleep(1)
		print("---------")
		dialogs = client(get_dialogs)
		print(dialogs.messages[0].message)

if __name__ == '__main__':  
	try:
		main()
	except KeyboardInterrupt:
		exit()


Зачем мне это нужно? Допустим, у меня есть микроконтроллер ESP-32 с камерой.

Например, такой


Если настроить отправку запроса на распознавание лица на внешний сервер, например, по тревоге, можно получить продвинутую систему, не нагружая ресурсы мк. Для ESP есть библиотеки распознавания лица в кадре, соответственно, можно выделить подходящий кадр для отправки.

Disclaimer
Автор не является сторонником глобальной слежки, но это, реальность сегодняшнего дня. Я долго думал, стоит публиковать эту инструкцию или нет, но «Ящик Пандоры» уже открыт. Подобные системы продолжат появляться.

Автор не несёт ответственности за действия третих лиц.
Пожалуйста, не используйте систему во вред людям.
Рекомендую воздержаться от политики в комментариях.
Проект полностью Just for fun.

Отдельное спасибо создателям вышеупомянутого сериала и
Saransh Kejriwa
Также, создателям SearchFace и VkUrlBot.

Картинка для размышления:


Кадр из сериала Person Of Interest
Only registered users can participate in poll. Log in, please.
Писать цикл статей? В планах анализ видеопотока и поиск по лицам
96.84% Да153
3.16% Нет5
158 users voted. 25 users abstained.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+12
Comments24

Articles

Change theme settings