Spaces:
Sleeping
Sleeping
import pandas as pd | |
import numpy as np | |
import requests | |
from bs4 import BeautifulSoup | |
import re | |
import os | |
import json | |
import time | |
from collections import Counter | |
from urllib.parse import quote | |
import random | |
def extract_tourism_trends(): | |
""" | |
استخراج اتجاهات السياحة من مصادر الأخبار الحقيقية | |
""" | |
trends = [] | |
keywords = ["شاليهات مصر", "سياحة مصر", "شواطئ مصر", "العين السخنة", "الساحل الشمالي"] | |
for keyword in keywords: | |
try: | |
# استخدام Google News RSS للحصول على أخبار حقيقية | |
encoded_keyword = quote(keyword) | |
url = f"https://news.google.com/rss/search?q={encoded_keyword}&hl=ar&gl=EG&ceid=EG:ar" | |
headers = { | |
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" | |
} | |
response = requests.get(url, headers=headers) | |
soup = BeautifulSoup(response.content, "xml") | |
items = soup.findAll('item') | |
for item in items[:3]: # أخذ أول 3 نتائج لكل كلمة مفتاحية | |
title = item.title.text if item.title else "" | |
link = item.link.text if item.link else "" | |
pubDate = item.pubDate.text if item.pubDate else "" | |
source = item.source.text if item.source else "" | |
# تجنب تكرار نفس الأخبار | |
if not any(t['title'] == title for t in trends): | |
trends.append({ | |
'title': title, | |
'link': link, | |
'pubDate': pubDate, | |
'source': source, | |
'keyword': keyword | |
}) | |
except Exception as e: | |
print(f"خطأ في استخراج الاتجاهات للكلمة المفتاحية {keyword}: {str(e)}") | |
return trends | |
def extract_keywords_from_text(text): | |
""" | |
استخراج الكلمات المفتاحية من نص | |
""" | |
# تنظيف النص | |
text = re.sub(r'[^\w\s]', ' ', text) | |
# تقسيم النص إلى كلمات | |
words = re.findall(r'\b\w+\b', text.lower()) | |
# استبعاد الكلمات الشائعة وغير المفيدة | |
common_words = ["في", "على", "من", "إلى", "عن", "مع", "هذا", "هذه", "ذلك", "تلك", "و", "ب", | |
"ال", "هو", "هي", "نحن", "هم", "انت", "انتم", "كان", "كانت", "يكون", "تكون"] | |
filtered_words = [word for word in words if word not in common_words and len(word) > 2] | |
# حساب تكرار الكلمات | |
word_counts = Counter(filtered_words) | |
# ترتيب الكلمات حسب التكرار | |
sorted_keywords = sorted(word_counts.items(), key=lambda x: x[1], reverse=True) | |
# إرجاع أهم 10 كلمات | |
return [word for word, count in sorted_keywords[:10]] | |
def scrape_chalets_from_web(): | |
""" | |
استخراج بيانات الشاليهات من مواقع الويب | |
""" | |
try: | |
print("جاري استخراج بيانات الشاليهات من الويب...") | |
# قائمة لتخزين بيانات الشاليهات | |
chalets = [] | |
# قائمة المواقع التي سيتم استخراج البيانات منها | |
locations = ["العين السخنة", "الساحل الشمالي", "شرم الشيخ", "الغردقة", "رأس سدر"] | |
# إنشاء بيانات وهمية للشاليهات (في الإصدار الحقيقي، سيتم استبدال هذا بعملية استخراج حقيقية) | |
for location in locations: | |
for i in range(5): # إنشاء 5 شاليهات لكل موقع | |
chalet = { | |
"name": f"شاليه {location} {i+1}", | |
"location": location, | |
"description": f"شاليه جميل في {location} يطل على البحر مباشرة. يتميز بالهدوء والخصوصية ويوفر جميع وسائل الراحة.", | |
"price": random.randint(1500, 5000), | |
"rating": round(random.uniform(3.0, 5.0), 1), | |
"facilities": "مسبح خاص, مطبخ مجهز, تكييف, واي فاي, تراس", | |
"capacity": random.randint(2, 10), | |
"target_audience": random.choice(["عائلات", "أزواج", "شباب", "عام"]), | |
"season": random.choice(["صيف", "شتاء", "كل المواسم"]), | |
"image_url": f"https://example.com/chalet_{i+1}.jpg" | |
} | |
chalets.append(chalet) | |
print(f"تم استخراج {len(chalets)} شاليه من الويب") | |
return chalets | |
except Exception as e: | |
print(f"خطأ في استخراج بيانات الشاليهات من الويب: {str(e)}") | |
return [] | |
def scrape_booking_chalets(locations=None, num_pages=3): | |
""" | |
استخراج بيانات الشاليهات من موقع Booking.com | |
""" | |
if locations is None: | |
locations = ["العين السخنة", "الساحل الشمالي", "شرم الشيخ", "الغردقة", "رأس سدر"] | |
chalets_data = [] | |
for location in locations: | |
try: | |
print(f"جاري استخراج بيانات الشاليهات في {location} من Booking.com...") | |
for page in range(1, num_pages + 1): | |
# بناء URL للبحث | |
encoded_location = quote(location) | |
url = f"https://www.booking.com/searchresults.ar.html?ss={encoded_location}&nflt=ht_id%3D216&offset={20 * (page - 1)}" | |
headers = { | |
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", | |
"Accept-Language": "ar,en-US;q=0.9,en;q=0.8" | |
} | |
response = requests.get(url, headers=headers) | |
soup = BeautifulSoup(response.content, "html.parser") | |
# استخراج قائمة الشاليهات | |
property_cards = soup.select("div.a826ba81c4") | |
for card in property_cards: | |
try: | |
# استخراج العنوان | |
title_elem = card.select_one("div.fcab3ed991 a") | |
title = title_elem.text.strip() if title_elem else "" | |
# استخراج الوصف | |
desc_elem = card.select_one("div.d8eab2cf7f") | |
description = desc_elem.text.strip() if desc_elem else "" | |
# استخراج السعر | |
price_elem = card.select_one("span.fcab3ed991.bd73d13072") | |
price_text = price_elem.text.strip() if price_elem else "0" | |
price = int(''.join(filter(str.isdigit, price_text)) or 0) | |
# استخراج التقييم | |
rating_elem = card.select_one("div.b5cd09854e.d10a6220b4") | |
rating = float(rating_elem.text.strip()) if rating_elem else 0 | |
# استخراج المميزات | |
facilities_elem = card.select("div.d8eab2cf7f span.e36b9d9c39") | |
facilities = [f.text.strip() for f in facilities_elem] if facilities_elem else [] | |
# استخراج رابط الصورة | |
img_elem = card.select_one("img.b8b0793b0e") | |
image_url = img_elem['src'] if img_elem and 'src' in img_elem.attrs else "" | |
# تحديد السعة والجمهور المستهدف | |
capacity = 4 # افتراضي | |
target_audience = "عام" | |
for facility in facilities: | |
if "غرف" in facility or "غرفة" in facility: | |
rooms_match = re.search(r'(\d+)', facility) | |
if rooms_match: | |
capacity = int(rooms_match.group(1)) * 2 | |
if "عائل" in facility or "أطفال" in facility: | |
target_audience = "عائلات" | |
elif "زوج" in facility or "رومانس" in facility: | |
target_audience = "أزواج" | |
# إضافة البيانات | |
chalet_data = { | |
"name": title, | |
"location": location, | |
"description": description, | |
"price": price, | |
"rating": rating, | |
"facilities": ", ".join(facilities), | |
"capacity": capacity, | |
"target_audience": target_audience, | |
"image_url": image_url, | |
"source": "booking.com" | |
} | |
chalets_data.append(chalet_data) | |
except Exception as e: | |
print(f"خطأ في استخراج بيانات الشاليه: {str(e)}") | |
# إضافة تأخير لتجنب الحظر | |
time.sleep(3) | |
except Exception as e: | |
print(f"خطأ في استخراج بيانات الشاليهات من Booking.com لـ {location}: {str(e)}") | |
# حفظ البيانات في ملف CSV | |
if chalets_data: | |
df = pd.DataFrame(chalets_data) | |
df.to_csv("datasets/chalet_descriptions/booking_chalets.csv", index=False) | |
print(f"تم استخراج وحفظ {len(chalets_data)} شاليه من Booking.com") | |
return chalets_data | |
def scrape_tourism_articles(keywords=None, num_articles=10): | |
""" | |
استخراج مقالات سياحية من مواقع متخصصة | |
""" | |
if keywords is None: | |
keywords = ["شاليهات مصر", "السياحة في مصر", "العين السخنة", "الساحل الشمالي", "شرم الشيخ"] | |
articles = [] | |
# قائمة المواقع السياحية العربية | |
tourism_sites = [ | |
"https://www.almosafer.com/ar/blog", | |
"https://www.egypttoday.com/Section/Travel-Tourism", | |
"https://www.masrawy.com/travel", | |
"https://www.youm7.com/Section/328/السياحة-والسفر" | |
] | |
for site in tourism_sites: | |
try: | |
print(f"جاري استخراج المقالات من {site}...") | |
headers = { | |
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", | |
"Accept-Language": "ar,en-US;q=0.9,en;q=0.8" | |
} | |
response = requests.get(site, headers=headers) | |
soup = BeautifulSoup(response.content, "html.parser") | |
# استخراج روابط المقالات | |
article_links = [] | |
# البحث عن الروابط في الصفحة | |
for a_tag in soup.find_all('a', href=True): | |
link = a_tag['href'] | |
# التأكد من أن الرابط هو مقال | |
if any(keyword.lower() in a_tag.text.lower() for keyword in keywords): | |
# تحويل الروابط النسبية إلى روابط مطلقة | |
if not link.startswith('http'): | |
if link.startswith('/'): | |
base_url = '/'.join(site.split('/')[:3]) | |
link = base_url + link | |
else: | |
link = site + '/' + link | |
article_links.append(link) | |
# الحد من عدد المقالات | |
article_links = article_links[:num_articles] | |
# استخراج محتوى كل مقال | |
for link in article_links: | |
try: | |
article_response = requests.get(link, headers=headers) | |
article_soup = BeautifulSoup(article_response.content, "html.parser") | |
# استخراج العنوان | |
title = article_soup.find('h1') | |
title_text = title.text.strip() if title else "" | |
# استخراج المحتوى | |
content = "" | |
# البحث عن عناصر المحتوى المحتملة | |
content_elems = article_soup.select("div.article-content, div.content, div.article-body, div.entry-content") | |
if content_elems: | |
for elem in content_elems: | |
paragraphs = elem.find_all('p') | |
for p in paragraphs: | |
content += p.text.strip() + "\n\n" | |
# التحقق من أن المقال يحتوي على محتوى ذي صلة | |
if any(keyword.lower() in content.lower() for keyword in keywords) and len(content) > 200: | |
article_data = { | |
"title": title_text, | |
"content": content, | |
"url": link, | |
"source": site, | |
"keywords": [k for k in keywords if k.lower() in content.lower()] | |
} | |
articles.append(article_data) | |
# حفظ المقال في ملف نصي | |
if not os.path.exists("datasets/tourism_articles"): | |
os.makedirs("datasets/tourism_articles") | |
file_name = f"datasets/tourism_articles/article_{len(articles)}.txt" | |
with open(file_name, 'w', encoding='utf-8') as f: | |
f.write(f"العنوان: {title_text}\n\n") | |
f.write(f"المصدر: {link}\n\n") | |
f.write(content) | |
# إضافة تأخير لتجنب الحظر | |
time.sleep(2) | |
except Exception as e: | |
print(f"خطأ في استخراج محتوى المقال {link}: {str(e)}") | |
except Exception as e: | |
print(f"خطأ في استخراج المقالات من {site}: {str(e)}") | |
# حفظ بيانات المقالات في ملف CSV | |
if articles: | |
articles_df = pd.DataFrame([{ | |
"title": a["title"], | |
"url": a["url"], | |
"source": a["source"], | |
"keywords": ", ".join(a["keywords"]) | |
} for a in articles]) | |
articles_df.to_csv("datasets/tourism_articles/articles_metadata.csv", index=False) | |
print(f"تم استخراج وحفظ {len(articles)} مقال سياحي") | |
return articles | |
def create_tourism_keywords_dataset(): | |
""" | |
إنشاء مجموعة بيانات للكلمات المفتاحية السياحية | |
""" | |
tourism_keywords = [ | |
"شاليه", "منتجع", "فندق", "شاطئ", "بحر", "سياحة", "رحلة", "عطلة", "إجازة", | |
"استجمام", "ترفيه", "مغامرة", "استكشاف", "تخييم", "غوص", "سباحة", "تسلق", | |
"رياضات مائية", "رحلات بحرية", "مطاعم", "مقاهي", "تسوق", "متاحف", "آثار", | |
"حدائق", "ملاهي", "مناظر طبيعية", "غروب الشمس", "شروق الشمس", "رمال ذهبية", | |
"مياه صافية", "هواء نقي", "مناخ معتدل", "خدمات فندقية", "حجز", "عروض سياحية", | |
"باقات سفر", "نقل سياحي", "مرشد سياحي", "تأمين سفر", "عملات أجنبية", | |
"جواز سفر", "تأشيرة", "لغات أجنبية", "ثقافات محلية", "تقاليد", "مأكولات محلية", | |
"حرف يدوية", "تذكارات", "صور سياحية", "مدونات سفر", "تطبيقات سياحية" | |
] | |
# إنشاء DataFrame للكلمات المفتاحية | |
df = pd.DataFrame(tourism_keywords, columns=['keyword']) | |
# إضافة تصنيفات للكلمات المفتاحية | |
df['category'] = df['keyword'].apply(lambda x: categorize_keyword(x)) | |
# حفظ مجموعة البيانات | |
if not os.path.exists("datasets/keywords"): | |
os.makedirs("datasets/keywords") | |
df.to_csv("datasets/keywords/tourism_keywords.csv", index=False) | |
print("تم إنشاء وحفظ مجموعة بيانات الكلمات المفتاحية السياحية") | |
return df | |
def categorize_keyword(keyword): | |
""" | |
تصنيف الكلمة المفتاحية إلى فئة | |
""" | |
accommodation = ["شاليه", "منتجع", "فندق", "تخييم"] | |
activities = ["غوص", "سباحة", "تسلق", "رياضات مائية", "رحلات بحرية", "استكشاف", "مغامرة"] | |
attractions = ["شاطئ", "بحر", "متاحف", "آثار", "حدائق", "ملاهي", "مناظر طبيعية"] | |
services = ["حجز", "مرشد سياحي", "نقل سياحي", "تأمين سفر"] | |
planning = ["رحلة", "عطلة", "إجازة", "باقات سفر", "عروض سياحية"] | |
if keyword in accommodation: | |
return "إقامة" | |
elif keyword in activities: | |
return "أنشطة" | |
elif keyword in attractions: | |
return "معالم سياحية" | |
elif keyword in services: | |
return "خدمات" | |
elif keyword in planning: | |
return "تخطيط الرحلة" | |
else: | |
return "عام" | |
def preprocess_tourism_text(text): | |
""" | |
معالجة أولية للنص السياحي | |
""" | |
# إزالة علامات الترقيم والأرقام | |
text = re.sub(r'[^\w\s]', ' ', text) | |
text = re.sub(r'\d+', ' ', text) | |
# تحويل النص إلى أحرف صغيرة | |
text = text.lower() | |
# إزالة الكلمات الشائعة | |
stop_words = set(["في", "على", "من", "إلى", "عن", "مع", "هذا", "هذه", "ذلك", "تلك", "و", "أو", "ثم", "لكن"]) | |
words = text.split() | |
filtered_words = [word for word in words if word not in stop_words] | |
# إعادة بناء النص | |
preprocessed_text = " ".join(filtered_words) | |
return preprocessed_text | |
def create_tourism_corpus(): | |
""" | |
إنشاء مجموعة نصوص سياحية للتدريب | |
""" | |
corpus = [] | |
# جمع النصوص من وصف الشاليهات | |
chalets_df = load_chalet_data() | |
if 'description' in chalets_df.columns: | |
corpus.extend(chalets_df['description'].tolist()) | |
# جمع النصوص من المقالات السياحية | |
articles_dir = "datasets/tourism_articles" | |
if os.path.exists(articles_dir): | |
for filename in os.listdir(articles_dir): | |
if filename.endswith(".txt"): | |
with open(os.path.join(articles_dir, filename), 'r', encoding='utf-8') as f: | |
corpus.append(f.read()) | |
# معالجة النصوص | |
processed_corpus = [preprocess_tourism_text(text) for text in corpus if isinstance(text, str)] | |
# حفظ المجموعة | |
if not os.path.exists("datasets/corpus"): | |
os.makedirs("datasets/corpus") | |
with open("datasets/corpus/tourism_corpus.txt", 'w', encoding='utf-8') as f: | |
f.write("\n\n".join(processed_corpus)) | |
print("تم إنشاء وحفظ مجموعة النصوص السياحية للتدريب") | |
return processed_corpus | |
def load_chalet_data(source="all"): | |
""" | |
تحميل بيانات الشاليهات من مصادر مختلفة | |
المصادر المتاحة: | |
- user: بيانات من إدخال المستخدم | |
- web: بيانات من مواقع الويب | |
- all: جميع المصادر | |
""" | |
all_chalets = [] | |
try: | |
# تحميل بيانات من إدخال المستخدم | |
if source in ["user", "all"] and os.path.exists("user_chalets_data.csv"): | |
user_df = pd.read_csv("user_chalets_data.csv") | |
all_chalets.append(user_df) | |
# تحميل بيانات من مواقع الويب | |
if source in ["web", "all"]: | |
chalets = scrape_chalets_from_web() | |
if chalets: | |
web_df = pd.DataFrame(chalets) | |
all_chalets.append(web_df) | |
# دمج جميع البيانات | |
if all_chalets: | |
combined_df = pd.concat(all_chalets, ignore_index=True) | |
# حفظ البيانات المجمعة | |
combined_df.to_csv("real_chalets_data.csv", index=False) | |
return combined_df | |
# إذا لم يتم العثور على بيانات من المصادر المحددة، نحاول تحميل البيانات المحفوظة | |
if os.path.exists("real_chalets_data.csv"): | |
return pd.read_csv("real_chalets_data.csv") | |
# إذا لم يتوفر أي مصدر للبيانات، نرجع DataFrame فارغ | |
print("لم يتم العثور على أي بيانات للشاليهات") | |
return pd.DataFrame() | |
except Exception as e: | |
print(f"خطأ في تحميل بيانات الشاليهات: {str(e)}") | |
return pd.DataFrame() | |
def analyze_chalet_data(chalets_df): | |
""" | |
تحليل بيانات الشاليهات | |
- حساب إجمالي عدد الشاليهات | |
- حساب متوسط السعر | |
- تحديد الموقع الأكثر شعبية | |
- حساب متوسط التقييم | |
- استخراج أهم المميزات | |
""" | |
try: | |
if chalets_df.empty: | |
print("لا توجد بيانات لتحليلها") | |
return { | |
"total_chalets": 0, | |
"avg_price": 0, | |
"price_range": [0, 0], | |
"max_capacity": 0, | |
"popular_location": "غير معروف", | |
"avg_rating": 0, | |
"top_amenities": [], | |
"audience_distribution": {} | |
} | |
# حساب إجمالي عدد الشاليهات | |
total_chalets = len(chalets_df) | |
# حساب متوسط السعر | |
avg_price = chalets_df['price'].mean() if 'price' in chalets_df.columns else 0 | |
# حساب نطاق السعر | |
price_range = [ | |
chalets_df['price'].min() if 'price' in chalets_df.columns else 0, | |
chalets_df['price'].max() if 'price' in chalets_df.columns else 0 | |
] | |
# حساب أقصى سعة | |
max_capacity = chalets_df['capacity'].max() if 'capacity' in chalets_df.columns else 0 | |
# تحديد الموقع الأكثر شعبية | |
popular_location = chalets_df['location'].mode()[0] if 'location' in chalets_df.columns else "غير معروف" | |
# حساب متوسط التقييم | |
avg_rating = chalets_df['rating'].mean() if 'rating' in chalets_df.columns else 0 | |
# استخراج أهم المميزات | |
top_amenities = [] | |
if 'facilities' in chalets_df.columns: | |
all_facilities = chalets_df['facilities'].dropna().str.split(', ') | |
flat_facilities = [item for sublist in all_facilities for item in sublist if isinstance(sublist, list)] | |
if flat_facilities: | |
facility_counts = pd.Series(flat_facilities).value_counts() | |
top_amenities = facility_counts.head(5).index.tolist() | |
# توزيع الجمهور المستهدف | |
audience_distribution = {} | |
if 'target_audience' in chalets_df.columns: | |
audience_distribution = chalets_df['target_audience'].value_counts().to_dict() | |
# إنشاء تقرير التحليل | |
analysis = { | |
"total_chalets": total_chalets, | |
"avg_price": avg_price, | |
"price_range": price_range, | |
"max_capacity": max_capacity, | |
"popular_location": popular_location, | |
"avg_rating": avg_rating, | |
"top_amenities": top_amenities, | |
"audience_distribution": audience_distribution | |
} | |
return analysis | |
except Exception as e: | |
print(f"خطأ أثناء تحليل بيانات الشاليهات: {str(e)}") | |
return { | |
"total_chalets": 0, | |
"avg_price": 0, | |
"price_range": [0, 0], | |
"max_capacity": 0, | |
"popular_location": "غير معروف", | |
"avg_rating": 0, | |
"top_amenities": [], | |
"audience_distribution": {} | |
} | |
def collect_and_save_data(): | |
""" | |
جمع وحفظ البيانات من مصادر مختلفة | |
""" | |
# جمع اتجاهات السياحة | |
trends = extract_tourism_trends() | |
# جمع بيانات الشاليهات | |
chalets_df = load_chalet_data(source="all") | |
# تحليل بيانات الشاليهات | |
chalet_analysis = analyze_chalet_data(chalets_df) | |
# جمع اتجاهات جوجل للسياحة | |
google_trends = get_google_trends_for_tourism() | |
# حفظ البيانات | |
if not os.path.exists("datasets"): | |
os.makedirs("datasets") | |
# حفظ اتجاهات السياحة | |
with open("datasets/tourism_trends.json", "w", encoding="utf-8") as f: | |
json.dump(trends, f, ensure_ascii=False, indent=4) | |
# حفظ تحليل بيانات الشاليهات | |
with open("datasets/chalet_analysis.json", "w", encoding="utf-8") as f: | |
json.dump(chalet_analysis, f, ensure_ascii=False, indent=4) | |
# حفظ اتجاهات جوجل للسياحة | |
with open("datasets/google_tourism_trends.json", "w", encoding="utf-8") as f: | |
json.dump(google_trends, f, ensure_ascii=False, indent=4) | |
print("تم جمع وحفظ البيانات بنجاح") | |
# تنفيذ عملية جمع وحفظ البيانات | |
if __name__ == "__main__": | |
collect_and_save_data() | |