najimq59 commited on
Commit
399b056
·
verified ·
1 Parent(s): 093bc48

Create app.py

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