joermd commited on
Commit
1148762
·
verified ·
1 Parent(s): 229bfd5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -549
app.py CHANGED
@@ -29,7 +29,7 @@ from collections import Counter
29
  from wordcloud import WordCloud
30
  import advertools as adv
31
 
32
- # تحسين مظهر الصفحة
33
  st.set_page_config(
34
  layout="wide",
35
  page_title="محلل المواقع المتقدم | Website Analyzer Pro",
@@ -37,7 +37,7 @@ st.set_page_config(
37
  initial_sidebar_state="expanded"
38
  )
39
 
40
- # تحسين التصميم باستخدام CSS المحسن
41
  st.markdown("""
42
  <style>
43
  @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap');
@@ -162,7 +162,7 @@ class AdvancedWebsiteAnalyzer:
162
  return pd.DataFrame(columns=['url', 'timestamp', 'performance_score', 'seo_score', 'security_score'])
163
 
164
  def save_history(self, data):
165
- self.history = self.history.append(data, ignore_index=True)
166
  self.history.to_csv('analysis_history.csv', index=False)
167
 
168
  async def analyze_performance(self, url):
@@ -173,7 +173,6 @@ class AdvancedWebsiteAnalyzer:
173
  load_time = time.time() - start_time
174
  page_size = len(response.content) / 1024
175
 
176
- # تحليل الصور والموارد
177
  soup = BeautifulSoup(response.text, 'html.parser')
178
  images = soup.find_all('img')
179
  scripts = soup.find_all('script')
@@ -190,7 +189,6 @@ class AdvancedWebsiteAnalyzer:
190
  "توصيات التحسين": self._get_performance_recommendations(load_time, page_size, len(images), len(scripts))
191
  }
192
 
193
- # إضافة تحليل الموارد
194
  resources_analysis = await self._analyze_resources(url)
195
  performance_metrics.update(resources_analysis)
196
 
@@ -204,10 +202,9 @@ class AdvancedWebsiteAnalyzer:
204
  response = await client.get(url)
205
  soup = BeautifulSoup(response.text, 'html.parser')
206
 
207
- # تحليل الصور
208
  images = soup.find_all('img')
209
  image_sizes = []
210
- for img in images[:5]: # تحليل أول 5 صور فقط لتجنب البطء
211
  if img.get('src'):
212
  try:
213
  img_response = await client.get(img['src'])
@@ -225,25 +222,41 @@ class AdvancedWebsiteAnalyzer:
225
  except Exception as e:
226
  return {"error": f"خطأ في تحليل الموارد: {str(e)}"}
227
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  def _calculate_performance_score(self, load_time, page_size, image_count, script_count):
229
  score = 100
230
 
231
- # تأثير زمن التحميل
232
  if load_time > 2:
233
  score -= min(30, (load_time - 2) * 10)
234
-
235
- # تأثير حجم الصفحة
236
  if page_size > 1000:
237
  score -= min(20, (page_size - 1000) / 100)
238
-
239
- # تأثير عدد الصور
240
  if image_count > 10:
241
  score -= min(15, (image_count - 10) * 1.5)
242
-
243
- # تأثير عدد ملفات JavaScript
244
  if script_count > 5:
245
  score -= min(15, (script_count - 5) * 2)
246
-
247
  return max(0, round(score))
248
 
249
  def _get_performance_recommendations(self, load_time, page_size, image_count, script_count):
@@ -255,28 +268,28 @@ class AdvancedWebsiteAnalyzer:
255
  "الحل": "تحسين سرعة الخادم وتفعيل التخزين المؤقت",
256
  "الأولوية": "عالية"
257
  })
258
-
259
  if page_size > 1000:
260
  recommendations.append({
261
  "المشكلة": "حجم الصفحة كبير",
262
  "الحل": "ضغط الملفات وتحسين الكود",
263
  "الأولوية": "متوسطة"
264
  })
265
-
266
  if image_count > 10:
267
  recommendations.append({
268
  "المشكلة": "عدد كبير من الصور",
269
  "الحل": "تحسين حجم الصور واستخدام التحميل الكسول",
270
  "الأولوية": "متوسطة"
271
  })
272
-
273
  if script_count > 5:
274
  recommendations.append({
275
  "المشكلة": "عدد كبير من ملفات JavaScript",
276
  "الحل": "دمج وضغط ملفات JavaScript",
277
  "الأولوية": "عالية"
278
  })
279
-
280
  return recommendations if recommendations else [{"المشكلة": "لا توجد مشاكل", "الحل": "الأداء جيد!", "الأولوية": "منخفضة"}]
281
 
282
  async def analyze_seo(self, url):
@@ -285,13 +298,8 @@ class AdvancedWebsiteAnalyzer:
285
  response = await client.get(url)
286
  soup = BeautifulSoup(response.text, 'html.parser')
287
 
288
- # تحليل المحتوى
289
  content_analysis = self._analyze_content(soup)
290
-
291
- # تحليل الروابط
292
  links_analysis = self._analyze_links(soup)
293
-
294
- # تحليل الكلمات المفتاحية
295
  keywords_analysis = self._extract_keywords(soup)
296
 
297
  seo_analysis = {
@@ -309,563 +317,221 @@ class AdvancedWebsiteAnalyzer:
309
  except Exception as e:
310
  return {"error": f"خطأ في تحليل SEO: {str(e)}"}
311
 
312
- def _analyze_content(self, soup):
313
- # استخراج النص
314
- text_content = ' '.join([p.text for p in soup.find_all('p')])
315
-
316
- # تحليل طول المحتوى
317
- word_count = len(text_content.split())
318
-
319
- # تحليل قراءة المحتوى
320
- readability_score = self._calculate_readability(text_content)
321
-
322
- # تحليل كثافة الكلمات المفتاحية
323
- keyword_density = self._calculate_keyword_density(text_content)
324
-
325
  return {
326
- "عدد الكلمات": word_count,
327
- "مستوى القراءة": readability_score,
328
- "كثافة الكلمات المفتاحية": keyword_density,
329
- "التقييم": "ممتاز" if word_count > 300 and readability_score > 60 else "يحتاج تحسين"
330
  }
331
 
332
- def _calculate_readability(self, text):
333
- # حساب مؤشر بسيط لسهولة القراءة
334
- sentences = len(re.split(r'[.!?]+', text))
335
- words = len(text.split())
336
- if sentences == 0:
337
- return 0
338
- return min(100, round((words / sentences) * 10))
339
-
340
- def _calculate_keyword_density(self, text):
341
- words = text.lower().split()
342
- word_freq = Counter(words)
343
- total_words = len(words)
344
-
345
- if total_words == 0:
346
- return {}
347
-
348
- return {word: round((count / total_words) * 100, 2)
349
- for word, count in word_freq.most_common(5)}
350
-
351
- import streamlit as st
352
- from streamlit_option_menu import option_menu
353
- import requests
354
- import pandas as pd
355
- import plotly.express as px
356
- import plotly.graph_objects as go
357
- from datetime import datetime
358
- import httpx
359
- import asyncio
360
- import aiohttp
361
- from bs4 import BeautifulSoup
362
- import whois
363
- import ssl
364
- import socket
365
- import dns.resolver
366
- from urllib.parse import urlparse
367
- import json
368
- import numpy as np
369
- from PIL import Image
370
- import io
371
- import time
372
- import matplotlib.pyplot as plt
373
- import seaborn as sns
374
- from datetime import timedelta
375
- import tldextract
376
- from concurrent.futures import ThreadPoolExecutor
377
- import re
378
- from collections import Counter
379
- from wordcloud import WordCloud
380
- import advertools as adv
381
-
382
- # تحسين مظهر الصفحة
383
- st.set_page_config(
384
- layout="wide",
385
- page_title="محلل المواقع المتقدم | Website Analyzer Pro",
386
- page_icon="🔍",
387
- initial_sidebar_state="expanded"
388
- )
389
-
390
- # تحسين التصميم باستخدام CSS المحسن
391
- st.markdown("""
392
- <style>
393
- @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap');
394
-
395
- * {
396
- font-family: 'Tajawal', sans-serif;
397
- }
398
-
399
- .main {
400
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
401
- padding: 20px;
402
- }
403
-
404
- .metric-card {
405
- background: white;
406
- border-radius: 15px;
407
- padding: 20px;
408
- box-shadow: 0 4px 15px rgba(0,0,0,0.1);
409
- transition: all 0.3s ease;
410
- margin-bottom: 20px;
411
- }
412
-
413
- .metric-card:hover {
414
- transform: translateY(-5px);
415
- box-shadow: 0 8px 25px rgba(0,0,0,0.15);
416
- }
417
-
418
- .metric-value {
419
- font-size: 2em;
420
- font-weight: bold;
421
- color: #2196F3;
422
- }
423
-
424
- .metric-label {
425
- color: #666;
426
- font-size: 1.1em;
427
- }
428
-
429
- .stButton>button {
430
- background: linear-gradient(45deg, #2196F3, #21CBF3);
431
- color: white;
432
- border-radius: 25px;
433
- padding: 15px 30px;
434
- border: none;
435
- box-shadow: 0 4px 15px rgba(33,150,243,0.3);
436
- transition: all 0.3s ease;
437
- font-size: 1.1em;
438
- font-weight: 500;
439
- width: 100%;
440
- }
441
-
442
- .stButton>button:hover {
443
- transform: translateY(-2px);
444
- box-shadow: 0 6px 20px rgba(33,150,243,0.4);
445
- }
446
-
447
- h1, h2, h3 {
448
- color: #1E3D59;
449
- font-weight: 700;
450
- }
451
-
452
- .stTextInput>div>div>input {
453
- border-radius: 10px;
454
- border: 2px solid #E0E0E0;
455
- padding: 12px;
456
- font-size: 1.1em;
457
- transition: all 0.3s ease;
458
- }
459
-
460
- .stTextInput>div>div>input:focus {
461
- border-color: #2196F3;
462
- box-shadow: 0 0 0 2px rgba(33,150,243,0.2);
463
- }
464
-
465
- .streamlit-expanderHeader {
466
- background-color: white;
467
- border-radius: 10px;
468
- padding: 10px;
469
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
470
- }
471
-
472
- .stProgress > div > div > div {
473
- background-color: #2196F3;
474
- }
475
-
476
- .tab-content {
477
- padding: 20px;
478
- background: white;
479
- border-radius: 15px;
480
- box-shadow: 0 4px 15px rgba(0,0,0,0.1);
481
- }
482
-
483
- .insight-card {
484
- background: #f8f9fa;
485
- border-right: 4px solid #2196F3;
486
- padding: 15px;
487
- margin: 10px 0;
488
- border-radius: 8px;
489
- }
490
-
491
- .chart-container {
492
- background: white;
493
- padding: 20px;
494
- border-radius: 15px;
495
- box-shadow: 0 4px 15px rgba(0,0,0,0.1);
496
- margin: 20px 0;
497
- }
498
- </style>
499
- """, unsafe_allow_html=True)
500
-
501
- class AdvancedWebsiteAnalyzer:
502
- def __init__(self):
503
- self.headers = {
504
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
505
  }
506
- self.history = self.load_history()
507
-
508
- def load_history(self):
509
- try:
510
- return pd.read_csv('analysis_history.csv')
511
- except:
512
- return pd.DataFrame(columns=['url', 'timestamp', 'performance_score', 'seo_score', 'security_score'])
513
-
514
- def save_history(self, data):
515
- self.history = self.history.append(data, ignore_index=True)
516
- self.history.to_csv('analysis_history.csv', index=False)
517
-
518
- async def analyze_performance(self, url):
519
- try:
520
- start_time = time.time()
521
- async with httpx.AsyncClient() as client:
522
- response = await client.get(url)
523
- load_time = time.time() - start_time
524
- page_size = len(response.content) / 1024
525
-
526
- # تحليل الصور والموارد
527
- soup = BeautifulSoup(response.text, 'html.parser')
528
- images = soup.find_all('img')
529
- scripts = soup.find_all('script')
530
- css_files = soup.find_all('link', {'rel': 'stylesheet'})
531
-
532
- performance_metrics = {
533
- "زمن التحميل": round(load_time, 2),
534
- "حجم الصفحة": round(page_size, 2),
535
- "حالة الاستجابة": response.status_code,
536
- "عدد الصور": len(images),
537
- "عدد ملفات JavaScript": len(scripts),
538
- "عدد ملفات CSS": len(css_files),
539
- "تقييم الأداء": self._calculate_performance_score(load_time, page_size, len(images), len(scripts)),
540
- "توصيات التحسين": self._get_performance_recommendations(load_time, page_size, len(images), len(scripts))
541
- }
542
-
543
- # إضافة تحليل الموارد
544
- resources_analysis = await self._analyze_resources(url)
545
- performance_metrics.update(resources_analysis)
546
-
547
- return performance_metrics
548
- except Exception as e:
549
- return {"error": f"خطأ في تحليل الأداء: {str(e)}"}
550
 
551
- async def _analyze_resources(self, url):
552
- try:
553
- async with httpx.AsyncClient() as client:
554
- response = await client.get(url)
555
- soup = BeautifulSoup(response.text, 'html.parser')
556
-
557
- # تحليل الصور
558
- images = soup.find_all('img')
559
- image_sizes = []
560
- for img in images[:5]: # تحليل أول 5 صور فقط لتجنب البطء
561
- if img.get('src'):
562
- try:
563
- img_response = await client.get(img['src'])
564
- image_sizes.append(len(img_response.content) / 1024)
565
- except:
566
- continue
567
-
568
- return {
569
- "تحليل الموارد": {
570
- "متوسط حجم الصور": round(np.mean(image_sizes), 2) if image_sizes else 0,
571
- "عدد الموارد الخارجية": len(soup.find_all(['script', 'link', 'img'])),
572
- "توصيات تحسين الموارد": self._get_resource_recommendations(image_sizes)
573
- }
574
- }
575
- except Exception as e:
576
- return {"error": f"خطأ في تحليل الموارد: {str(e)}"}
577
-
578
- def _calculate_performance_score(self, load_time, page_size, image_count, script_count):
579
- score = 100
580
-
581
- # تأثير زمن التحميل
582
- if load_time > 2:
583
- score -= min(30, (load_time - 2) * 10)
584
-
585
- # تأثير حجم الصفحة
586
- if page_size > 1000:
587
- score -= min(20, (page_size - 1000) / 100)
588
-
589
- # تأثير عدد الصور
590
- if image_count > 10:
591
- score -= min(15, (image_count - 10) * 1.5)
592
-
593
- # تأثير عدد ملفات JavaScript
594
- if script_count > 5:
595
- score -= min(15, (script_count - 5) * 2)
596
-
597
- return max(0, round(score))
598
 
599
- def _get_performance_recommendations(self, load_time, page_size, image_count, script_count):
600
- recommendations = []
 
 
 
601
 
602
- if load_time > 2:
603
- recommendations.append({
604
- "المشكلة": "بطء زمن التحميل",
605
- "الحل": "تحسين سرعة الخادم وتفعيل التخزين المؤقت",
606
- "الأولوية": "عالية"
607
- })
608
-
609
- if page_size > 1000:
610
- recommendations.append({
611
- "المشكلة": "حجم الصفحة كبير",
612
- "الحل": "ضغط الملفات وتحسين الكود",
613
- "الأولوية": "متوسطة"
614
- })
615
-
616
- if image_count > 10:
617
- recommendations.append({
618
- "المشكلة": "عدد كبير من الصور",
619
- "الحل": "تحسين حجم الصور واستخدام التحميل الكسول",
620
- "الأولوية": "متوسطة"
621
- })
622
-
623
- if script_count > 5:
624
- recommendations.append({
625
- "المشكلة": "عدد كبير من ملفات JavaScript",
626
- "الحل": "دمج وضغط ملفات JavaScript",
627
- "الأولوية": "عالية"
628
- })
629
-
630
- return recommendations if recommendations else [{"المشكلة": "لا توجد مشاكل", "الحل": "الأداء جيد!", "الأولوية": "منخفضة"}]
631
-
632
- async def analyze_seo(self, url):
633
- try:
634
- async with httpx.AsyncClient() as client:
635
- response = await client.get(url)
636
- soup = BeautifulSoup(response.text, 'html.parser')
637
-
638
- # تحليل المحتوى
639
- content_analysis = self._analyze_content(soup)
640
-
641
- # تحليل الروابط
642
- links_analysis = self._analyze_links(soup)
643
-
644
- # تحليل الكلمات المفتاحية
645
- keywords_analysis = self._extract_keywords(soup)
646
 
647
- seo_analysis = {
648
- "تحليل العنوان": self._analyze_title(soup),
649
- "تحليل الوصف": self._analyze_description(soup),
650
- "تحليل الكلمات المفتاحية": keywords_analysis,
651
- "تحليل العناوين": self._analyze_headings(soup),
652
- "تحليل الروابط": links_analysis,
653
- "تحليل المحتوى": content_analysis,
654
- "تقييم SEO": self._calculate_seo_score(soup),
655
- "توصيات تحسين SEO": self._get_seo_recommendations(soup)
656
- }
657
-
658
- return seo_analysis
659
- except Exception as e:
660
- return {"error": f"خطأ في تحليل SEO: {str(e)}"}
661
 
662
- def _analyze_content(self, soup):
663
- # استخراج النص
664
- text_content = ' '.join([p.text for p in soup.find_all('p')])
 
 
 
 
 
 
 
665
 
666
- # تحليل طول المحتوى
667
- word_count = len(text_content.split())
 
668
 
669
- # تحليل قراءة المحتوى
670
  readability_score = self._calculate_readability(text_content)
671
 
672
- # تحليل كثافة الكلمات المفتاحية
673
  keyword_density = self._calculate_keyword_density(text_content)
674
 
675
- return {
676
- "عدد الكلمات": word_count,
677
- "مستوى القراءة": readability_score,
678
- "كثافة الكلمات المفتاحية": keyword_density,
679
- "التقييم": "ممتاز" if word_count > 300 and readability_score > 60 else "يحتاج تحسين"
680
- }
681
-
682
- def _calculate_readability(self, text):
683
- # حساب مؤشر بسيط لسهولة القراءة
684
- sentences = len(re.split(r'[.!?]+', text))
685
- words = len(text.split())
686
- if sentences == 0:
687
- return 0
688
- return min(100, round((words / sentences) * 10))
689
-
690
- def _calculate_keyword_density(self, text):
691
- words = text.lower().split()
692
- word_freq = Counter(words)
693
- total_words = len(words)
694
 
695
- if total_words == 0:
696
- return {}
697
-
698
- return {word: round((count / total_words) * 100, 2)
699
- for word, count in word_freq.most_common(5)}
700
-
701
- def analyze_security(self, url):
702
- try:
703
- domain = urlparse(url).netloc
704
- whois_info = self._get_whois_info(domain)
705
 
706
- security_analysis = {
707
- "تحليل SSL": self._check_ssl(url),
708
- "تحليل DNS": self._check_dns(domain),
709
- "تحليل Headers": self._check_security_headers(url),
710
- "فحص المخاطر": self._check_security_risks(url),
711
- "معلومات Whois": whois_info,
712
- "تقييم الأمان": self._calculate_security_score(url),
713
- "توصيات الأمان": self._get_security_recommendations(url)
714
- }
715
- return security_analysis
716
- except Exception as e:
717
- return {"error": f"خطأ في تحليل الأمان: {str(e)}"}
718
-
719
- def _get_whois_info(self, domain):
720
- try:
721
- w = whois.whois(domain)
722
  return {
723
- "اسم النطاق": domain,
724
- "تاريخ التسجيل": str(w.creation_date),
725
- "تاريخ الانتهاء": str(w.expiration_date),
726
- "المسجل": w.registrar,
727
- "الحالة": w.status
728
- }
729
- except:
730
- return {"error": "لا يمكن الحصول على معلومات Whois"}
731
-
732
- def _check_ssl(self, url):
733
- try:
734
- context = ssl.create_default_context()
735
- with socket.create_connection((urlparse(url).netloc, 443)) as sock:
736
- with context.wrap_socket(sock, server_hostname=urlparse(url).netloc) as ssock:
737
- cert = ssock.getpeercert()
738
- return {
739
- "الحالة": "آمن ✅",
740
- "نوع الشهادة": cert.get('subject', {}).get('commonName', 'Unknown'),
741
- "تاريخ الإصدار": cert.get('notBefore', 'Unknown'),
742
- "تاريخ الانتهاء": cert.get('notAfter', 'Unknown'),
743
- "الخوارزمية": ssock.cipher()[0],
744
- "قوة التشفير": f"{ssock.cipher()[2]} bits"
745
- }
746
- except:
747
- return {
748
- "الحالة": "غير آمن ❌",
749
- "السبب": "لا يوجد شهادة SSL صالحة"
750
- }
751
-
752
- def _check_security_headers(self, url):
753
- try:
754
- response = requests.get(url)
755
- headers = response.headers
756
- security_headers = {
757
- 'Strict-Transport-Security': 'HSTS',
758
- 'Content-Security-Policy': 'CSP',
759
- 'X-Frame-Options': 'X-Frame',
760
- 'X-Content-Type-Options': 'X-Content-Type',
761
- 'X-XSS-Protection': 'XSS Protection'
762
- }
763
-
764
- results = {}
765
- for header, name in security_headers.items():
766
- results[name] = {
767
- "موجود": header in headers,
768
- "القيمة": headers.get(header, "غير موجود")
769
  }
770
- return results
771
- except:
772
- return {"error": "فشل فحص headers الأمان"}
773
-
774
- def _check_security_risks(self, url):
775
- risks = []
776
-
777
- # فحص بروتوكول HTTP
778
- if not url.startswith('https'):
779
- risks.append({
780
- "المستوى": "عالي",
781
- "النوع": "بروتوكول غير آمن",
782
- "الوصف": "الموقع يستخدم HTTP بدلاً من HTTPS"
783
- })
784
-
785
- # فحص تحديث شهادة SSL
786
- ssl_info = self._check_ssl(url)
787
- if ssl_info.get("الحالة") == "غير آمن ❌":
788
- risks.append({
789
- "المستوى": "عالي",
790
- "النوع": "شهادة SSL",
791
- "الوصف": "شهادة SSL غير صالحة أو منتهية"
792
- })
793
-
794
- # فحص headers الأمان
795
- headers = self._check_security_headers(url)
796
- if isinstance(headers, dict) and not headers.get("HSTS", {}).get("موجود"):
797
- risks.append({
798
- "المستوى": "متوسط",
799
- "النوع": "HSTS غير مفعل",
800
- "الوصف": "عدم وجود حماية النقل الآمن الصارم"
801
- })
802
-
803
- return {
804
- "المخاطر المكتشفة": risks,
805
- "عدد المخاطر": len(risks),
806
- "مستوى الخطورة": "عالي" if any(r["المستوى"] == "عالي" for r in risks) else "متوسط" if risks else "منخفض"
807
- }
808
 
809
- def _calculate_security_score(self, url):
 
 
 
810
  score = 100
811
 
812
- # فحص HTTPS
813
- if not url.startswith('https'):
814
- score -= 30
815
-
816
- # فحص SSL
817
- ssl_info = self._check_ssl(url)
818
- if ssl_info.get("الحالة") == "غير آمن ❌":
819
- score -= 25
820
-
821
- # فحص Headers
822
- headers = self._check_security_headers(url)
823
- if isinstance(headers, dict):
824
- for header_info in headers.values():
825
- if not header_info.get("موجود"):
826
- score -= 5
827
-
828
- # فحص مخاطر الأمان
829
- risks = self._check_security_risks(url)
830
- score -= (risks.get("عدد المخاطر", 0) * 10)
831
-
 
 
 
 
 
 
 
 
832
  return max(0, score)
833
 
834
- def _get_security_recommendations(self, url):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
  recommendations = []
836
 
837
- # فحص HTTPS
838
- if not url.startswith('https'):
839
  recommendations.append({
840
- "المشكلة": "عدم استخدام HTTPS",
841
- "الحل": "قم بتفعيل HTTPS وتثبيت شهادة SSL",
842
  "الأولوية": "عالية"
843
  })
844
 
845
- # فحص SSL
846
- ssl_info = self._check_ssl(url)
847
- if ssl_info.get("الحالة") == "غير آمن ":
 
 
 
 
 
848
  recommendations.append({
849
- "المشكلة": "شهادة SSL غير صالحة",
850
- "الحل": "قم بتجديد أو تثبيت شهادة SSL جديدة",
851
  "الأولوية": "عالية"
852
  })
853
 
854
- # فحص Headers
855
- headers = self._check_security_headers(url)
856
- if isinstance(headers, dict):
857
- for name, info in headers.items():
858
- if not info.get("موجود"):
859
- recommendations.append({
860
- "المشكلة": f"عدم وجود {name}",
861
- "الحل": f"قم بإضافة header الأمان {name}",
862
- "الأولوية": "متوسطة"
863
- })
864
 
865
- return recommendations if recommendations else [
866
- {
867
- "المشكلة": "لا توجد مشاكل أمنية واضحة",
868
- "الحل": "استمر في مراقبة وتحديث إعدادات الأمان",
869
- "الأولوية": "منخفضة"
870
- }
871
- ]
 
 
 
 
 
 
 
 
 
 
29
  from wordcloud import WordCloud
30
  import advertools as adv
31
 
32
+ # Page configuration
33
  st.set_page_config(
34
  layout="wide",
35
  page_title="محلل المواقع المتقدم | Website Analyzer Pro",
 
37
  initial_sidebar_state="expanded"
38
  )
39
 
40
+ # Custom CSS
41
  st.markdown("""
42
  <style>
43
  @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap');
 
162
  return pd.DataFrame(columns=['url', 'timestamp', 'performance_score', 'seo_score', 'security_score'])
163
 
164
  def save_history(self, data):
165
+ self.history = pd.concat([self.history, pd.DataFrame([data])], ignore_index=True)
166
  self.history.to_csv('analysis_history.csv', index=False)
167
 
168
  async def analyze_performance(self, url):
 
173
  load_time = time.time() - start_time
174
  page_size = len(response.content) / 1024
175
 
 
176
  soup = BeautifulSoup(response.text, 'html.parser')
177
  images = soup.find_all('img')
178
  scripts = soup.find_all('script')
 
189
  "توصيات التحسين": self._get_performance_recommendations(load_time, page_size, len(images), len(scripts))
190
  }
191
 
 
192
  resources_analysis = await self._analyze_resources(url)
193
  performance_metrics.update(resources_analysis)
194
 
 
202
  response = await client.get(url)
203
  soup = BeautifulSoup(response.text, 'html.parser')
204
 
 
205
  images = soup.find_all('img')
206
  image_sizes = []
207
+ for img in images[:5]:
208
  if img.get('src'):
209
  try:
210
  img_response = await client.get(img['src'])
 
222
  except Exception as e:
223
  return {"error": f"خطأ في تحليل الموارد: {str(e)}"}
224
 
225
+ def _get_resource_recommendations(self, image_sizes):
226
+ recommendations = []
227
+
228
+ if image_sizes:
229
+ avg_size = np.mean(image_sizes)
230
+ if avg_size > 100:
231
+ recommendations.append({
232
+ "المشكلة": "حجم الصور كبير",
233
+ "الحل": "ضغط الصور وتحسين جودتها",
234
+ "الأولوية": "عالية"
235
+ })
236
+
237
+ return recommendations if recommendations else [
238
+ {
239
+ "المشكلة": "لا توجد مشاكل",
240
+ "الحل": "الموارد محسنة بشكل جيد",
241
+ "الأولوية": "منخفضة"
242
+ }
243
+ ]
244
+
245
  def _calculate_performance_score(self, load_time, page_size, image_count, script_count):
246
  score = 100
247
 
 
248
  if load_time > 2:
249
  score -= min(30, (load_time - 2) * 10)
250
+
 
251
  if page_size > 1000:
252
  score -= min(20, (page_size - 1000) / 100)
253
+
 
254
  if image_count > 10:
255
  score -= min(15, (image_count - 10) * 1.5)
256
+
 
257
  if script_count > 5:
258
  score -= min(15, (script_count - 5) * 2)
259
+
260
  return max(0, round(score))
261
 
262
  def _get_performance_recommendations(self, load_time, page_size, image_count, script_count):
 
268
  "الحل": "تحسين سرعة الخادم وتفعيل التخزين المؤقت",
269
  "الأولوية": "عالية"
270
  })
271
+
272
  if page_size > 1000:
273
  recommendations.append({
274
  "المشكلة": "حجم الصفحة كبير",
275
  "الحل": "ضغط الملفات وتحسين الكود",
276
  "الأولوية": "متوسطة"
277
  })
278
+
279
  if image_count > 10:
280
  recommendations.append({
281
  "المشكلة": "عدد كبير من الصور",
282
  "الحل": "تحسين حجم الصور واستخدام التحميل الكسول",
283
  "الأولوية": "متوسطة"
284
  })
285
+
286
  if script_count > 5:
287
  recommendations.append({
288
  "المشكلة": "عدد كبير من ملفات JavaScript",
289
  "الحل": "دمج وضغط ملفات JavaScript",
290
  "الأولوية": "عالية"
291
  })
292
+
293
  return recommendations if recommendations else [{"المشكلة": "لا توجد مشاكل", "الحل": "الأداء جيد!", "الأولوية": "منخفضة"}]
294
 
295
  async def analyze_seo(self, url):
 
298
  response = await client.get(url)
299
  soup = BeautifulSoup(response.text, 'html.parser')
300
 
 
301
  content_analysis = self._analyze_content(soup)
 
 
302
  links_analysis = self._analyze_links(soup)
 
 
303
  keywords_analysis = self._extract_keywords(soup)
304
 
305
  seo_analysis = {
 
317
  except Exception as e:
318
  return {"error": f"خطأ في تحليل SEO: {str(e)}"}
319
 
320
+ def _analyze_title(self, soup):
321
+ title = soup.find('title')
322
+ title_text = title.text if title else ""
 
 
 
 
 
 
 
 
 
 
323
  return {
324
+ "العنوان": title_text,
325
+ "الطول": len(title_text),
326
+ "التقييم": "جيد" if 30 <= len(title_text) <= 60 else "يحتاج تحسين"
 
327
  }
328
 
329
+ def _analyze_description(self, soup):
330
+ meta_desc = soup.find('meta', {'name': 'description'})
331
+ desc_text = meta_desc.get('content', '') if meta_desc else ""
332
+ return {
333
+ "الوصف": desc_text,
334
+ "الطول": len(desc_text),
335
+ "التقييم": "جيد" if 120 <= len(desc_text) <= 160 else "يحتاج تحسين"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
 
338
+ def _analyze_headings(self, soup):
339
+ headings = {}
340
+ for i in range(1, 7):
341
+ h_tags = soup.find_all(f'h{i}')
342
+ headings[f'h{i}'] = {
343
+ "العدد": len(h_tags),
344
+ "النصوص": [h.text.strip() for h in h_tags]
345
+ }
346
+ return headings
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
 
348
+ def _analyze_links(self, soup):
349
+ links = soup.find_all('a')
350
+ internal_links = []
351
+ external_links = []
352
+ broken_links = []
353
 
354
+ for link in links:
355
+ href = link.get('href', '')
356
+ if href.startswith('#') or not href:
357
+ continue
358
+ elif href.startswith('/') or urlparse(href).netloc == urlparse(href).netloc:
359
+ internal_links.append(href)
360
+ else:
361
+ external_links.append(href)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
363
+ try:
364
+ response = requests.head(href)
365
+ if response.status_code >= 400:
366
+ broken_links.append(href)
367
+ except:
368
+ broken_links.append(href)
369
+
370
+ return {
371
+ "عدد الروابط الداخلية": len(internal_links),
372
+ "عدد الروابط الخارجية": len(external_links),
373
+ "عدد الروابط المكسورة": len(broken_links),
374
+ "الروابط المكسورة": broken_links
375
+ }
 
376
 
377
+ def _analyze_content(self, soup):
378
+ """
379
+ Analyzes webpage content for SEO factors
380
+ """
381
+ try:
382
+ # Extract all text content
383
+ text_content = ' '.join([p.text.strip() for p in soup.find_all(['p', 'div', 'article', 'section'])])
384
+
385
+ # Analyze headings hierarchy
386
+ headings = {f'h{i}': len(soup.find_all(f'h{i}')) for i in range(1, 7)}
387
 
388
+ # Calculate word count
389
+ words = text_content.split()
390
+ word_count = len(words)
391
 
392
+ # Calculate readability score
393
  readability_score = self._calculate_readability(text_content)
394
 
395
+ # Analyze keyword density
396
  keyword_density = self._calculate_keyword_density(text_content)
397
 
398
+ # Check for images with alt text
399
+ images = soup.find_all('img')
400
+ images_with_alt = len([img for img in images if img.get('alt')])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
 
402
+ # Calculate content quality score
403
+ quality_score = self._calculate_content_quality_score(
404
+ word_count,
405
+ readability_score,
406
+ images_with_alt,
407
+ len(images),
408
+ headings
409
+ )
 
 
410
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  return {
412
+ "إحصائيات المحتوى": {
413
+ "عدد الكلمات": word_count,
414
+ "مستوى القراءة": readability_score,
415
+ "نسبة الصور مع نص بديل": f"{(images_with_alt/len(images)*100 if images else 0):.1f}%",
416
+ "توزيع العناوين": headings,
417
+ },
418
+ "تحليل الكلمات المفتاحية": {
419
+ "كثافة الكلمات الرئيسية": keyword_density,
420
+ "الكلمات الأكثر تكراراً": self._get_top_words(text_content, 5)
421
+ },
422
+ "تقييم جودة المحتوى": {
423
+ "الدرجة": quality_score,
424
+ "التقييم": self._get_content_rating(quality_score),
425
+ "التوصيات": self._get_content_recommendations(
426
+ word_count,
427
+ readability_score,
428
+ images_with_alt,
429
+ len(images),
430
+ headings
431
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
432
  }
433
+ }
434
+ except Exception as e:
435
+ return {"error": f"خطأ في تحليل المحتوى: {str(e)}"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
 
437
+ def _calculate_content_quality_score(self, word_count, readability, alt_images, total_images, headings):
438
+ """
439
+ Calculates a content quality score based on various factors
440
+ """
441
  score = 100
442
 
443
+ # Word count scoring
444
+ if word_count < 300:
445
+ score -= 20
446
+ elif word_count < 600:
447
+ score -= 10
448
+
449
+ # Readability scoring
450
+ if readability < 40:
451
+ score -= 15
452
+ elif readability < 60:
453
+ score -= 10
454
+
455
+ # Image alt text scoring
456
+ if total_images > 0:
457
+ alt_ratio = alt_images / total_images
458
+ if alt_ratio < 0.5:
459
+ score -= 15
460
+ elif alt_ratio < 0.8:
461
+ score -= 10
462
+
463
+ # Heading hierarchy scoring
464
+ if headings.get('h1', 0) == 0:
465
+ score -= 10
466
+ if headings.get('h1', 0) > 1:
467
+ score -= 5
468
+ if headings.get('h2', 0) == 0:
469
+ score -= 5
470
+
471
  return max(0, score)
472
 
473
+ def _get_content_rating(self, score):
474
+ """
475
+ Converts numerical score to qualitative rating
476
+ """
477
+ if score >= 90:
478
+ return "ممتاز"
479
+ elif score >= 80:
480
+ return "جيد جداً"
481
+ elif score >= 70:
482
+ return "جيد"
483
+ elif score >= 60:
484
+ return "مقبول"
485
+ else:
486
+ return "يحتاج تحسين"
487
+
488
+ def _get_content_recommendations(self, word_count, readability, alt_images, total_images, headings):
489
+ """
490
+ Generates content improvement recommendations
491
+ """
492
  recommendations = []
493
 
494
+ if word_count < 300:
 
495
  recommendations.append({
496
+ "المشكلة": "محتوى قصير جداً",
497
+ "الحل": "زيادة المحتوى إلى 300 كلمة على الأقل",
498
  "الأولوية": "عالية"
499
  })
500
 
501
+ if readability < 60:
502
+ recommendations.append({
503
+ "المشكلة": "صعوبة قراءة المحتوى",
504
+ "الحل": "تبسيط الجمل واستخدام لغة أسهل",
505
+ "الأولوية": "متوسطة"
506
+ })
507
+
508
+ if total_images > 0 and (alt_images / total_images) < 0.8:
509
  recommendations.append({
510
+ "المشكلة": "نقص في النصوص البديلة للصور",
511
+ "الحل": "إضافة نص بديل وصفي لجميع الصور",
512
  "الأولوية": "عالية"
513
  })
514
 
515
+ if headings.get('h1', 0) != 1:
516
+ recommendations.append({
517
+ "المشكلة": "عدد غير مناسب من عناوين H1",
518
+ "الحل": "استخدام عنوان H1 واحد فقط للصفحة",
519
+ "الأولوية": "عالية"
520
+ })
 
 
 
 
521
 
522
+ return recommendations if recommendations else [{
523
+ "المشكلة": "لا توجد مشاكل واضحة",
524
+ "الحل": "الاستمرار في تحديث المحتوى بشكل دوري",
525
+ "الأولوية": "منخفضة"
526
+ }]
527
+
528
+ def _get_top_words(self, text, count=5):
529
+ """
530
+ Gets the most frequent meaningful words in the content
531
+ """
532
+ # Remove common Arabic and English stop words
533
+ stop_words = set(['و', 'في', 'من', 'على', 'the', 'and', 'in', 'of', 'to'])
534
+ words = text.lower().split()
535
+ word_freq = Counter(word for word in words if word not in stop_words and len(word) > 2)
536
+
537
+ return {word: count for word, count in word_freq.most_common(count)}