ווב סקרייפינג עם פייתון - מדריך למתחילים¶
בואו נדבר בכנות. הרבה פעמים אתם רוצים מידע מאתר - מחירים, כתבות, רשימת מוצרים - והאתר לא נותן לכם דרך נוחה להוריד אותו. אין API, אין קובץ להורדה, רק דף HTML רגיל. פה נכנס ווב סקרייפינג - הטכניקה של לכתוב תוכנית שמורידה דף אינטרנט ומחלצת ממנו את המידע שאתם צריכים, אוטומטית.
זה לא קסם ולא האקינג. זה בעצם שילוב של שני דברים פשוטים - להוריד את הדף, ואז לחפש בתוכו את הפיסות שמעניינות אתכם.
שני הכלים שאתם צריכים¶
בפייתון, הצמד הכי נפוץ לסקרייפינג בסיסי הוא requests ו-BeautifulSoup. requests מוריד את דף ה-HTML הגולמי מהשרת, ו-BeautifulSoup יודע לקרוא HTML ולתת לכם לחפש בו אלמנטים לפי תג, class או id, בלי שתצטרכו לפרסר את זה בעצמכם עם regex - וזה חשוב, כי לנסות לפרסר HTML עם ביטויים רגולריים זה כאב ראש מיותר לגמרי.
אם עוד לא מותקן אצלכם, ההתקנה היא פקודה אחת:
הורדת דף ראשונה¶
הצעד הראשון הוא פשוט - להוריד את התוכן הגולמי של הדף:
import requests
url = "https://example.com"
response = requests.get(url)
print(response.status_code) # 200 אומר שהכל תקין
html = response.text
response.status_code הוא קוד שמספר לכם אם הבקשה הצליחה. 200 זה בסדר, 404 אומר שהדף לא נמצא, ו-403 או 429 יכולים לרמז שהאתר חוסם בקשות אוטומטיות. תמיד שווה לבדוק את זה לפני שממשיכים, כדי לא לנסות לפרסר דף שלא באמת התקבל.
חילוץ מידע עם BeautifulSoup¶
אחרי שיש לכם את ה-HTML כמחרוזת, אתם מעבירים אותו ל-BeautifulSoup כדי לחפש בתוכו:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
title = soup.find("h1")
print(title.text)
links = soup.find_all("a")
for link in links:
print(link.get("href"))
find מחזיר את האלמנט הראשון שמתאים לתג שביקשתם, ו-find_all מחזיר רשימה של כל האלמנטים המתאימים. אפשר גם לחפש לפי class, ששימושי כשרוצים אלמנט ספציפי בתוך דף עמוס:
שימו לב ל-strip() - טקסט שמגיע מ-HTML לרוב מכיל רווחים ומעברי שורה מיותרים מסביב, וכדאי לנקות אותו לפני שמשתמשים בו.
דוגמה מלאה - איסוף כותרות¶
בואו נחבר הכל לדוגמה שמורידה דף ואוספת את כל הכותרות שבו לרשימה:
import requests
from bs4 import BeautifulSoup
response = requests.get("https://example.com/blog")
if response.status_code == 200:
soup = BeautifulSoup(response.text, "html.parser")
headlines = [h.text.strip() for h in soup.find_all("h2")]
for headline in headlines:
print(headline)
else:
print(f"הבקשה נכשלה, קוד סטטוס: {response.status_code}")
זו בדיוק התבנית שחוזרת על עצמה ברוב פרויקטי הסקרייפינג הבסיסיים - הורדה, בדיקת סטטוס, חיפוש, וניקוי.
כללי התנהגות שכדאי להכיר¶
לפני שאתם מריצים סקרייפר על אתר אמיתי, שווה לזכור כמה כללים. לרוב האתרים יש קובץ בשם robots.txt (למשל example.com/robots.txt) שמפרט אילו חלקים באתר מותר לכלי אוטומטיים לגשת אליהם. זה לא חוק פיזי שאוכף את עצמו, אבל זה הסכם ג'נטלמני שכדאי לכבד. בנוסף, כדאי להריץ בקשות בקצב סביר ולא להפציץ שרת בעשרות בקשות בשנייה - זה יכול להיראות כמו מתקפה ולגרום לחסימה של הכתובת שלכם. ולבסוף, לא כל מידע שמותר לגרד מבחינה טכנית מותר להשתמש בו מבחינה משפטית או של תנאי שימוש - אם משהו מרגיש אפור, שווה לבדוק לפני שממשיכים.
מתי לא לגשת לסקרייפינג בכלל¶
הכלל החשוב ביותר בנושא הזה - אם לאתר יש API רשמי, תשתמשו בו במקום לגרד. API נותן לכם מידע מובנה, נקי, ולרוב יציב יותר, בלי להישבר בכל פעם שהאתר משנה קצת את מבנה ה-HTML שלו. סקרייפינג הוא כלי למקרים שבהם אין ברירה אחרת - לא הפתרון הראשון שקופצים אליו כי הוא "מגניב".
אם הנושא הזה נשמע לכם רחוק כרגע כי עוד לא ממש חזק לכם הבסיס בפייתון, שווה קודם לעבור על קורס התכנות הבסיסי שלנו, ואז לחזור לנושאים כמו סקרייפינג עם בסיס יציב יותר.
ואם בניתם סקרייפר ונתקעתם על משהו ספציפי - HTML שלא נמצא, אתר שחוסם אתכם, או מבנה דף מוזר - שתפו בקהילה בדיסקורד ותקבלו עזרה.