שלום אורח התחבר

הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

הזינו את כתובת המייל וקבלו את הפוסט היומי בכל בוקר אליכם לתיבה:

יש הרבה מאוד גישות ודעות שונות איך להחליט איזה פרויקטים לקחת בתור פרילאנסרים ואיך יודעים איזה פרויקט יקדם אתכם בצורה הטובה ביותר. הגישה שעבדה בשבילי היא שילוב של שתי שאלות:

  1. עד כמה הפרויקט הזה יכול לעזור ללקוח?

  2. עד כמה הפרויקט הזה מוציא אותי מפוקוס ופוגע בפרויקטים אחרים שחשובים לי?

לרוב הפרילאנסרים בתחילת הדרך אין עדיין פוקוס ולכן נרצה למצוא פרויקטים שתהיה להם כמה שיותר השפעה על הלקוח והעולם שלו. ככל שההשפעה גדולה יותר כך גדל הסיכוי שתסיימו את הפרויקט עם לקוח שירוץ לספר לכל החברים שלו. בגלל זה לא הייתי ממליץ לפרילאנסר גם בתחילת הדרך לבנות דפי נחיתה למשרדי פירסום או לפתוח פרויקט ב XPlace. אלה מקומות שאולי קל למצוא עבודה אבל קשה להפתיע לטובה. העבודות הכי טובות שהיו לי בתור פרילאנסר מתחיל היו דווקא פרויקטים בהתנדבות או כמעט בהתנדבות.

אחרי כמה פרויקטים טובים הלקוחות שלכם כבר יתחילו לספר לחברים שלהם ואז אתם מתחילים להתמודד עם בעיה חדשה שנקראת פוקוס. ככל שהפרויקטים שלכם יותר קרובים אחד לשני כך יהיה לכם יותר קל לעשות עבודה טובה יותר - כי אפשר לשתף קוד ורעיונות בין הפרויקטים. רופא עיניים מומחה שעושה את אותה פרוצדורה עשר פעמים ביום במשך שנים ממשיך לשפר את הטכניקה עם כל יום שעובר וכך מצליח לתת ערך גדול יותר ללקוחות שלו.

כל השאלות האחרות כגון האם משלמים לי מספיק? האם הלקוח נחמד? האם אני אלמד משהו חדש מהפרויקט? איך זה יראה בתיק עבודות שלי? באיזה שפת תכנות הפרויקט? ועוד שאלות רבות נוספות הן לרוב לא יותר מהסחות דעת. תתמקדו בהשפעה של הפרויקט על הלקוח שלכם וכל השאר יסתדר מעצמו.

התחביב שלי הוא תכנות, זה ברור. אני אוהב לכתוב קוד, לקרוא קוד, לדבר עם אנשים על קוד, לקרוא פוסטים על פריימוורקים חדשים. בקיצור אני מאלה.

ובגלל זה אחד הרגעים השמחים שהיו לי אחרי שהתחלתי ללמוד שפה חדשה היה כשהצלחתי לקרוא פוסטים מקצועיים בצרפתית. התחלתי ברדיט כמובן ומשם הגעתי לבחור הזה וממנו לעוד הרבה חברים שלו. ומכאן המחגר התחיל להסתובב: ככל שהצלחתי לקרוא ולהבין יותר פוסטים כך חיפשתי עוד ועוד מהם, מה שאומר שקראתי יותר וכך יכולת הקריאה שלי השתפרה.

והנה עוד אחד- לפני כמה חודשים העליתי לכאן קורס וידאו בנושא git. כמה אנשים ראו את הקורס וחשבו שהוא מספיק מעניין כדי להזמין אותי להרצות על גיט אצלם בחברה. מההרצאה והשאלות של המשתתפים גם אני למדתי יותר. על חלק מהלקחים האלה כתבתי כאן בבלוג וזה עודד עוד כמה אנשים להזמין אותי להרצות גם אצלם על גיט ומפה לשם אני יודע היום גיט לא רע בכלל.

רוצים לבנות לעצמכם תוכנית לימודים (לא משנה למה)? תתחילו עם המחגר. כשהגלגל זז רק קדימה ההצלחה מובטחת.

פיצ'ר ריצה ללא ראש של כרום עשוי לשנות את המשחק בכל מה שקשור ל Web Scraping. בזכות פיצ'ר זה אתם יכולים להפעיל כרום ממש מתוך תוכנית פייתון, לגלוש לאתרים, ללחוץ על כפתורים שעל המסך וכל זה בלי שתצטרכו ממשק משתמש גרפי מה שאומר שאתם יכולים להריץ את הקוד גם מסקריפט אוטומטי שרץ על השרת.

בואו נצא לסיבוב עם כרום נטול הראש כדי לראות איך הוא מתמודד עם העולם.

תחילה התקנת הכלים- תצטרכו להתקין את כרום זה ברור ואני מניח שיש לכם פייתון מותקן (למרות שממש לא חייבים פייתון ואפשר לכתוב את כל דוגמאות הקוד כאן גם בכל שפה אחרת שתומכת בסלניום). בכל מקרה אנחנו רצים עם פייתון אז בטוח תרצו להתקין גם את סלניום עם:

$ pip install selenium

הרכיב האחרון בסיפור נקרא ChromeDriver וזו תוכנה קטנה שמחברת בין סלניום לכרום. אתם צריכים להוריד את הדרייבר ולשמור אותו על המחשב במקום נגיש, ומה שיותר מעייף זה שאתם צריכים פעם בכמה שבועות לשדרג אותו כי כרום כל הזמן רץ קדימה. את הדרייבר בכל מקרה מורידים מכאן:

http://chromedriver.chromium.org/downloads

עכשיו אפשר לעבור לתוכניות הדוגמא - ראינו כאן לפני כמה ימים איך להדפיס את כל הכותרות מאתר ynet דרך שורת הפקודה. הנה אותן הכותרות הפעם עם סלניום וכרום נטול ראש:

import os
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

CHROMEDRIVER_PATH = '/Users/ynonperek/bin/chromedriver'

options = Options()
options.headless = True
driver = webdriver.Chrome(CHROMEDRIVER_PATH, chrome_options=options)

# Start Here
driver.get("https://www.ynet.co.il/home/0,7340,L-184,00.html")
news = driver.find_elements_by_css_selector('a.smallheader')
for item in news:
    print(item.text)

driver.close()

החלק הראשון שמופיע לפני ה Start Here הוא הגדרת הכלים. אנחנו צריכים להגיד לסלניום איפה הוא יכול למצוא את הדרייבר שהורדנו ושאנחנו רוצים לרוץ ללא ראש. מכאן ממשיכים כמו בתוכנית סלניום רגילה רק במקום לבדוק שדברים נמצאים במקום אנחנו משתמשים בהם כדי להדפיס את המידע.

באותו האופן נוכל להדפיס את הכותרות מאתר רוטר:

import os  
from selenium import webdriver  
from selenium.webdriver.chrome.options import Options  

CHROMEDRIVER_PATH = '/Users/ynonperek/bin/chromedriver'

options = Options()
options.headless = True
driver = webdriver.Chrome(CHROMEDRIVER_PATH, chrome_options=options)

# Start Here
driver.get("http://rotter.net/")
news = driver.find_elements_by_css_selector('a[target="news"] span')
for item in news:
    print(item.text)

driver.close()

בגלל שמדובר בסלניום אנחנו יכולים לבצע פעולות באתרים ממש כאילו היינו גולשים בהם מדפדפן כרום אמיתי, כולל כל היכולות של מילוי מידע בטפסים, לחיצה על כפתורים והרצת קוד JavaScript. הבעיה היחידה עם כל הטוב הזה היא שיש לנו את דפדפן כרום שצריך לדאוג לו. הפעלת הדפדפן עם הפעלת התוכנית, ניווט לדפים אחרים וסגירתו בסוף התוכנית משפיעים על הביצועים ומייצרים קוד שרץ יותר לאט. כמה יותר לאט? על המחשב שלי הצגת הכותרות מ ynet לקחה לי 5 שניות בגירסת הסלניום לעומת חצי שניה בגירסת ה Beautiful Soup. בתוכניות יותר גדולות תוספת הזמן להמראה עשויה להיות פחות משמעותית כי אנחנו מבלים יותר זמן בשיטוטים באתר.

ההשפעה הגדולה יותר על ביצועים תגיע מהכיוון של מקביליות. נרצה לראות איך לכתוב כלי אוטומטי שלוקח מידע מאתר ואיך למקבל את העבודה שלו כדי להגיע לביצועים סבירים. אבל זה כבר חומר לפוסט הבא בסידרה.

אוהבים Web Scraping? שבוע הבא ביום חמישי בבוקר אני מתכנן להעביר וובינר בנושא שם אראה את כל הדוגמאות מכל הפוסטים האלה ועוד ויהיה גם מקום לשאלות. אם אתם פנויים מוזמנים להצטרף דרך הקישור:

https://www.tocode.co.il/workshops/64

אני לא יודע אם בטעות או בכוונה אבל כשאחד הקוראים ניסה לקחת את דוגמת הקוד שפירסמתי כאן לפני כמה ימים ולהתאים אותה לרוטר כך שתדפיס את כל הכותרות משם במקום מ ynet הסיפור לא נגמר יפה. מסתבר שה HTML של רוטר נט לא התאים למבנה ש Beatiful Soup ציפו לו.

צפיה בקוד של אתר רוטר יכולה לרמוז לנו מה הבעיה:

<!--</u>531268</u><--></u><span style='font-size:9.0pt;color:red'><b>16:29</b></span>&nbsp; <a target='news' HREF='http://rotter.net/forum/scoops1/531268.shtml'><span style='font-size:10.0pt;color:000099'></g>אחרי הספירה גדעון סער מקום רביעי</g></span></a><br>

שימו לב לתג ה g שמקיף את ההודעה על זכייתו של סער במקום הרביעי. בטעות או בכוונה לפני הטקסט מופיע שם תג סוגר. מבחינת Beautiful Soup ופרסרים רבים נוספים בשביל לסגור את ה g צריך לסגור קודם את ה a שמעליו ולכן הטקסט שאתם רואים בכלל לא נמצא בתוך אלמנט ה a.

פרסר אחר לפייתון בשם lxml יצליח להתמודד עם הבעיה אבל בצורה קצת מוזרה: במקום לקחת את הטקסט מתוך ה a אנחנו נבקש ממנו לקחת את הטקסט מההורה של ה a, וכך נצליח להגיע לכל הכותרות. התחביר ש lxml עובד איתו נקרא xpath והקוד המלא נראה כך:

import requests
from bs4 import BeautifulSoup
from lxml.html.soupparser import fromstring
from lxml import etree

url = 'http://rotter.net/'
r = requests.get(url)
r.encoding = 'iso8859-8'
root = fromstring(r.text)
headlines = [
        text for text in root.xpath('//a[@target="news"]/../text()')
        if text != '\n' and text != '\n\n' and text != '\xa0 '
]

for text in headlines:
    print(text)

בניגוד ל ynet, ברוטר ה Character Encoding לא מוגדר טוב ולכן צריך להגיד ל requests בצורה מפורשת שאנחנו רוצים עברית. פקודת ה xpath למציאת הטקסטים היתה:

root.xpath('//a[@target="news"]/../text()')

זה מאוד מזכיר CSS Selector מלבד סימן הנקודה-נקודה שמציין מעבר לאלמנט ההורה. בעברית זה יישמע משהו כמו - קח כל אלמנט a שיש לו מאפיין target עם ערך news, תמצא את ההורה של כל אחד מהם, ומההורה הזה קח את כל הטקסטים שנמצאים ישירות תחתיו. אלה בדיוק הטקסטים שיימצאו "ליד" אלמנטי ה a, בגלל שה g גרם להם לצאת מה a.

מעניין לציין שלדפדפנים אין את הבעיה הזאת ובתוך ה Developer Console של כרום אנחנו יכולים בכיף לכתוב:

$$('a[target="news"]')[0].textContent

כדי לקבל את הטקסט של האייטם הראשון.

באחד הפוסטים הבאים בסידרה אספר לכם איך להפעיל Headless Chrome מתוך פייתון כדי לקבל גישה למשהו שמתנהג הרבה יותר כמו דפדפן. ואם בא לכם ללמוד יותר על Web Scraping, לראות בשידור חי איך אני מנסה להוריד מידע מאתרים ומסתבך או להציע אתרים לקחת מהם מידע - מוזמנים להצטרף אליי בשבוע הבא ביום חמישי בבוקר לוובינר של שעה בנושא. פרטים והרשמה בחינם כאן:

https://www.tocode.co.il/workshops/64

הדרך הכי טובה ללמוד היא קצת מכל דבר-

גם לכתוב משהו לבד בטכנולוגיה החדשה, גם לקרוא את התיעוד, גם להיתקע ולחפש תשובות ב Stack Overflow, גם ללכת למיטאפ כדי להכיר אנשים שעובדים בזה, גם להיכנס לקבוצת פייסבוק שלהם, גם להיכנס לערוץ IRC של הפרויקט, גם לראות הרצאות מכנסים ב Youtube, גם להעביר הרצאה במיטאפ ההוא שהתחלתם ללכת, גם לקרוא ספר מקצועי.

יותר נקודות מבט עוזרות לקבל תמונה עשירה יותר ועוזרות להיכנס לראש של האנשים שכותבים את הטכנולוגיה ושל אלה שכבר עובדים בה. לפני שאתם צוללים לכתיבת פרויקט שלם מאפס ב React (או כל טכנולוגיה אחרת), קחו את הזמן להכיר ולהבין את כל ה Ecosystem שלה. התוצאה תהיה פרויקט טוב יותר ובדרך כלל גם עבודה הרבה יותר מהנה.

חלק מהמשימות שלכם הולכות להיות יותר קשות עם הזמן, וחלק יותר קלות.

שידרוג גירסת תוכנה שאתם תלויים בה הולך להיות יותר קשה עם כל יום שעובר. כשאתה רק גירסא אחת אחורה עוד יש סקריפטים אוטומטיים לשדרוג ומדריכים ומה לא. כשאתם שלוש גירסאות אחורה החיים הרבה יותר קשים.

אותו דבר עובד לגבי לימוד כלי עבודה. כשאתה רק מתחיל לעבוד עם git להשקיע יומיים בלהבין איך זה עובד אמור להיות די פשוט. ככל שתחכה עם זה יהיה יותר קשה למצוא את הזמן ובכלל להבין מאיפה להתחיל. כל החומר באינטרנט יראה מוכר ואתה נשאר תקוע עם ההרגשה שאתה כבר יודע הכל, למרות פערי ידע שאולי צברת.

מצד שני שינויים טכנולוגיים לרוב מחלקים דיבידנדים דווקא למי שמחכה. ריאקט ראוטר היה ממש גרוע בגירסאות הראשונות שלו, ומי שחיכה לגירסא 4 קיבל מערכת בשלה ויציבה. בצורה דומה React Native עשתה חיים ממש קלים למפתחי Mobile בהשוואה ל PhoneGap, וכמובן שהחיים ב JavaScript הרבה יותר קלים אחרי ES8.

הקושי הוא להבין איזה משימה שייכת לאיזה קטגוריה, להתאזר בסבלנות כשאנחנו רואים משימה שתהיה יותר קלה בעוד שלושה חודשים ולהתאמץ להקדים משימות שיהיו הרבה יותר קשות בעוד שלושה חודשים.

אתרי אינטרנט מציגים את המידע שלהם בצורה שבוני האתר מצאו לנכון, אבל לא תמיד זאת הצורה שאנחנו הגולשים הכי רוצים. המתח המוכר ביותר בין בוני אתרים לגולשים הוא בנושא הפירסומות וחוסמי הפירסומות, אבל הוא לא היחיד. אולי אתם רוצים שהמידע יהיה מאורגן אחרת, או לקבל רק חלק מהמידע, או שילוב מידע מכמה מקורות.

לשמחתכם יש די הרבה כלים קטנים שאפשר להשתמש בהם כדי לבנות סקריפטים שיעשו בדיוק את זה. בשבועיים הקרובים אני מתכנן להראות דוגמאות למצבים כאלה ולסקריפטים קטנים שעוזרים בהם - כולם לקראת וובינר Web Scraping שיתקיים ביום חמישי הבא. היום בשביל הפתיחה ניקח משימה יחסית קלה: הצגת כל הכותרות מ ynet בשורת הפקודה.

שני דברים שכדאי לשים לב אליהם עוד לפני שניגשים לכתוב את שורת הקוד הראשונה:

  1. הכי קל לקבל את הכותרות בדף ה"מבזקים" של ynet. אם תצליחו למצוא את הכפתור "מבזקים" תוכלו להעתיק את ה url משם.

  2. בדף המבזקים כל כותרת היא תגית a עם קלאס בשם smallheader.

אז מה עושים? לוקחים את ה HTML מדף המבזקים, זורקים אותו ל HTML Parser ושם שולפים את כל אלמנטי ה a עם הקלאס smallheader. בפייתון הספריה שעוזרת לקבל קובץ HTML לפי כתובת ברשת נקראת requests והספריה שמפענחת קבצי HTML נקראת Beautiful Soup. כשמחברים את שתיהן יחד מקבלים:

import requests
from bs4 import BeautifulSoup

url = 'https://www.ynet.co.il/home/0,7340,L-184,00.html'
r = requests.get(url)
soup = BeautifulSoup(r.text)
for link in soup.select('a.smallheader'):
    print(link.text)

את הסקריפט הזה אתם יכולים כבר להריץ מ cronjob ולקבל את רשימת המבזקים מתוקצרת ישר למייל שלכם על הבוקר וכך תוכלו להיות רגועים ולדעת שהעולם לא התמוטט כשישנתם.

לא כל דבר שמנסים מצליח, גם בחיים וגם בתכנות. בפרק זה נלמד על חריגים בפייתון ונראה מה קורה כשמשהו משתבש וכיצד ניתן להחליט בעצמנו על תוכנית מילוט.

המשך קריאה...

הטעות הראשונה היא פיקוח יתר, וזה מה שקורה במהלך השיעור. המורה מדברת והילדים יושבים למלא קווים בחוברות עבודה שאי אפשר ללכת לאיבוד בהן. אגב לתרגולים בקודסקול יש את אותה בעיה. אנחנו לומדים באמת דרך משימות פתוחות שדורשות בניה של משהו מקצה לקצה.

הטעות השניה היא היעדר פיקוח, וזה מה שקורה בהפסקה. כאילו בשביל להתמודד עם פיקוח היתר וכדי שהילדים לא "יתפוצצו" אנחנו נותנים להם להוציא קיטור ולרוץ בלי השגחה רבע שעה בין שיעור לשיעור. בפועל ילדים לא יכולים לעשות שום דבר מועיל בהפסקה בדיוק בגלל שאין הכוונה.

בית ספר אידאלי נותן לילדים יום שלם ללכת באמצע- לבנות את הדברים הנכונים עם ההכוונה הנכונה, בלי לתת הוראות מדויקות ובלי לפחד שהילדים יטעו או יבזבזו את הזמן. זה בסדר גמור שצוות ינסה להרים מופע ובסוף לא יצליח, אבל עם הכוונה נכונה מסביב לשעון הם ילמדו מהתהליך.

(*) "אי אפשר ללכת לאיבוד בהן" - אם שואלים אתכם כמה זה 2 ועוד 2 ותכתבו 5 הצלחתם לכתוב את התשובה הלא נכונה. זה לא אומר שהצלחתם ללכת לאיבוד. ללכת לאיבוד זה לבנות משהו אחר לגמרי ממה שכותב השאלה התכוון ועדיין להרגיש טוב וללמוד מהתהליך. ללכת לאיבוד זה שקורה כשאני נותן משימה מסוג "תמצאו כמה שיותר בעיות אבטחה בקוד המערכת ההיא", או "בנו בוט לטלגרם שעושה משהו נחמד". גם אם לא מצאתם אף בעיית אבטחה או שהבוט לטלגרם שלכם לא מצליח לנסח תשובה נורמלית לשום שאלה, עדיין למדתם המון.

כמה לקחים מעבודת אינטגרציה קטנה שאני עובד עליה, אבל קודם בשתי מילים מה זה SOAP ולמה אנחנו מקטרים.

אז בתחילת שנות ה 2,000 היה פורמט של קבצים שנקרא XML וכולם עפו עליו וחשבו שזה הדבר הכי טוב מאז הלחם הפרוס או משהו. בכל מקרה אחת החברות שעפה על XML נקראת מייקרוסופט והם בדיוק חיפשו דרך לבנות ארכיטקטורה גנרית לתקשורת בין מערכות מבוזרות. הם חשבו על המון דברים והתוצאה היתה שבשביל לקבל למשל פרטי לקוח דרך API היית שולח בקשה שנראית בערך כך:

<?xml version="1.0"?>
<soap:Envelope 
          xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <m:GetCustomer 
          xmlns:m="http://www.example.org/customers">
      <m:CustomerId>43456</m:CustomerId>
    </m:GetCustomer>
  </soap:Body>
</soap:Envelope>

ומקבל בחזרה תשובה שנראית בערך כך:

<?xml version='1.0' ?>
<env:Envelope 
        xmlns:env="http://www.w3.org/2003/05/soap-envelope" >
 <env:Body>
    <m:GetCustomerResponse 
          xmlns:m="http://www.example.org/customers">
       <m:Customer>Foobar Quux, inc</m:Customer>
    </m:GetCustomerResponse>
 </env:Body>
</env:Envelope>

כל העסק הזה היה עטוף בענן סוכר של כלים בתוך ה Visual Studio כדי שמתכנתים אף פעם לא יצטרכו לראות את ה XML-ים האלה והכל נוצר בשבילכם באופן אוטומטי בלחיצת כפתור.

עד שיום אחד מתכנתים הפסיקו לעבוד ב Visual Studio והלכו לכתוב מערכות אינטרנט ב Rails (כן ריילס היה פופולרי ממש ב 2005) ומפה לשם שמנו לב שהרבה יותר קל פשוט לשלוח הודעה בפרוטוקול REST:

GET /customers/43456 HTTP/1.1
Host: www.example.org

ולקבל את התשובה ב JSON:

{'Customer': 'Foobar Quux, inc'}

אתם יכולים לקרוא עוד על הכישלון של SOAP במאמר המצוין בקישור הזה (ממנו גם לקחתי את הדוגמאות):

http://keithba.net/simplicity-and-utility-or-why-soap-lost

עכשיו בחזרה אלינו וללקחים מ SOAP-

  1. טכנולוגיות לא מתות. זאת הסיבה שאנגולר1 תמשיך להיות דבר עוד המון שנים.

  2. מוצרים טכנולוגיים מספיק וותיקים יכללו טכנולוגיות "מתות", כי ברגע שיש בסיס קוד גדול קשה מאוד להחליף את הכל.

  3. למודול soap ב npm יש באזור השמונים אלף הורדות בשבוע. זה אולי לא מתקרב ל 7 מיליון הורדות של אקספרס אבל עדיין מזכיר שאני לא היחיד שהיה צריך להתחבר לשרת SOAP השבוע.