🎯 מה זה Web Scraping ולמה זה שימושי?
Web Scraping הוא תהליך אוטומטי של איסוף מידע מאתרי אינטרנט. במקום להעתיק ידנית מידע מאתרים - אתה כותב תוכנה שעושה את זה בשבילך.
למה להנדסאי רכב/מכונות זה חשוב?
לגרוף מחירי חלפים מעשרות אתרים בדקות במקום שעות של חיפוש ידני.
לאסוף מפרטים טכניים של מאות רכיבים/מכונות בקליק אחד.
לאסוף אלפי ביקורות רכב/ציוד ולנתח מה הבעיות השכיחות.
לעקוב אחרי שינויי מחירים, מלאי, דגמים חדשים - אוטומטית.
לפני: אתה מחפש רפידות בלמים ל-Toyota Corolla 2020 ב-10 אתרים שונים. לוקח שעה.
עם Scraping: הסקריפט בודק 50 אתרים ב-2 דקות, מציג טבלה עם המחיר הזול ביותר.
Web Scraping הוא חוקי אבל צריך לעשות אותו אחראית:
- לא להציף שרתים בבקשות (יש לשמור על rate limiting)
- לכבד את תנאי השימוש של האתר
- לא לגרוף מידע אישי של אנשים
- לבדוק את ה-robots.txt של האתר
נדון בזה לעומק בטאב "חוקיות".
💡 חומר למחשבה
האם ידעת ש... גוגל עצמה מבוססת על Web Scraping? הם "זוחלים" (crawling) על כל האינטרנט כדי לאנדקס אותו. אתה עושה בעצם את אותו הדבר, רק בקנה מידה קטן יותר!
🛠️ הכלים שנשתמש בהם
-
1Python
שפת התכנות הפופולרית ביותר ל-scraping. קלה ללמידה, עוצמתית.
-
2Requests
ספרייה לשליחת בקשות HTTP - כדי "לבקר" באתרים.
-
3Beautiful Soup
ספרייה לניתוח HTML - לחלץ את המידע שאתה רוצה מהדף.
-
4Pandas
לניהול וניתוח הנתונים שאספת.
-
5Selenium (מתקדם)
לאתרים דינמיים עם JavaScript - יוצר דפדפן אוטומטי.
התקנה ראשונית (פעם אחת)
pip install requests beautifulsoup4 pandas lxml selenium
🔧 יסודות Web Scraping
תהליך עבודה שלב אחר שלב
שלב 1: לשלוח בקשה לאתר
import requests
# שליחת בקשה GET
url = "https://example.com/products"
response = requests.get(url)
# בדיקת תקינות
if response.status_code == 200:
print("הבקשה הצליחה!")
html_content = response.text
else:
print(f"שגיאה: {response.status_code}")
שלב 2: לנתח את ה-HTML
from bs4 import BeautifulSoup
# יצירת soup object
soup = BeautifulSoup(html_content, 'lxml')
# מציאת אלמנטים
# לפי תגית
all_links = soup.find_all('a')
# לפי class
products = soup.find_all('div', class_='product')
# לפי id
main_content = soup.find(id='main-content')
# CSS selector (מתקדם)
prices = soup.select('.product .price')
שלב 3: לחלץ מידע
# לחלץ טקסט
product_name = soup.find('h2', class_='title').text.strip()
# לחלץ attribute
image_url = soup.find('img')['src']
link = soup.find('a')['href']
# לחלץ ממספר אלמנטים
products = []
for item in soup.find_all('div', class_='product'):
name = item.find('h3').text.strip()
price = item.find('span', class_='price').text.strip()
products.append({'name': name, 'price': price})
print(products)
שלב 4: לשמור את הנתונים
import pandas as pd
# המרה ל-DataFrame
df = pd.DataFrame(products)
# שמירה ל-CSV
df.to_csv('products.csv', index=False, encoding='utf-8-sig')
print("הנתונים נשמרו בהצלחה!")
לפני שכותבים קוד, פתח את האתר בדפדפן → לחץ F12 → Inspect Element.
זה יראה לך את ה-HTML ותוכל למצוא את ה-classes וה-tags הנכונים.
⚠️ רגע, עצור!
לפני שתמשיך... זכור שאתרים משתנים כל הזמן! הקוד שעובד היום עלול להפסיק לעבוד מחר אם האתר שינה את המבנה. תמיד בדוק ותתחזק את הקוד שלך!
📝 דוגמה מלאה - גריפת מחירי מוצר
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
def scrape_prices(search_term):
"""
גורף מחירים מאתר דמה
"""
# הוסף user agent (מתחזה לדפדפן רגיל)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
url = f"https://example-shop.com/search?q={search_term}"
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'lxml')
results = []
products = soup.find_all('div', class_='product-item')
for product in products:
name = product.find('h3', class_='product-name').text.strip()
price_text = product.find('span', class_='price').text.strip()
# נקה מחיר (הסר ₪, רווחים וכו')
price = float(price_text.replace('₪', '').replace(',', '').strip())
rating = product.find('span', class_='rating').text.strip()
link = product.find('a')['href']
results.append({
'שם_מוצר': name,
'מחיר': price,
'דירוג': rating,
'קישור': link
})
return results
except Exception as e:
print(f"שגיאה: {e}")
return []
# שימוש
products = scrape_prices("brake pads toyota corolla")
# המרה ל-DataFrame
df = pd.DataFrame(products)
# מיון לפי מחיר
df = df.sort_values('מחיר')
# הצגה
print(df)
# שמירה
df.to_csv('brake_pads_prices.csv', index=False, encoding='utf-8-sig')
# המחיר הזול ביותר
cheapest = df.iloc[0]
print(f"\nהזול ביותר: {cheapest['שם_מוצר']} - {cheapest['מחיר']} ₪")
🚗 דוגמאות מעשיות - רכב
5 תרחישים אמיתיים עם קוד מוכן לשימוש
1. גריפת מחירי חלפים ממספר ספקים
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
def scrape_multiple_suppliers(part_name, car_model):
"""
גורף מחירי חלק מספקים שונים
"""
suppliers = {
'supplier_a': 'https://supplier-a.com/search',
'supplier_b': 'https://supplier-b.com/parts',
'supplier_c': 'https://supplier-c.com/catalog'
}
all_results = []
for supplier_name, base_url in suppliers.items():
try:
# הוסף delay בין בקשות (מנומס!)
time.sleep(2)
url = f"{base_url}?part={part_name}&model={car_model}"
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
if response.status_code == 200:
soup = BeautifulSoup(response.content, 'lxml')
# כאן תתאים את הסלקטורים לכל ספק
items = soup.find_all('div', class_='item')
for item in items:
name = item.find('h3').text.strip()
price = float(item.find('span', class_='price').text.replace('₪', '').strip())
stock = item.find('span', class_='stock').text.strip()
all_results.append({
'ספק': supplier_name,
'שם_חלק': name,
'מחיר': price,
'מלאי': stock
})
except Exception as e:
print(f"שגיאה בגריפה מ-{supplier_name}: {e}")
return pd.DataFrame(all_results)
# שימוש
df = scrape_multiple_suppliers("brake pads", "Toyota Corolla 2020")
# מיון לפי מחיר
df_sorted = df.sort_values('מחיר')
print("=== השוואת מחירים ===")
print(df_sorted)
# סטטיסטיקות
print(f"\nמחיר ממוצע: {df['מחיר'].mean():.2f} ₪")
print(f"מחיר מינימלי: {df['מחיר'].min():.2f} ₪")
print(f"מחיר מקסימלי: {df['מחיר'].max():.2f} ₪")
print(f"הבדל: {df['מחיר'].max() - df['מחיר'].min():.2f} ₪")
2. איסוף ביקורות רכב לניתוח
from collections import Counter
import re
def scrape_car_reviews(car_model, max_pages=5):
"""
אוסף ביקורות רכב ומנתח תלונות שכיחות
"""
reviews = []
for page in range(1, max_pages + 1):
url = f"https://car-reviews-site.com/{car_model}/reviews?page={page}"
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
soup = BeautifulSoup(response.content, 'lxml')
review_elements = soup.find_all('div', class_='review')
for review in review_elements:
rating = review.find('span', class_='rating').text
text = review.find('p', class_='review-text').text.strip()
pros = review.find('div', class_='pros').text.strip()
cons = review.find('div', class_='cons').text.strip()
reviews.append({
'דירוג': rating,
'טקסט': text,
'יתרונות': pros,
'חסרונות': cons
})
time.sleep(1) # מנומס!
return pd.DataFrame(reviews)
def analyze_complaints(reviews_df):
"""
מנתח תלונות שכיחות
"""
# איחוד כל החסרונות
all_cons = ' '.join(reviews_df['חסרונות'].tolist())
# מילות מפתח לחיפוש
keywords = ['רעש', 'צריכה', 'בלמים', 'מנוע', 'תקלה', 'אבזור', 'נוחות']
keyword_count = {}
for keyword in keywords:
count = len(re.findall(keyword, all_cons, re.IGNORECASE))
keyword_count[keyword] = count
# מיון לפי תדירות
sorted_complaints = sorted(keyword_count.items(), key=lambda x: x[1], reverse=True)
print("\n=== תלונות שכיחות ===")
for complaint, count in sorted_complaints:
if count > 0:
print(f"{complaint}: {count} פעמים")
return keyword_count
# שימוש
reviews = scrape_car_reviews("mazda-3-2021")
complaints = analyze_complaints(reviews)
# סיכום
avg_rating = reviews['דירוג'].astype(float).mean()
print(f"\nדירוג ממוצע: {avg_rating:.2f}/5")
print(f"סה\"כ ביקורות: {len(reviews)}")
3. מעקב אחר מחירי רכבים יד שנייה
import datetime
def track_car_prices(model, year, max_km):
"""
עוקב אחרי מחירי רכבים יד שנייה
"""
url = f"https://yad2.co.il/vehicles/cars?manufacturer={model}&year={year}&km={max_km}"
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
soup = BeautifulSoup(response.content, 'lxml')
cars = []
listings = soup.find_all('div', class_='feeditem')
for listing in listings:
try:
title = listing.find('span', class_='title').text.strip()
price = int(listing.find('span', class_='price').text.replace('₪', '').replace(',', '').strip())
year = listing.find('span', class_='year').text.strip()
km = int(listing.find('span', class_='km').text.replace(',', '').strip())
location = listing.find('span', class_='city').text.strip()
cars.append({
'תאריך_סריקה': datetime.datetime.now().strftime('%Y-%m-%d'),
'כותרת': title,
'מחיר': price,
'שנה': year,
'קילומטראז': km,
'מיקום': location
})
except:
continue
df = pd.DataFrame(cars)
# שמירה עם תאריך
filename = f"car_prices_{datetime.datetime.now().strftime('%Y%m%d')}.csv"
df.to_csv(filename, index=False, encoding='utf-8-sig')
# סטטיסטיקות
print(f"=== סריקה ביום {datetime.datetime.now().strftime('%d/%m/%Y')} ===")
print(f"נמצאו: {len(cars)} רכבים")
print(f"מחיר ממוצע: {df['מחיר'].mean():,.0f} ₪")
print(f"מחיר מינימלי: {df['מחיר'].min():,.0f} ₪")
print(f"מחיר מקסימלי: {df['מחיר'].max():,.0f} ₪")
return df
# שימוש יומי (הרץ עם cron/task scheduler)
df = track_car_prices("Toyota", "2020", 100000)
# מעקב אחר שינויים לאורך זמן
# אפשר לטעון קבצים קודמים ולהשוות
⚙️ דוגמאות מעשיות - מכונות וציוד תעשייתי
1. השוואת מחירי כלי עבודה וציוד
def scrape_tool_prices(tool_name):
"""
גורף מחירי כלי עבודה מאתרים שונים
"""
# דוגמה: השוואת מקדחות CNC
sources = {
'aliexpress': f"https://aliexpress.com/wholesale?SearchText={tool_name}",
'amazon': f"https://amazon.com/s?k={tool_name}",
'ebay': f"https://ebay.com/sch/i.html?_nkw={tool_name}"
}
results = []
for source, url in sources.items():
time.sleep(2)
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
soup = BeautifulSoup(response.content, 'lxml')
# כל אתר יש structure שונה - צריך להתאים
if source == 'aliexpress':
items = soup.find_all('div', class_='product-item')
for item in items[:10]: # רק 10 ראשונים
name = item.find('h3').text.strip()
price_usd = float(item.find('span', class_='price').text.replace('$', '').strip())
price_ils = price_usd * 3.7 # המרה בערך
results.append({
'מקור': source,
'שם': name,
'מחיר_USD': price_usd,
'מחיר_ILS': round(price_ils, 2),
'קישור': item.find('a')['href']
})
df = pd.DataFrame(results)
df_sorted = df.sort_values('מחיר_ILS')
return df_sorted
# שימוש
tools = scrape_tool_prices("cnc drill bit set")
print(tools.head(10))
2. גריפת מפרטים טכניים של מכונות
def scrape_machine_specs(machine_model):
"""
אוסף מפרטים טכניים של מכונות
"""
url = f"https://machinery-specs.com/{machine_model}"
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
soup = BeautifulSoup(response.content, 'lxml')
specs = {}
# מציאת טבלת מפרטים
spec_table = soup.find('table', class_='specifications')
if spec_table:
rows = spec_table.find_all('tr')
for row in rows:
cols = row.find_all('td')
if len(cols) == 2:
key = cols[0].text.strip()
value = cols[1].text.strip()
specs[key] = value
# תמונות
images = []
img_elements = soup.find_all('img', class_='product-image')
for img in img_elements:
images.append(img['src'])
# מחיר
price_element = soup.find('span', class_='price')
price = price_element.text.strip() if price_element else 'N/A'
result = {
'דגם': machine_model,
'מפרטים': specs,
'תמונות': images,
'מחיר': price
}
return result
# שימוש
machine = scrape_machine_specs("DMG-MORI-NLX2500")
print(f"דגם: {machine['דגם']}")
print("\nמפרטים:")
for key, value in machine['מפרטים'].items():
print(f" {key}: {value}")
print(f"\nמחיר: {machine['מחיר']}")
🚀 טכניקות מתקדמות
1. Selenium - לאתרים דינמיים
אתרים רבים משתמשים ב-JavaScript לטעינת תוכן. Selenium פותח דפדפן אמיתי.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# הגדרת דפדפן
options = webdriver.ChromeOptions()
options.add_argument('--headless') # רץ ברקע
driver = webdriver.Chrome(options=options)
# פתיחת עמוד
driver.get("https://dynamic-website.com/products")
# המתנה לטעינת אלמנט ספציפי
wait = WebDriverWait(driver, 10)
products = wait.until(
EC.presence_of_all_elements_located((By.CLASS_NAME, "product-item"))
)
# חילוץ מידע
results = []
for product in products:
name = product.find_element(By.CLASS_NAME, "name").text
price = product.find_element(By.CLASS_NAME, "price").text
results.append({'name': name, 'price': price})
driver.quit()
print(results)
2. Rate Limiting - להיות מנומס
import time
from ratelimit import limits, sleep_and_retry
# מגביל ל-10 בקשות לדקה
@sleep_and_retry
@limits(calls=10, period=60)
def make_request(url):
return requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
# שימוש
urls = ['url1', 'url2', 'url3', ...]
for url in urls:
response = make_request(url)
# עיבוד...
3. Error Handling - טיפול בשגיאות
def safe_scrape(url, max_retries=3):
"""
גריפה עם retry אוטומטי
"""
for attempt in range(max_retries):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response
except requests.exceptions.Timeout:
print(f"Timeout - ניסיון {attempt + 1}/{max_retries}")
time.sleep(2 ** attempt) # exponential backoff
except requests.exceptions.HTTPError as e:
print(f"HTTP Error: {e}")
break
except Exception as e:
print(f"שגיאה: {e}")
break
return None
⚖️ חוקיות ואתיקה
Web Scraping הוא חוקי, אבל יש כללים שחובה לעקוב אחריהם.
מה מותר ומה אסור?
- מותר: לגרוף מידע פומבי (מחירים, מפרטים, ביקורות)
- מותר: לגרוף למטרות מחקר אישי וניתוח
- מותר: לגרוף אתרים שאין להם robots.txt שאוסר
- אסור: לגרוף מידע אישי (אימיילים, טלפונים של אנשים פרטיים)
- אסור: להציף שרת בבקשות (DDoS בטעות)
- אסור: לעקוף מנגנוני הגנה (CAPTCHA, login)
- אסור: להפר זכויות יוצרים (לגרוף תוכן ולפרסם כשלך)
robots.txt - מה זה?
קובץ robots.txt מגדיר אילו חלקים של האתר מותרים לגריפה.
from urllib.robotparser import RobotFileParser
def can_scrape(url):
"""
בודק אם מותר לגרוף URL
"""
rp = RobotFileParser()
rp.set_url("https://example.com/robots.txt")
rp.read()
return rp.can_fetch("*", url)
# שימוש
if can_scrape("https://example.com/products"):
print("מותר לגרוף!")
else:
print("אסור לגרוף!")
Best Practices
תמיד הוסף delay בין בקשות (1-3 שניות לפחות)
זהה את עצמך בצורה כנה ב-User-Agent header
הרץ scraping בשעות לא עמוסות (לילה/סופ"ש)
שמור תוצאות ולא תבקש אותו מידע פעמיים
אם אתה מתכנן scraping מסחרי או בקנה מידה גדול - התייעץ עם עורך דין.
המידע כאן הוא כללי בלבד ולא מהווה ייעוץ משפטי.
🤫 סוד קטן
ניסית פעם...? להוסיף time.sleep(random.uniform(1, 3)) במקום time.sleep(2)? זה עושה delay אקראי שנראה יותר "אנושי" ופחות חשוד לשרתים!
🎯 מסקנות ויישום מעשי
✅ מה למדנו היום?
- Web Scraping זה כוח-על - אוטומציה של איסוף מידע
- Python + Beautiful Soup - הכלים הבסיסיים שצריך
- יישומים מעשיים - מחירים, מפרטים, ביקורות
- אחריות וחוקיות - איך לעשות את זה נכון
- טכניקות מתקדמות - Selenium, Rate Limiting, Error Handling
🚀 איך להמשיך להתפתח?
- תרגול מעשי - התחל עם אתר פשוט
- למד Selenium - לאתרים דינמיים
- בנה פרויקטים - מעקב מחירים, ניתוח שוק
- למד APIs - לפעמים יש דרך קלה יותר
- שלב עם AI - ChatGPT לניתוח הנתונים
⚠️ טעויות נפוצות להימנע מהן
- לא לבדוק robots.txt - תמיד בדוק קודם
- בקשות מהירות מדי - תוסיף delay!
- לא לטפל בשגיאות - האינטרנט לא מושלם
- קוד לא גמיש - אתרים משתנים
- התעלמות מחוקיות - עשה את זה נכון
📋 משימות לשבוע הקרוב
🎯 רמה בסיסית (מתחילים)
- התקן Python ו-Beautiful Soup
- נסה את הדוגמה הבסיסית מהמדריך
- גרוף מחירים מאתר פשוט (כמו quotes.toscrape.com)
- שמור את התוצאות ל-CSV
- למד F12 Developer Tools בדפדפן
⚡ רמה מתקדמת (מנוסים)
- בנה scraper למעקב מחירי חלפים
- התקן Selenium ונסה אתר דינמי
- צור מערכת התראות על שינוי מחירים
- למד על APIs כחלופה ל-scraping
- שלב עם ניתוח נתונים - עבור למדריך ניתוח נתונים
- בנה dashboard עם הנתונים שאספת
😎 בונוס
תרגיל קטן: נסה לגרוף את מחירי הדלק מאתר דלק ישראל ולעקוב אחר השינויים. זה מעשי ומעניין לכל נהג!
🚀 הפוך לאמן Web Scraping
כל המידע באינטרנט זמין לך - רק צריך לדעת איך לגשת אליו
התחל עכשיו ותהיה המהנדס שיודע להפיק תובנות מכל מקום!
💡 זכור: עם Web Scraping אתה לא מוגבל למה שהאתרים רוצים להראות לך - אתה שולט במידע!