Update app.py
Browse files
app.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1 |
import streamlit as st
|
2 |
-
from streamlit_lottie import st_lottie
|
3 |
from streamlit_option_menu import option_menu
|
4 |
import requests
|
5 |
import pandas as pd
|
@@ -17,9 +16,6 @@ import dns.resolver
|
|
17 |
from urllib.parse import urlparse
|
18 |
import json
|
19 |
import numpy as np
|
20 |
-
from selenium import webdriver
|
21 |
-
from selenium.webdriver.chrome.options import Options
|
22 |
-
from webdriver_manager.chrome import ChromeDriverManager
|
23 |
from PIL import Image
|
24 |
import io
|
25 |
import time
|
@@ -37,13 +33,11 @@ st.set_page_config(
|
|
37 |
# تحسين التصميم باستخدام CSS
|
38 |
st.markdown("""
|
39 |
<style>
|
40 |
-
/* تخصيص الخلفية والألوان */
|
41 |
.main {
|
42 |
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
43 |
padding: 20px;
|
44 |
}
|
45 |
|
46 |
-
/* تنسيق البطاقات */
|
47 |
.metric-card {
|
48 |
background: white;
|
49 |
border-radius: 15px;
|
@@ -55,7 +49,6 @@ st.markdown("""
|
|
55 |
transform: translateY(-5px);
|
56 |
}
|
57 |
|
58 |
-
/* تنسيق الأزرار */
|
59 |
.stButton>button {
|
60 |
background: linear-gradient(45deg, #2196F3, #21CBF3);
|
61 |
color: white;
|
@@ -70,20 +63,17 @@ st.markdown("""
|
|
70 |
box-shadow: 0 6px 20px rgba(0,0,0,0.25);
|
71 |
}
|
72 |
|
73 |
-
/* تنسيق العناوين */
|
74 |
h1, h2, h3 {
|
75 |
color: #1E3D59;
|
76 |
font-family: 'Tajawal', sans-serif;
|
77 |
}
|
78 |
|
79 |
-
/* تنسيق المدخلات */
|
80 |
.stTextInput>div>div>input {
|
81 |
border-radius: 10px;
|
82 |
border: 2px solid #E0E0E0;
|
83 |
padding: 10px;
|
84 |
}
|
85 |
|
86 |
-
/* تنسيق التوسيعات */
|
87 |
.streamlit-expanderHeader {
|
88 |
background-color: white;
|
89 |
border-radius: 10px;
|
@@ -92,21 +82,6 @@ st.markdown("""
|
|
92 |
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700&display=swap" rel="stylesheet">
|
93 |
""", unsafe_allow_html=True)
|
94 |
|
95 |
-
# تحسين تحميل الرسوم المتحركة
|
96 |
-
def load_lottieurl(url):
|
97 |
-
try:
|
98 |
-
r = requests.get(url)
|
99 |
-
if r.status_code == 200:
|
100 |
-
return r.json()
|
101 |
-
except:
|
102 |
-
pass
|
103 |
-
return None
|
104 |
-
|
105 |
-
# تحميل الرسوم المتحركة المختلفة
|
106 |
-
lottie_analyzing = load_lottieurl("https://assets5.lottiefiles.com/packages/lf20_qpwbqki6.json")
|
107 |
-
lottie_success = load_lottieurl("https://assets9.lottiefiles.com/packages/lf20_jbrw3hcz.json")
|
108 |
-
lottie_error = load_lottieurl("https://assets8.lottiefiles.com/packages/lf20_my7r4w9m.json")
|
109 |
-
|
110 |
class WebsiteAnalyzer:
|
111 |
def __init__(self):
|
112 |
self.headers = {
|
@@ -121,15 +96,10 @@ class WebsiteAnalyzer:
|
|
121 |
load_time = time.time() - start_time
|
122 |
page_size = len(response.content) / 1024
|
123 |
|
124 |
-
# تحليل محسن للأداء
|
125 |
performance_metrics = {
|
126 |
"load_time": round(load_time, 2),
|
127 |
"page_size": round(page_size, 2),
|
128 |
"status_code": response.status_code,
|
129 |
-
"تقدير السرعة": self._estimate_speed(load_time),
|
130 |
-
"عدد الزيارات التقريبي": self._estimate_traffic(url),
|
131 |
-
"ترتيب الموقع على جوجل": self._estimate_google_rank(url),
|
132 |
-
"السعر التقريبي للموقع": self._estimate_website_value(url),
|
133 |
"تقييم الأداء": self._calculate_performance_score(load_time, page_size),
|
134 |
"توصيات تحسين الأداء": self._get_performance_recommendations(load_time, page_size)
|
135 |
}
|
@@ -160,15 +130,13 @@ class WebsiteAnalyzer:
|
|
160 |
response = await client.get(url)
|
161 |
soup = BeautifulSoup(response.text, 'html.parser')
|
162 |
|
163 |
-
# تحليل SEO محسن
|
164 |
seo_analysis = {
|
165 |
"العنوان": self._analyze_title(soup),
|
166 |
"الوصف": self._analyze_description(soup),
|
167 |
-
"الكلمات المفتاحية": self.
|
168 |
"هيكل العناوين": self._analyze_headings(soup),
|
169 |
"الروابط": self._analyze_links(soup),
|
170 |
-
"
|
171 |
-
"تقييم SEO الإجمالي": self._calculate_seo_score(soup)
|
172 |
}
|
173 |
|
174 |
return seo_analysis
|
@@ -180,34 +148,70 @@ class WebsiteAnalyzer:
|
|
180 |
return {
|
181 |
"النص": title,
|
182 |
"الطول": len(title) if title else 0,
|
183 |
-
"التقييم": "ممتاز" if title and 30 <= len(title) <= 60 else "يحتاج تحسين"
|
184 |
-
"التوصيات": self._get_title_recommendations(title)
|
185 |
}
|
186 |
|
187 |
-
def
|
188 |
-
|
189 |
-
if
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
|
197 |
def analyze_security(self, url):
|
198 |
try:
|
199 |
domain = urlparse(url).netloc
|
200 |
security_analysis = {
|
201 |
-
"شهادة SSL": self.
|
202 |
-
"سجلات DNS": self.
|
203 |
-
"تقييم
|
204 |
-
"توصيات الأمان": self._get_security_recommendations(url)
|
205 |
}
|
206 |
return security_analysis
|
207 |
except Exception as e:
|
208 |
return {"error": f"خطأ في تحليل الأمان: {str(e)}"}
|
209 |
|
210 |
-
def
|
211 |
try:
|
212 |
context = ssl.create_default_context()
|
213 |
with socket.create_connection((urlparse(url).netloc, 443)) as sock:
|
@@ -215,41 +219,39 @@ class WebsiteAnalyzer:
|
|
215 |
cert = ssock.getpeercert()
|
216 |
return {
|
217 |
"الحالة": "آمن ✅",
|
218 |
-
"تاريخ الانتهاء": cert['notAfter']
|
219 |
-
"مُصدر الشهادة": cert['issuer'][0][0][1]
|
220 |
}
|
221 |
except:
|
222 |
-
return {"الحالة": "غير آمن ❌"
|
223 |
|
224 |
-
def
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
return
|
243 |
|
244 |
def main():
|
245 |
st.title("🔍 محلل المواقع المتقدم")
|
246 |
|
247 |
-
# القائمة الجانبية المحسنة
|
248 |
with st.sidebar:
|
249 |
selected = option_menu(
|
250 |
menu_title="القائمة الرئيسية",
|
251 |
-
options=["تحليل جديد", "التقارير السابقة", "الإحصائيات"
|
252 |
-
icons=["search", "file-text", "graph-up"
|
253 |
menu_icon="cast",
|
254 |
styles={
|
255 |
"container": {"padding": "15px"},
|
@@ -267,8 +269,6 @@ def main():
|
|
267 |
|
268 |
if analyze_button:
|
269 |
with st.spinner("جاري التحليل... ⏳"):
|
270 |
-
st_lottie(lottie_analyzing, height=200)
|
271 |
-
|
272 |
analyzer = WebsiteAnalyzer()
|
273 |
|
274 |
# تحليل متزامن
|
@@ -279,284 +279,34 @@ def main():
|
|
279 |
seo_data = loop.run_until_complete(analyzer.analyze_seo(url))
|
280 |
security_data = analyzer.analyze_security(url)
|
281 |
|
282 |
-
# عرض النتائج بشكل جذاب
|
283 |
st.success("✨ تم اكتمال التحليل بنجاح!")
|
284 |
|
285 |
-
#
|
286 |
-
|
287 |
-
with col1:
|
288 |
-
st.metric(
|
289 |
-
"⚡ سرعة التحميل",
|
290 |
-
f"{performance_data.get('load_time', 'N/A')}s",
|
291 |
-
delta="-0.2s"
|
292 |
-
)
|
293 |
-
with col2:
|
294 |
-
st.metric(
|
295 |
-
"👥 الزيارات الشهرية",
|
296 |
-
f"{performance_data.get('عدد الزيارات التقريبي', 'N/A'):,}",
|
297 |
-
delta="↑ 12%"
|
298 |
-
)
|
299 |
-
with col3:
|
300 |
-
st.metric(
|
301 |
-
"🎯 ترتيب جوجل",
|
302 |
-
f"#{performance_data.get('ترتيب الموقع على جوجل', 'N/A')}",
|
303 |
-
delta="↑ 5"
|
304 |
-
)
|
305 |
-
with col4:
|
306 |
-
st.metric(
|
307 |
-
"💰 القيمة التقديرية",
|
308 |
-
f"${performance_data.get('السعر التقريبي للموقع', 'N/A'):,}",
|
309 |
-
delta="↑ $1,000"
|
310 |
-
)
|
311 |
-
|
312 |
-
# تقارير تفصيلية
|
313 |
-
tabs = st.tabs(["📊 الأداء", "🎯 SEO", "🔒 الأمان", "📈 التقرير الشامل"])
|
314 |
|
315 |
with tabs[0]:
|
316 |
-
st.subheader("تحليل الأداء
|
317 |
-
|
318 |
-
# رسم بياني للأداء
|
319 |
-
performance_fig = go.Figure()
|
320 |
-
|
321 |
-
# إضافة مؤشر سرعة التحميل
|
322 |
-
performance_fig.add_trace(go.Indicator(
|
323 |
-
mode = "gauge+number",
|
324 |
-
value = performance_data.get('تقييم الأداء', 0),
|
325 |
-
title = {'text': "تقييم الأداء العام"},
|
326 |
-
gauge = {
|
327 |
-
'axis': {'range': [0, 100]},
|
328 |
-
'steps': [
|
329 |
-
{'range': [0, 50], 'color': "lightgray"},
|
330 |
-
{'range': [50, 75], 'color': "gray"},
|
331 |
-
{'range': [75, 100], 'color': "darkblue"}
|
332 |
-
],
|
333 |
-
'bar': {'color': "royalblue"}
|
334 |
-
}
|
335 |
-
))
|
336 |
-
|
337 |
-
st.plotly_chart(performance_fig, use_container_width=True)
|
338 |
-
|
339 |
-
# جدول تفصيلي للأداء
|
340 |
-
st.markdown("""
|
341 |
-
<div class="metric-card">
|
342 |
-
<h3>📊 تفاصيل الأداء</h3>
|
343 |
-
""", unsafe_allow_html=True)
|
344 |
-
|
345 |
-
perf_cols = st.columns(2)
|
346 |
-
with perf_cols[0]:
|
347 |
-
st.markdown(f"""
|
348 |
-
- ⚡ زمن التحميل: {performance_data.get('load_time')}s
|
349 |
-
- 📦 حجم الصفحة: {performance_data.get('page_size')} KB
|
350 |
-
- 🎯 تقدير السرعة: {performance_data.get('تقدير السرعة')}
|
351 |
-
""")
|
352 |
-
|
353 |
-
with perf_cols[1]:
|
354 |
-
st.markdown(f"""
|
355 |
-
- 👥 الزيارات الشهرية: {performance_data.get('عدد الزيارات التقريبي'):,}
|
356 |
-
- 🌐 حالة الموقع: {performance_data.get('status_code')}
|
357 |
-
- 💰 القيمة التقديرية: ${performance_data.get('السعر التقريبي للموقع'):,}
|
358 |
-
""")
|
359 |
|
360 |
with tabs[1]:
|
361 |
st.subheader("تحليل SEO")
|
362 |
-
|
363 |
-
# مخطط رادار لتقييم SEO
|
364 |
-
seo_scores = {
|
365 |
-
'العنوان': seo_data.get('العنوان', {}).get('التقييم', 0),
|
366 |
-
'الوصف': seo_data.get('الوصف', {}).get('التقييم', 0),
|
367 |
-
'الكلمات المفتاحية': seo_data.get('الكلمات المفتاحية', {}).get('التقييم', 0),
|
368 |
-
'الروابط': seo_data.get('الروابط', {}).get('التقييم', 0),
|
369 |
-
'الصور': seo_data.get('الصور', {}).get('التقييم', 0)
|
370 |
-
}
|
371 |
-
|
372 |
-
seo_fig = go.Figure(data=go.Scatterpolar(
|
373 |
-
r=list(seo_scores.values()),
|
374 |
-
theta=list(seo_scores.keys()),
|
375 |
-
fill='toself'
|
376 |
-
))
|
377 |
-
|
378 |
-
seo_fig.update_layout(
|
379 |
-
polar=dict(
|
380 |
-
radialaxis=dict(visible=True, range=[0, 100])
|
381 |
-
),
|
382 |
-
showlegend=False
|
383 |
-
)
|
384 |
-
|
385 |
-
st.plotly_chart(seo_fig, use_container_width=True)
|
386 |
-
|
387 |
-
# بطاقات تحليل SEO
|
388 |
-
seo_cols = st.columns(3)
|
389 |
-
|
390 |
-
with seo_cols[0]:
|
391 |
-
st.markdown("""
|
392 |
-
<div class="metric-card">
|
393 |
-
<h4>🎯 تحليل العنوان</h4>
|
394 |
-
""", unsafe_allow_html=True)
|
395 |
-
st.write(seo_data.get('العنوان', {}))
|
396 |
-
|
397 |
-
with seo_cols[1]:
|
398 |
-
st.markdown("""
|
399 |
-
<div class="metric-card">
|
400 |
-
<h4>📝 تحليل الوصف</h4>
|
401 |
-
""", unsafe_allow_html=True)
|
402 |
-
st.write(seo_data.get('الوصف', {}))
|
403 |
-
|
404 |
-
with seo_cols[2]:
|
405 |
-
st.markdown("""
|
406 |
-
<div class="metric-card">
|
407 |
-
<h4>🔍 الكلمات المفتاحية</h4>
|
408 |
-
""", unsafe_allow_html=True)
|
409 |
-
st.write(seo_data.get('الكلمات المفتاحية', {}))
|
410 |
|
411 |
with tabs[2]:
|
412 |
st.subheader("تحليل الأمان")
|
413 |
-
|
414 |
-
# مؤشر الأمان العام
|
415 |
-
security_score = security_data.get('تقييم الحماية', 0)
|
416 |
-
|
417 |
-
security_fig = go.Figure(go.Indicator(
|
418 |
-
mode = "gauge+number+delta",
|
419 |
-
value = security_score,
|
420 |
-
delta = {'reference': 90},
|
421 |
-
title = {'text': "مستوى الأمان العام"},
|
422 |
-
gauge = {
|
423 |
-
'axis': {'range': [0, 100]},
|
424 |
-
'steps': [
|
425 |
-
{'range': [0, 50], 'color': "red"},
|
426 |
-
{'range': [50, 75], 'color': "yellow"},
|
427 |
-
{'range': [75, 100], 'color': "green"}
|
428 |
-
]
|
429 |
-
}
|
430 |
-
))
|
431 |
-
|
432 |
-
st.plotly_chart(security_fig, use_container_width=True)
|
433 |
-
|
434 |
-
# تفاصيل الأمان
|
435 |
-
security_cols = st.columns(3)
|
436 |
-
|
437 |
-
with security_cols[0]:
|
438 |
-
st.markdown("""
|
439 |
-
<div class="metric-card">
|
440 |
-
<h4>🔒 شهادة SSL</h4>
|
441 |
-
""", unsafe_allow_html=True)
|
442 |
-
st.write(security_data.get('شهادة SSL', {}))
|
443 |
-
|
444 |
-
with security_cols[1]:
|
445 |
-
st.markdown("""
|
446 |
-
<div class="metric-card">
|
447 |
-
<h4>🌐 سجلات DNS</h4>
|
448 |
-
""", unsafe_allow_html=True)
|
449 |
-
st.write(security_data.get('سجلات DNS', {}))
|
450 |
-
|
451 |
-
with security_cols[2]:
|
452 |
-
st.markdown("""
|
453 |
-
<div class="metric-card">
|
454 |
-
<h4>⚡ توصيات الأمان</h4>
|
455 |
-
""", unsafe_allow_html=True)
|
456 |
-
st.write(security_data.get('توصيات الأمان', []))
|
457 |
-
|
458 |
-
with tabs[3]:
|
459 |
-
st.subheader("التقرير الشامل")
|
460 |
-
|
461 |
-
# إنشاء تقرير PDF
|
462 |
-
if st.button("📥 تحميل التقرير الشامل (PDF)"):
|
463 |
-
report_data = {
|
464 |
-
'url': url,
|
465 |
-
'date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
466 |
-
'performance': performance_data,
|
467 |
-
'seo': seo_data,
|
468 |
-
'security': security_data
|
469 |
-
}
|
470 |
-
|
471 |
-
# هنا يمكن إضافة كود لإنشاء ملف PDF
|
472 |
-
st.success("تم تحضير التقرير بنجاح! اضغط هنا للتحميل")
|
473 |
-
|
474 |
-
# عرض ملخص شامل
|
475 |
-
st.markdown("""
|
476 |
-
<div class="metric-card">
|
477 |
-
<h3>📊 ملخص التحليل الشامل</h3>
|
478 |
-
""", unsafe_allow_html=True)
|
479 |
-
|
480 |
-
summary_cols = st.columns(3)
|
481 |
-
|
482 |
-
with summary_cols[0]:
|
483 |
-
st.markdown("""
|
484 |
-
#### 🚀 الأداء العام
|
485 |
-
""")
|
486 |
-
st.progress(performance_data.get('تقييم الأداء', 0) / 100)
|
487 |
-
|
488 |
-
with summary_cols[1]:
|
489 |
-
st.markdown("""
|
490 |
-
#### 🎯 تقييم SEO
|
491 |
-
""")
|
492 |
-
st.progress(seo_data.get('تقييم SEO الإجمالي', 0) / 100)
|
493 |
-
|
494 |
-
with summary_cols[2]:
|
495 |
-
st.markdown("""
|
496 |
-
#### 🔒 مستوى الأمان
|
497 |
-
""")
|
498 |
-
st.progress(security_data.get('تقييم الحماية', 0) / 100)
|
499 |
-
|
500 |
-
# توصيات التحسين
|
501 |
-
st.markdown("""
|
502 |
-
### 📈 توصيات التحسين
|
503 |
-
""")
|
504 |
-
|
505 |
-
recommendations = st.expander("عرض التوصيات", expanded=True)
|
506 |
-
with recommendations:
|
507 |
-
rec_cols = st.columns(3)
|
508 |
-
|
509 |
-
with rec_cols[0]:
|
510 |
-
st.markdown("#### 🚀 تحسين الأداء")
|
511 |
-
for rec in performance_data.get('توصيات تحسين الأداء', []):
|
512 |
-
st.markdown(f"- {rec}")
|
513 |
-
|
514 |
-
with rec_cols[1]:
|
515 |
-
st.markdown("#### 🎯 تحسين SEO")
|
516 |
-
for rec in seo_data.get('توصيات', []):
|
517 |
-
st.markdown(f"- {rec}")
|
518 |
-
|
519 |
-
with rec_cols[2]:
|
520 |
-
st.markdown("#### 🔒 تحسين الأمان")
|
521 |
-
for rec in security_data.get('توصيات الأمان', []):
|
522 |
-
st.markdown(f"- {rec}")
|
523 |
|
524 |
with col2:
|
525 |
st.subheader("📊 آخر التحليلات")
|
526 |
-
|
527 |
-
st.markdown("""
|
528 |
-
<div class="metric-card">
|
529 |
-
<h4>آخر 5 مواقع تم تحليلها</h4>
|
530 |
-
</div>
|
531 |
-
""", unsafe_allow_html=True)
|
532 |
-
|
533 |
-
# يمكن إضافة قاعدة بيانات لتخزين التحليلات السابقة
|
534 |
-
recent_analyses = [
|
535 |
-
{"url": "example1.com", "date": "2024-03-15", "score": 85},
|
536 |
-
{"url": "example2.com", "date": "2024-03-14", "score": 92},
|
537 |
-
{"url": "example3.com", "date": "2024-03-13", "score": 78}
|
538 |
-
]
|
539 |
-
|
540 |
-
for analysis in recent_analyses:
|
541 |
-
st.markdown(f"""
|
542 |
-
<div style='padding: 10px; margin: 5px; background-color: white; border-radius: 5px;'>
|
543 |
-
🌐 {analysis['url']}<br>
|
544 |
-
📅 {analysis['date']}<br>
|
545 |
-
⭐ {analysis['score']}/100
|
546 |
-
</div>
|
547 |
-
""", unsafe_allow_html=True)
|
548 |
|
549 |
elif selected == "التقارير السابقة":
|
550 |
st.subheader("📊 التقارير السابقة")
|
551 |
-
|
552 |
|
553 |
elif selected == "الإحصائيات":
|
554 |
st.subheader("📈 إحصائيات التحليل")
|
555 |
-
|
556 |
-
|
557 |
-
elif selected == "الإعدادات":
|
558 |
-
st.subheader("⚙️ إعدادات التحليل")
|
559 |
-
# يمكن إضافة كود للإعدادات
|
560 |
|
561 |
if __name__ == "__main__":
|
562 |
main()
|
|
|
1 |
import streamlit as st
|
|
|
2 |
from streamlit_option_menu import option_menu
|
3 |
import requests
|
4 |
import pandas as pd
|
|
|
16 |
from urllib.parse import urlparse
|
17 |
import json
|
18 |
import numpy as np
|
|
|
|
|
|
|
19 |
from PIL import Image
|
20 |
import io
|
21 |
import time
|
|
|
33 |
# تحسين التصميم باستخدام CSS
|
34 |
st.markdown("""
|
35 |
<style>
|
|
|
36 |
.main {
|
37 |
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
38 |
padding: 20px;
|
39 |
}
|
40 |
|
|
|
41 |
.metric-card {
|
42 |
background: white;
|
43 |
border-radius: 15px;
|
|
|
49 |
transform: translateY(-5px);
|
50 |
}
|
51 |
|
|
|
52 |
.stButton>button {
|
53 |
background: linear-gradient(45deg, #2196F3, #21CBF3);
|
54 |
color: white;
|
|
|
63 |
box-shadow: 0 6px 20px rgba(0,0,0,0.25);
|
64 |
}
|
65 |
|
|
|
66 |
h1, h2, h3 {
|
67 |
color: #1E3D59;
|
68 |
font-family: 'Tajawal', sans-serif;
|
69 |
}
|
70 |
|
|
|
71 |
.stTextInput>div>div>input {
|
72 |
border-radius: 10px;
|
73 |
border: 2px solid #E0E0E0;
|
74 |
padding: 10px;
|
75 |
}
|
76 |
|
|
|
77 |
.streamlit-expanderHeader {
|
78 |
background-color: white;
|
79 |
border-radius: 10px;
|
|
|
82 |
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700&display=swap" rel="stylesheet">
|
83 |
""", unsafe_allow_html=True)
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
class WebsiteAnalyzer:
|
86 |
def __init__(self):
|
87 |
self.headers = {
|
|
|
96 |
load_time = time.time() - start_time
|
97 |
page_size = len(response.content) / 1024
|
98 |
|
|
|
99 |
performance_metrics = {
|
100 |
"load_time": round(load_time, 2),
|
101 |
"page_size": round(page_size, 2),
|
102 |
"status_code": response.status_code,
|
|
|
|
|
|
|
|
|
103 |
"تقييم الأداء": self._calculate_performance_score(load_time, page_size),
|
104 |
"توصيات تحسين الأداء": self._get_performance_recommendations(load_time, page_size)
|
105 |
}
|
|
|
130 |
response = await client.get(url)
|
131 |
soup = BeautifulSoup(response.text, 'html.parser')
|
132 |
|
|
|
133 |
seo_analysis = {
|
134 |
"العنوان": self._analyze_title(soup),
|
135 |
"الوصف": self._analyze_description(soup),
|
136 |
+
"الكلمات المفتاحية": self._extract_keywords(soup),
|
137 |
"هيكل العناوين": self._analyze_headings(soup),
|
138 |
"الروابط": self._analyze_links(soup),
|
139 |
+
"تقييم SEO": self._calculate_seo_score(soup)
|
|
|
140 |
}
|
141 |
|
142 |
return seo_analysis
|
|
|
148 |
return {
|
149 |
"النص": title,
|
150 |
"الطول": len(title) if title else 0,
|
151 |
+
"التقييم": "ممتاز" if title and 30 <= len(title) <= 60 else "يحتاج تحسين"
|
|
|
152 |
}
|
153 |
|
154 |
+
def _analyze_description(self, soup):
|
155 |
+
meta_desc = soup.find('meta', {'name': 'description'})
|
156 |
+
desc = meta_desc['content'] if meta_desc else ""
|
157 |
+
return {
|
158 |
+
"النص": desc,
|
159 |
+
"الطول": len(desc) if desc else 0,
|
160 |
+
"التقييم": "ممتاز" if desc and 120 <= len(desc) <= 160 else "يحتاج تحسين"
|
161 |
+
}
|
162 |
+
|
163 |
+
def _extract_keywords(self, soup):
|
164 |
+
keywords = []
|
165 |
+
meta_keywords = soup.find('meta', {'name': 'keywords'})
|
166 |
+
if meta_keywords:
|
167 |
+
keywords = [k.strip() for k in meta_keywords['content'].split(',')]
|
168 |
+
return {
|
169 |
+
"الكلمات": keywords,
|
170 |
+
"العدد": len(keywords),
|
171 |
+
"التقييم": "ممتاز" if keywords else "يحتاج تحسين"
|
172 |
+
}
|
173 |
+
|
174 |
+
def _analyze_headings(self, soup):
|
175 |
+
headings = {f'h{i}': len(soup.find_all(f'h{i}')) for i in range(1, 7)}
|
176 |
+
return {
|
177 |
+
"العدد": headings,
|
178 |
+
"التقييم": "ممتاز" if headings.get('h1', 0) == 1 else "يحتاج تحسين"
|
179 |
+
}
|
180 |
+
|
181 |
+
def _analyze_links(self, soup):
|
182 |
+
links = soup.find_all('a')
|
183 |
+
return {
|
184 |
+
"العدد الإجمالي": len(links),
|
185 |
+
"الروابط الداخلية": len([l for l in links if l.get('href', '').startswith('/')]),
|
186 |
+
"الروابط الخارجية": len([l for l in links if l.get('href', '').startswith('http')])
|
187 |
+
}
|
188 |
+
|
189 |
+
def _calculate_seo_score(self, soup):
|
190 |
+
score = 100
|
191 |
+
# حساب النتيجة بناءً على العوامل المختلفة
|
192 |
+
if not soup.title:
|
193 |
+
score -= 20
|
194 |
+
if not soup.find('meta', {'name': 'description'}):
|
195 |
+
score -= 15
|
196 |
+
if not soup.find('meta', {'name': 'keywords'}):
|
197 |
+
score -= 10
|
198 |
+
if len(soup.find_all('h1')) != 1:
|
199 |
+
score -= 10
|
200 |
+
return max(0, score)
|
201 |
|
202 |
def analyze_security(self, url):
|
203 |
try:
|
204 |
domain = urlparse(url).netloc
|
205 |
security_analysis = {
|
206 |
+
"شهادة SSL": self._check_ssl(url),
|
207 |
+
"سجلات DNS": self._check_dns(domain),
|
208 |
+
"تقييم الأمان": self._calculate_security_score(url)
|
|
|
209 |
}
|
210 |
return security_analysis
|
211 |
except Exception as e:
|
212 |
return {"error": f"خطأ في تحليل الأمان: {str(e)}"}
|
213 |
|
214 |
+
def _check_ssl(self, url):
|
215 |
try:
|
216 |
context = ssl.create_default_context()
|
217 |
with socket.create_connection((urlparse(url).netloc, 443)) as sock:
|
|
|
219 |
cert = ssock.getpeercert()
|
220 |
return {
|
221 |
"الحالة": "آمن ✅",
|
222 |
+
"تاريخ الانتهاء": cert['notAfter']
|
|
|
223 |
}
|
224 |
except:
|
225 |
+
return {"الحالة": "غير آمن ❌"}
|
226 |
|
227 |
+
def _check_dns(self, domain):
|
228 |
+
try:
|
229 |
+
records = dns.resolver.resolve(domain, 'A')
|
230 |
+
return {
|
231 |
+
"عدد السجلات": len(records),
|
232 |
+
"السجلات": [str(r) for r in records]
|
233 |
+
}
|
234 |
+
except:
|
235 |
+
return {"error": "لا يمكن الوصول إلى سجلات DNS"}
|
236 |
+
|
237 |
+
def _calculate_security_score(self, url):
|
238 |
+
score = 100
|
239 |
+
try:
|
240 |
+
if not url.startswith('https'):
|
241 |
+
score -= 40
|
242 |
+
# يمكن إضافة المزيد من الفحوصات الأمنية هنا
|
243 |
+
except:
|
244 |
+
score = 0
|
245 |
+
return score
|
246 |
|
247 |
def main():
|
248 |
st.title("🔍 محلل المواقع المتقدم")
|
249 |
|
|
|
250 |
with st.sidebar:
|
251 |
selected = option_menu(
|
252 |
menu_title="القائمة الرئيسية",
|
253 |
+
options=["تحليل جديد", "التقارير السابقة", "الإحصائيات"],
|
254 |
+
icons=["search", "file-text", "graph-up"],
|
255 |
menu_icon="cast",
|
256 |
styles={
|
257 |
"container": {"padding": "15px"},
|
|
|
269 |
|
270 |
if analyze_button:
|
271 |
with st.spinner("جاري التحليل... ⏳"):
|
|
|
|
|
272 |
analyzer = WebsiteAnalyzer()
|
273 |
|
274 |
# تحليل متزامن
|
|
|
279 |
seo_data = loop.run_until_complete(analyzer.analyze_seo(url))
|
280 |
security_data = analyzer.analyze_security(url)
|
281 |
|
|
|
282 |
st.success("✨ تم اكتمال التحليل بنجاح!")
|
283 |
|
284 |
+
# عرض النتائج
|
285 |
+
tabs = st.tabs(["📊 الأداء", "🎯 SEO", "🔒 الأمان"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
|
287 |
with tabs[0]:
|
288 |
+
st.subheader("تحليل الأداء")
|
289 |
+
st.json(performance_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
290 |
|
291 |
with tabs[1]:
|
292 |
st.subheader("تحليل SEO")
|
293 |
+
st.json(seo_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
|
295 |
with tabs[2]:
|
296 |
st.subheader("تحليل الأمان")
|
297 |
+
st.json(security_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
|
299 |
with col2:
|
300 |
st.subheader("📊 آخر التحليلات")
|
301 |
+
st.info("سيتم عرض آخر المواقع التي تم تحليلها هنا")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
302 |
|
303 |
elif selected == "التقارير السابقة":
|
304 |
st.subheader("📊 التقارير السابقة")
|
305 |
+
st.info("قريباً...")
|
306 |
|
307 |
elif selected == "الإحصائيات":
|
308 |
st.subheader("📈 إحصائيات التحليل")
|
309 |
+
st.info("قريباً...")
|
|
|
|
|
|
|
|
|
310 |
|
311 |
if __name__ == "__main__":
|
312 |
main()
|