import requests from bs4 import BeautifulSoup import re from urllib.parse import urljoin, urlparse def scrape_article_url(url: str) -> dict: """ Scrapes a webpage URL and extracts: - title - content (main body text) - author - image (cover image) - category """ 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" } try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() # Detect encoding if response.encoding == 'ISO-8859-1': response.encoding = response.apparent_encoding soup = BeautifulSoup(response.text, "html.parser") # 1. Extract Title title = "" # Try og:title first og_title = soup.find("meta", property="og:title") if og_title and og_title.get("content"): title = og_title["content"] else: # Try

h1 = soup.find("h1") if h1: title = h1.get_text().strip() else: title_tag = soup.find("title") if title_tag: title = title_tag.get_text().strip() if not title: title = "مقال مستخلص من الويب" # 2. Extract Author author = "كاتب ويب" author_meta = soup.find("meta", attrs={"name": "author"}) or soup.find("meta", property="article:author") if author_meta and author_meta.get("content"): author = author_meta["content"].strip() else: # Search for typical author classes author_tag = soup.find(class_=re.compile(r"author|byline|writer", re.I)) if author_tag: author = author_tag.get_text().strip() # 3. Extract Cover Image image_url = "https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=600&auto=format&fit=crop&q=60" # default og_image = soup.find("meta", property="og:image") if og_image and og_image.get("content"): image_url = og_image["content"] else: # Try finding the first large image in body for img in soup.find_all("img"): src = img.get("src") if src and not src.endswith(".gif") and not src.endswith(".svg"): # Resolve relative url image_url = urljoin(url, src) break # 4. Extract Main Content # Remove noisy elements for element in soup(["script", "style", "nav", "footer", "header", "aside", "form"]): element.extract() # Find paragraphs paragraphs = soup.find_all("p") text_blocks = [] for p in paragraphs: text = p.get_text().strip() # Ignore short/noise paragraphs (less than 30 characters) if len(text) > 30: text_blocks.append(text) content = "\n\n".join(text_blocks) if not content: # Fallback: get raw body text if no paragraphs are found content = soup.body.get_text(separator="\n\n").strip() if soup.body else "تعذر استخلاص محتوى النص من هذا الموقع." # Limit length if it's too raw and full of noise content = content[:3000] # 5. Extract/Guess Category or Domain Name domain = urlparse(url).netloc.replace("www.", "") category = domain.split(".")[0].capitalize() return { "title": title, "content": content, "author": author, "image": image_url, "category": category } except Exception as e: import traceback traceback.print_exc() print(f"Scraping error: {e}") return { "title": "فشل جلب المقال", "content": f"حدث خطأ أثناء محاولة الاتصال بالموقع أو جلب محتواه:\n{str(e)}", "author": "خطأ النظام", "image": "https://images.unsplash.com/photo-1594322436404-5a0526db4d13?w=600&auto=format&fit=crop&q=60", "category": "خطأ" }