非官方的 Hinge API Python SDK。通过编程方式与 Hinge 交互,获取推荐、发送消息、下载媒体以及自动化交互。
要使用此 SDK,您需要有效的认证凭据。您可以将凭据存储在 .env 文件中,或直接传递给客户端。
BEARER_TOKEN:您的 JWT 认证令牌(例如 L2euNWN...)。SESSION_ID:当前会话 UUID。USER_ID:您的用户/玩家 ID。如果您想使用现有 Hinge 账户,同时避免因新设备登录而触发风险标记,您必须从应用的网络流量中提取这些值。
注意: 您只需一次操作即可获取正确变量。捕获后,后续会话可使用短信登录方法。
prod-api.hingeaws.net 或类似 Hinge 端点的 HTTPS 请求。authorization(Bearer 令牌)x-session-idx-device-idx-install-idUser ID(通常在响应正文中作为 subjectId 或类似字段出现)您可以通过 SDK 通过短信登录生成新凭据。这会执行全新的登录流程。
from hingesdk.client import HingeClient
# 这些 ID 必须与您账户关联的实际值匹配。
# 不能使用随机 UUID;它们必须与账户注册的设备一致。
client = HingeClient.login_with_sms(
phone_number="+15551234567",
device_id="your_device_id_uuid",
install_id="your_install_id_uuid"
)
print(f"BEARER_TOKEN={client.auth_token}")
print(f"SESSION_ID={client.session_id}")
print(f"USER_ID={client.user_id}")
克隆仓库并安装包:
git clone https://github.com/reedgraff/hingesdk
cd hingesdk
pip install .
以下是一个最小示例,用于验证身份并获取用户推荐。
import os
from hingesdk.api import HingeAPIClient
# 使用凭据初始化
client = HingeAPIClient(
auth_token=os.getenv("BEARER_TOKEN"),
session_id=os.getenv("SESSION_ID"),
user_id=os.getenv("USER_ID")
)
# 获取推荐
recs = client.get_recommendations()
print(f"成功获取推荐请求。")
from hingesdk.client import HingeAPIClient
auth_token = 'your_auth_token'
user_id = 'your_user_id'
client = HingeAPIClient(auth_token=auth_token, user_id=user_id)
response = client.send_message(
subject_id='receiver_id',
message='你好,这是一条测试消息!'
)
print(response)
from hingesdk.api import HingeAPIClient
client = HingeAPIClient(auth_token=auth_token, user_id=user_id)
recommendations = client.get_recommendations()
print(recommendations)
from hingesdk.tools import HingeTools
from hingesdk.api import HingeAPIClient
from hingesdk.media import HingeMediaClient
api_client = HingeAPIClient(auth_token=auth_token, user_id=user_id)
media_client = HingeMediaClient(auth_token=auth_token)
tools = HingeTools(api_client, media_client)
tools.download_recommendation_content(output_path='path_to_save_images')
import os
import json
from hingesdk.tools import HingeTools
from hingesdk.api import HingeAPIClient
from hingesdk.media import HingeMediaClient
auth_token = os.getenv("BEARER_TOKEN")
session_id = os.getenv("SESSION_ID")
user_id = os.getenv("USER_ID")
api_client = HingeAPIClient(
auth_token=auth_token,
session_id=session_id,
user_id=user_id
)
media_client = HingeMediaClient(auth_token=auth_token)
tools = HingeTools(api_client, media_client)
# 示例:获取用户信息
tools.create_profile_json(
source=ProfileSource.STANDOUTS,
output_file="standouts.json"
)
# 示例:点赞用户
with open("standouts.json", "r") as f:
profiles = json.load(f)
personData = profiles["35582109789..."]
# 点赞用户的问题
questionIDToLike = "5c4a346828fd883a24..."
response = api_client.like_profile(
subject_id=personData["interaction_data"]["subject_id"],
rating_token=personData["interaction_data"]["rating_token"],
prompt={
"questionId": questionIDToLike,
"response": "我在迈阿密待了一年,还没去过呢 (╥﹏╥)"
}
)
print(response)
# 点赞用户的照片
# photoIDToLike = "2c6411ac-66e4-4194-..."
# response = api_client.like_profile(
# subject_id=personData["interaction_data"]["subject_id"],
# rating_token=personData["interaction_data"]["rating_token"],
# photo={
# "contentId": photoIDToLike,
# "comment": "那么有多少人评论说来过这里呢?"
# }
# )
# print(response)
此示例演示如何抓取推荐并根据特定条件(例如顶尖大学)过滤个人资料。
def find_top_50_university_students(json_file_path, age_min=18, age_max=24):
# 用于存储匹配个人资料的列表
matching_profiles = []
# 前50所大学的模式字典(不区分大小写)
top_50_patterns = {
"Princeton University": [r"princeton", r"\bpu\b", r"princeton\s+university"],
"Massachusetts Institute of Technology": [r"mit", r"massachusetts\s+institute\s+of\s+technology", r"mass\s+tech"],
"Harvard University": [r"harvard", r"\bhu\b", r"harvard\s+university"],
"Stanford University": [r"stanford", r"\bsu\b", r"stanford\s+university"],
"Yale University": [r"yale", r"\byu\b", r"yale\s+university"],
"California Institute of Technology": [r"caltech", r"california\s+institute\s+of\s+technology"],
"Duke University": [r"duke", r"\bdu\b", r"duke\s+university"],
"Johns Hopkins University": [r"johns\s+hopkins", r"\bjhu\b", r"hopkins"],
"Northwestern University": [r"northwestern", r"\bnu\b", r"northwestern\s+university"],
"University of Pennsylvania": [r"upenn", r"penn", r"university\s+of\s+pennsylvania"],
"Cornell University": [r"cornell", r"\bcu\b", r"cornell\s+university"],
"University of Chicago": [r"uchicago", r"university\s+of\s+chicago", r"u\s+chicago"],
"Brown University": [r"brown", r"\bbu\b", r"brown\s+university"],
"Columbia University": [r"columbia", r"\bcu\b", r"columbia\s+university"],
"Dartmouth College": [r"dartmouth", r"\bdc\b", r"dartmouth\s+college"],
"University of California--Los Angeles": [r"ucla", r"university\s+of\s+california\s+los\s+angeles", r"uc\s+la"],
"University of California, Berkeley": [r"uc\s+berkeley", r"berkeley", r"university\s+of\s+california\s+berkeley"],
"Rice University": [r"rice", r"\bru\b", r"rice\s+university"],
"University of Notre Dame": [r"notre\s+dame", r"\bnd\b", r"university\s+of\s+notre\s+dame"],
"Vanderbilt University": [r"vanderbilt", r"\bvu\b", r"vandy"],
"Carnegie Mellon University": [r"carnegie\s+mellon", r"\bcmu\b", r"cmu"],
"University of Michigan--Ann Arbor": [r"umich", r"michigan", r"university\s+of\s+michigan"],
"Washington University in St. Louis": [r"washu", r"washington\s+university", r"wu\s+stl"],
"Emory University": [r"emory", r"\beu\b", r"emory\s+university"],
"Georgetown University": [r"georgetown", r"\bgu\b", r"georgetown\s+university"],
"University of Virginia": [r"uva", r"virginia", r"university\s+of\s+virginia"],
"University of North Carolina--Chapel Hill": [r"unc", r"chapel\s+hill", r"university\s+of\s+north\s+carolina"],
"University of Southern California": [r"usc", r"southern\s+california", r"university\s+of\s+southern\s+california"],
"University of California, San Diego": [r"ucsd", r"uc\s+san\s+diego", r"university\s+of\s+california\s+san\s+diego"],
"New York University": [r"nyu", r"new\s+york\s+university"],
"University of Florida": [r"uf", r"florida", r"university\s+of\s+florida"],
"The University of Texas--Austin": [r"ut\s+austin", r"utexas", r"university\s+of\s+texas"],
"Georgia Institute of Technology": [r"gatech", r"georgia\s+tech", r"georgia\s+institute\s+of\s+technology"],
"University of California, Davis": [r"uc\s+davis", r"ucd", r"university\s+of\s+california\s+davis"],
"University of California--Irvine": [r"uci", r"uc\s+irvine", r"university\s+of\s+california\s+irvine"],
"University of Illinois Urbana-Champaign": [r"uiuc", r"illinois", r"university\s+of\s+illinois"],
"Boston College": [r"bc", r"boston\s+college"],
"Tufts University": [r"tufts", r"\btu\b", r"tufts\s+university"],
"University of California, Santa Barbara": [r"ucsb", r"uc\s+santa\s+barbara", r"university\s+of\s+california\s+santa\s+barbara"],
"University of Wisconsin--Madison": [r"uw\s+madison", r"wisconsin", r"university\s+of\s+wisconsin"],
"Boston University": [r"bu", r"boston\s+university"],
"The Ohio State University": [r"ohio\s+state", r"osu", r"the\s+ohio\s+state\s+university"],
"Rutgers University--New Brunswick": [r"rutgers", r"ru", r"rutgers\s+university"],
"University of Maryland, College Park": [r"umd", r"maryland", r"university\s+of\s+maryland"],
"University of Rochester": [r"rochester", r"\bur\b", r"university\s+of\s+rochester"],
"Lehigh University": [r"lehigh", r"\blu\b", r"lehigh\s+university"],
"Purdue University--Main Campus": [r"purdue", r"\bpu\b", r"purdue\s+university"],
"University of Georgia": [r"uga", r"georgia", r"university\s+of\s+georgia"],
"University of Washington": [r"uw", r"washington", r"university\s+of\s+washington"],
"Wake Forest University": [r"wake\s+forest", r"\bwfu\b", r"wake"],
"Case Western Reserve University": [r"case\s+western", r"\bcwru\b", r"case"],
"Texas A&M University": [r"texas\s+a&m", r"tamu", r"a&m"],
"Virginia Tech": [r"virginia\s+tech", r"vt", r"vtech"],
"Florida State University": [r"fsu", r"florida\s+state", r"florida\s+state\s+university"],
"University of Miami": [r'umiami', r'\bum\b', r'university\s+of\s+miami']
}
try:
# 读取 JSON 文件
with open(json_file_path, 'r') as file:
data = json.load(file)
# 遍历每个用户个人资料
for user_id, profile in data.items():
profile_info = profile.get('profile_info', {})
# 检查年龄范围(默认可配置的最小/最大年龄)
age = profile_info.get('age', 0)
if not (age_min <= age <= age_max):
continue
# 获取教育列表(如果不存在则默认为空列表)
educations = profile_info.get('educations', [])
# 检查每个教育字符串是否包含前50所大学引用
found_match = False
matched_university = None
for edu in educations:
if not isinstance(edu, str):
continue
# 转换为小写进行不区分大小写的匹配
edu_lower = edu.lower()
# 检查每个大学的模式
for university, patterns in top_50_patterns.items():
for pattern in patterns:
if re.search(pattern, edu_lower):
found_match = True
matched_university = university
break
if found_match:
break
if found_match:
break
# 如果找到匹配项,将个人资料添加到结果中
if found_match:
# 获取图片列表(如果不存在则默认为空列表)
images = profile.get('images', [])
image_urls = [img.get('url', '') for img in images if img.get('url')]
matching_profiles.append({
'user_id': user_id,
'age': age,
'firstName': profile_info.get('firstName', ''),
'educations': educations,
'matched_university': matched_university,
'location': profile_info.get('location', {}).get('name', ''),
'image_urls': image_urls
})
return matching_profiles
except FileNotFoundError:
print(f"错误:未找到文件 {json_file_path}。")
return []
except json.JSONDecodeError:
print(f"错误:{json_file_path} 中的 JSON 格式无效。")
return []
except Exception as e:
print(f"意外错误:{str(e)}")
return []
def main():
# 使用您的认证令牌初始化客户端
auth_token = os.getenv("BEARER_TOKEN")
session_id = os.getenv("SESSION_ID")
user_id = os.getenv("USER_ID")
api_client = HingeAPIClient(
auth_token=auth_token,
session_id=session_id,
user_id=user_id
)
media_client = HingeMediaClient(auth_token=auth_token)
tools = HingeTools(api_client, media_client)
# 示例:批量抓取
# tools.scrape_recommendations_multiple(
# iterations=40, # 40 似乎是在需要跳过用户之前的最大值...
# min_sleep = 20,
# max_sleep = 60,
# )
json_file_path = 'all_recommendations.json'
csv_file_path = 'university_matches.csv'
results = find_top_50_university_students(json_file_path)
print(f"找到 {len(results)} 个匹配的个人资料。")
# 定义 CSV 表头,每个图片一个独立列
headers = ['timestamp', 'user_id', 'name', 'age', 'location', 'education',
'image1', 'image2', 'image3', 'image4', 'image5', 'image6']
# 以追加模式打开 CSV 文件
with open(csv_file_path, 'a', newline='', encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=headers)
# 如果文件为空则写入表头
if csvfile.tell() == 0:
writer.writeheader()
# 将每个个人资料作为一行写入
for profile in results:
# 创建行字典
row_data = {
'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'user_id': profile['user_id'],
'name': profile['firstName'],
'age': profile['age'],
'location': profile['location'],
'education': ', '.join(profile['educations'])
}
# 将图片 URL 添加到单独的列
for i in range(6):
image_key = f'image{i+1}'
if profile['image_urls'] and i < len(profile['image_urls']):
row_data[image_key] = profile['image_urls'][i]
else:
row_data[image_key] = ''
writer.writerow(row_data)
print(f"结果已追加到 {csv_file_path}")
SDK 被组织为逻辑模块以分离关注点。
hingesdk/
├── __init__.py
├── client.py # 基础 HingeClient:处理 HTTP 请求、标头和认证
├── api.py # HingeAPIClient:核心 API 方法(点赞、消息、获取推荐)
├── media.py # HingeMediaClient:下载/处理图片的辅助工具
├── tools.py # HingeTools:高级工作流(批量抓取、导出)
├── models.py # Pydantic 模型和数据结构(如适用)
├── exceptions.py # 自定义异常类(HingeAPIError、HingeAuthError)
└── assets/ # 静态资源(例如提示定义)
本项目使用 MIT 许可证授权。