Update app.py
Browse files
app.py
CHANGED
@@ -117,13 +117,20 @@ class WebsiteAnalyzer:
|
|
117 |
response = await client.get(url)
|
118 |
soup = BeautifulSoup(response.text, 'html.parser')
|
119 |
|
120 |
-
# تحليل العناوين
|
121 |
headings = {
|
122 |
'h1': len(soup.find_all('h1')),
|
123 |
'h2': len(soup.find_all('h2')),
|
124 |
'h3': len(soup.find_all('h3'))
|
125 |
}
|
126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
# تحليل الروابط
|
128 |
links = soup.find_all('a')
|
129 |
internal_links = len([link for link in links if urlparse(link.get('href', '')).netloc == urlparse(url).netloc])
|
@@ -132,14 +139,66 @@ class WebsiteAnalyzer:
|
|
132 |
# تحليل الصور
|
133 |
images = soup.find_all('img')
|
134 |
images_without_alt = len([img for img in images if not img.get('alt')])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
|
136 |
return {
|
137 |
-
"title":
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
}
|
144 |
except Exception as e:
|
145 |
return {"error": str(e)}
|
@@ -237,17 +296,17 @@ def main():
|
|
237 |
with cols[1]:
|
238 |
st.metric("حجم الصفحة", f"{performance_data.get('page_size', 'N/A')} KB")
|
239 |
with cols[2]:
|
240 |
-
st.metric("الروابط الداخلية", seo_data.get('internal_links', 'N/A'))
|
241 |
|
242 |
# عرض تحليل SEO
|
243 |
with st.expander("تحليل SEO", expanded=True):
|
244 |
st.json(seo_data)
|
245 |
|
246 |
# رسم بياني للعناوين
|
247 |
-
if 'headings' in seo_data:
|
248 |
fig = px.bar(
|
249 |
-
x=list(seo_data['headings'].keys()),
|
250 |
-
y=list(seo_data['headings'].values()),
|
251 |
title="توزيع العناوين",
|
252 |
labels={'x': 'نوع العنوان', 'y': 'العدد'}
|
253 |
)
|
|
|
117 |
response = await client.get(url)
|
118 |
soup = BeautifulSoup(response.text, 'html.parser')
|
119 |
|
120 |
+
# تحليل العناوين مع تقييم
|
121 |
headings = {
|
122 |
'h1': len(soup.find_all('h1')),
|
123 |
'h2': len(soup.find_all('h2')),
|
124 |
'h3': len(soup.find_all('h3'))
|
125 |
}
|
126 |
|
127 |
+
# تقييم العناوين
|
128 |
+
heading_score = 0
|
129 |
+
if headings['h1'] > 0:
|
130 |
+
heading_score += 20 # تأكد من وجود H1
|
131 |
+
heading_score += min(headings['h2'], 3) * 5 # حتى 3 عناوين H2
|
132 |
+
heading_score += min(headings['h3'], 3) * 3 # حتى 3 عناوين H3
|
133 |
+
|
134 |
# تحليل الروابط
|
135 |
links = soup.find_all('a')
|
136 |
internal_links = len([link for link in links if urlparse(link.get('href', '')).netloc == urlparse(url).netloc])
|
|
|
139 |
# تحليل الصور
|
140 |
images = soup.find_all('img')
|
141 |
images_without_alt = len([img for img in images if not img.get('alt')])
|
142 |
+
images_alt_score = max(0, 100 - (images_without_alt * 5)) # خصم 5 نقاط لكل صورة بدون Alt
|
143 |
+
|
144 |
+
# تحليل العنوان والوصف
|
145 |
+
title = soup.title.string if soup.title else "لا يوجد عنوان"
|
146 |
+
meta_description = soup.find("meta", {"name": "description"}) or soup.find("meta", {"property": "og:description"})
|
147 |
+
description_text = meta_description.get("content") if meta_description else "لا يوجد وصف"
|
148 |
+
|
149 |
+
# حساب نقاط العنوان والوصف
|
150 |
+
title_score = 0
|
151 |
+
if title and len(title) > 10 and len(title) <= 60:
|
152 |
+
title_score = 20
|
153 |
+
|
154 |
+
description_score = 0
|
155 |
+
if description_text != "لا يوجد وصف" and 70 <= len(description_text) <= 160:
|
156 |
+
description_score = 20
|
157 |
+
|
158 |
+
# حساب النقاط الإجمالية
|
159 |
+
total_seo_score = heading_score + images_alt_score + title_score + description_score
|
160 |
|
161 |
return {
|
162 |
+
"title": {
|
163 |
+
"text": title,
|
164 |
+
"score": title_score,
|
165 |
+
"recommendation": "يجب أن يكون العنوان بين 10-60 حرفًا" if title_score == 0 else "العنوان مثالي"
|
166 |
+
},
|
167 |
+
"meta_description": {
|
168 |
+
"text": description_text,
|
169 |
+
"score": description_score,
|
170 |
+
"recommendation": "يجب أن يكون الوصف بين 70-160 حرفًا" if description_score == 0 else "الوصف مثالي"
|
171 |
+
},
|
172 |
+
"headings": {
|
173 |
+
"details": headings,
|
174 |
+
"score": heading_score,
|
175 |
+
"recommendation": "تأكد من وجود عنوان H1 واستخدم العناوين الفرعية بشكل هرمي"
|
176 |
+
},
|
177 |
+
"internal_links": {
|
178 |
+
"count": internal_links,
|
179 |
+
"score": min(internal_links, 20),
|
180 |
+
"recommendation": "الروابط الداخلية جيدة للتنقل وتحسين SEO"
|
181 |
+
},
|
182 |
+
"external_links": {
|
183 |
+
"count": external_links,
|
184 |
+
"recommendation": "استخدم الروابط الخارجية بحكمة للمصداقية"
|
185 |
+
},
|
186 |
+
"images": {
|
187 |
+
"total": len(images),
|
188 |
+
"without_alt": images_without_alt,
|
189 |
+
"alt_score": images_alt_score,
|
190 |
+
"recommendation": f"أضف نص بديل لـ {images_without_alt} صورة"
|
191 |
+
},
|
192 |
+
"total_seo_score": {
|
193 |
+
"score": total_seo_score,
|
194 |
+
"max_score": 100,
|
195 |
+
"grade": (
|
196 |
+
"ممتاز" if total_seo_score >= 80 else
|
197 |
+
"جيد" if total_seo_score >= 60 else
|
198 |
+
"متوسط" if total_seo_score >= 40 else
|
199 |
+
"ضعيف"
|
200 |
+
)
|
201 |
+
}
|
202 |
}
|
203 |
except Exception as e:
|
204 |
return {"error": str(e)}
|
|
|
296 |
with cols[1]:
|
297 |
st.metric("حجم الصفحة", f"{performance_data.get('page_size', 'N/A')} KB")
|
298 |
with cols[2]:
|
299 |
+
st.metric("الروابط الداخلية", seo_data.get('internal_links', 'N/A')['count'])
|
300 |
|
301 |
# عرض تحليل SEO
|
302 |
with st.expander("تحليل SEO", expanded=True):
|
303 |
st.json(seo_data)
|
304 |
|
305 |
# رسم بياني للعناوين
|
306 |
+
if 'headings' in seo_data and 'details' in seo_data['headings']:
|
307 |
fig = px.bar(
|
308 |
+
x=list(seo_data['headings']['details'].keys()),
|
309 |
+
y=list(seo_data['headings']['details'].values()),
|
310 |
title="توزيع العناوين",
|
311 |
labels={'x': 'نوع العنوان', 'y': 'العدد'}
|
312 |
)
|