Spaces:
No application file
No application file
File size: 10,468 Bytes
399b056 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
import gradio as gr
import datetime
import json
import re
import pycountry
from curl_cffi import requests
from lxml import html
# --- كلاس TikTokUser (يبقى كما هو) ---
class TikTokUser:
def __init__(self, data) -> None:
user = data.get("user", {})
stats = data.get("stats", {})
self.username = user.get("uniqueId", "N/A")
self.name = user.get("nickname", "N/A")
self.avatar = user.get("avatarMedium", "")
self.bio = user.get("signature", "لا توجد سيرة ذاتية.")
self.created = user.get("createTime", None)
self.verified = user.get("verified", False)
self.private = user.get("privateAccount", False)
self.country_code = user.get("region", "N/A")
self.language_code = user.get("language", "N/A")
self.followers = stats.get("followerCount", 0)
self.following = stats.get("followingCount", 0)
self.hearts = stats.get("heart", 0)
self.video_count = stats.get("videoCount", 0)
self.friends = stats.get("friendCount", 0)
if self.created:
try:
self.created = datetime.datetime.fromtimestamp(self.created).strftime('%Y-%m-%d %H:%M:%S')
except (TypeError, ValueError):
self.created = "غير معروف"
else:
self.created = "غير معروف"
self.country = "غير معروف"
if self.country_code != "N/A":
try:
self.country = pycountry.countries.get(alpha_2=self.country_code.upper()).name
except AttributeError:
self.country = f"رمز ({self.country_code})"
self.language = "غير معروف"
if self.language_code != "N/A":
try:
self.language = pycountry.languages.get(alpha_2=self.language_code.lower()).name
except AttributeError:
self.language = f"رمز ({self.language_code})"
if bio_link := user.get("bioLink", {}):
if link_url := bio_link.get("link"):
self.bio += f"\n\n🔗 رابط السيرة الذاتية: {link_url}"
self.followers_formatted = f"{self.followers:,}"
self.following_formatted = f"{self.following:,}"
self.hearts_formatted = f"{self.hearts:,}"
self.video_count_formatted = f"{self.video_count:,}"
self.friends_formatted = f"{self.friends:,}"
# --- دالة get_user_info (تبقى كما هي، مع تعديل بسيط للتعامل مع الأخطاء لـ Gradio) ---
def get_user_info_from_tiktok(username):
username = re.sub(r"^.*@", "", username).strip()
if not username:
return "خطأ: اسم المستخدم لا يمكن أن يكون فارغاً."
url = f"https://www.tiktok.com/@{username}"
print(f"محاولة جلب البيانات من: {url}")
try:
r = requests.get(url, impersonate="chrome", timeout=15)
r.raise_for_status()
tree = html.fromstring(r.text, parser=html.HTMLParser(encoding="utf8"))
script_tag = tree.xpath('//script[@id="__UNIVERSAL_DATA_FOR_REHYDRATION__"]')
if not script_tag:
return ("خطأ: لم يتم العثور على وسم البيانات في الصفحة. "
"قد يكون هيكل الصفحة قد تغير، أو تم حظر الطلب.")
data = json.loads(script_tag[0].text)
user_info_data = data.get("__DEFAULT_SCOPE__", {})\
.get("webapp.user-detail", {})\
.get("userInfo")
if not user_info_data:
return (f"خطأ: لم يتم العثور على معلومات لمستخدم تيك توك: '{username}'. "
"تأكد من صحة اسم المستخدم وأنه حساب عام.")
user = TikTokUser(user_info_data)
# تنسيق المخرجات لـ Gradio
output_html = f"""
<div style="direction: rtl; text-align: right; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; padding: 20px; border-radius: 8px; background-color: #f9f9f9; box-shadow: 0 4px 15px rgba(0,0,0,0.1);">
<div style="display: flex; align-items: center; gap: 20px; margin-bottom: 20px; flex-wrap: wrap; justify-content: flex-end;">
<img src="{user.avatar if user.avatar else 'https://via.placeholder.com/120/CCCCCC/000000?text=لا+صورة'}" alt="صورة الملف الشخصي" style="width: 120px; height: 120px; border-radius: 50%; object-fit: cover; border: 3px solid #FE2C55; box-shadow: 0 2px 8px rgba(0,0,0,0.15);">
<div style="text-align: right; flex-grow: 1;">
<h2 style="margin: 0; color: #222; font-size: 2em;">
{user.name}
{"<span style='color: #4CAF50; font-weight: bold; margin-right: 8px;'>✅ (موثق)</span>" if user.verified else ""}
{"<span style='color: #FFC107; font-weight: bold; margin-right: 8px;'>🔒 (خاص)</span>" if user.private else ""}
</h2>
<p style="margin: 5px 0 0 0; color: #555; font-size: 1.1em;">{user.username}</p>
</div>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 15px; margin-top: 20px;">
<div style="background-color: #fff; padding: 15px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); text-align: center;">
<strong style="display: block; font-size: 1.6em; color: #FE2C55; margin-bottom: 5px;">{user.followers_formatted}</strong>
<span style="font-size: 0.9em; color: #777;">متابع</span>
</div>
<div style="background-color: #fff; padding: 15px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); text-align: center;">
<strong style="display: block; font-size: 1.6em; color: #FE2C55; margin-bottom: 5px;">{user.following_formatted}</strong>
<span style="font-size: 0.9em; color: #777;">يتابع</span>
</div>
<div style="background-color: #fff; padding: 15px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); text-align: center;">
<strong style="display: block; font-size: 1.6em; color: #FE2C55; margin-bottom: 5px;">{user.hearts_formatted}</strong>
<span style="font-size: 0.9em; color: #777;">إعجاب</span>
</div>
<div style="background-color: #fff; padding: 15px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); text-align: center;">
<strong style="display: block; font-size: 1.6em; color: #FE2C55; margin-bottom: 5px;">{user.video_count_formatted}</strong>
<span style="font-size: 0.9em; color: #777;">فيديو</span>
</div>
</div>
<div style="margin-top: 25px; padding: 15px; background-color: #eef; border-radius: 8px; text-align: right; border-top: 1px solid #e0e0e0;">
<h3 style="margin-top: 0; color: #444; font-size: 1.3em; border-bottom: 2px solid #FE2C55; padding-bottom: 5px; display: inline-block;">السيرة الذاتية:</h3>
<p style="margin: 10px 0; line-height: 1.6; color: #444; white-space: pre-wrap; word-wrap: break-word;">{user.bio}</p>
</div>
<div style="margin-top: 25px; padding: 15px; background-color: #fdfdfd; border-radius: 8px; text-align: right; border-top: 1px solid #e0e0e0;">
<h3 style="margin-top: 0; color: #444; font-size: 1.3em; border-bottom: 2px solid #FE2C55; padding-bottom: 5px; display: inline-block;">معلومات إضافية:</h3>
<p style="margin: 8px 0; line-height: 1.5; color: #555;"><strong>الدولة:</strong> {user.country}</p>
<p style="margin: 8px 0; line-height: 1.5; color: #555;"><strong>اللغة:</strong> {user.language}</p>
<p style="margin: 8px 0; line-height: 1.5; color: #555;"><strong>تاريخ الإنشاء:</strong> {user.created}</p>
</div>
<p style="font-size: 0.9em; color: #a00; margin-top: 30px; padding-top: 15px; border-top: 1px dashed #f00; text-align: center; font-weight: bold;">
⚠️ ملاحظة هامة: هذا التطبيق يقوم بمحاولة استخلاص البيانات مباشرة من صفحة تيك توك.
<span style="display: block; margin-top: 5px; font-size: 0.8em; color: #c00;">هذه الطريقة غير رسمية وقد تتوقف عن العمل في أي وقت بسبب تغييرات تيك توك.</span>
<span style="display: block; margin-top: 5px; font-size: 0.8em; color: #c00;">كما أنها قد تتعارض مع شروط خدمة تيك توك، وتؤدي إلى حظر عنوان IP الخاص بك.</span>
<span style="display: block; margin-top: 5px; font-size: 0.8em; color: #c00;">استخدم على مسؤوليتك الخاصة ولأغراض تعليمية فقط.</span>
</p>
</div>
"""
return output_html
except Exception as e:
return f"حدث خطأ: {str(e)}. يرجى المحاولة مرة أخرى باسم مستخدم صحيح وتأكد من أن الحساب عام."
# --- واجهة Gradio ---
iface = gr.Interface(
fn=get_user_info_from_tiktok, # الدالة التي ستقوم بالعمل
inputs=gr.Textbox(label="أدخل اسم مستخدم تيك توك (بدون @)", placeholder="مثال: cristiano"), # مدخل نصي
outputs=gr.HTML(label="معلومات مستخدم تيك توك"), # مخرج HTML لعرض المعلومات المنسقة
title="جالب معلومات مستخدم تيك توك (تجريبي)",
description="قم بإدخال اسم مستخدم تيك توك لمحاولة جلب معلوماته. هذه الطريقة تعتمد على الاستخلاص وقد تفشل.",
theme="soft", # يمكنك تغيير الثيم
allow_flagging="never" # لا يسمح بوضع علامات على النتائج
)
if __name__ == "__main__":
iface.launch()
# local_host=True
# share=True # لإنشاء رابط مشاركة مؤقت إذا كنت تختبر محلياً |