שיפור גראסיפה אינטרנטית עם מודלים של שפות גדולות: גישה מודרנית

בימים הראשונים שלי כמהנדס נתונים (שחוזרים עד 2016), הייתה לי האחריות לגשת לנתונים מרשתות אינטרנט שונות. גילוי מידע מאינטרנט מערב שימוש בכלים מופתעים כדי להשיג כמויות גדולות של נתונים מהאתרים, בדרך כלל מהם HTML.

I remember building around the application, digging into the HTML code, and trying to figure out the best solutions for scraping all the data. One of my main challenges was dealing with frequent changes to the websites: for example, the Amazon pages I was scraping changed every one to two weeks.

מחשבה אחת שקרתה לי כשהתחלתי לקרוא על מודלים של שפה גדולים (LLMs) היתה, "האם אני יכול להימנע מכל המלכודות שעמדו בפני בשימוש ב-LLMs לעיצוב נתונים מדפי האינטרנט?"

בואו נראה אם אני יכול.

כלים ושיטות גילוי מידע מאינטרנט

באותו זמן, הכלים העיקריים שהשתמשתי בהם היו Rקריאות, BeautifulSoup, ו-Selenium. כל שירות משמש מטרה שונה ומיועד לסביבות אינטרנט שונות.

  • קריאות היא ספרייה פייתון שניתן להשתמש בה כדי לבצע בקשות HTTP בקלות. ספרייה זו מבצעת פעולות GET ו-POST נגד URL שמוצג בבקשות. היא נמצאת לעתים קרובות כדי להשיג תוכן HTML שניתן לנתח על ידי BeautifulSoup.
  • BeautifulSoup היא בריבריית פייתון לניתוח דואקומנטים HTML ו-XML, המבוססת על יישום עץ פיסת קוד ממקור הדף המאפשר לך לגשת בקלות לאלמנטים שונים בדף. בדר"כ, היא משלבת עם בריבריות אחרות כמו Requests או Selenium שמספקות את קוד ה-HTML.
  • Selenium משמש בעיקר עבור אתרים עם הרבה ג'אווה סקריפט. שלא כמו BeautifulSoup, Selenium אינה פשוטה בניתוח ה-HTML קוד: היא מתקשרת עם אתרים על ידי הצגת פעולות משתמש כמו לחיצות וגלישות. זה מאפשר פילוט נתונים מאתרים שיוצרים תוכן דינמי.

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

מהם מודלים שפה גדולים (LLMs)?

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

שילוב LLMs בפילוט אתרים

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

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

  1. קבלת HTML: השתמש בכלים כמו Selenium או Requests להשגת תוכן HTML של דף אינטרנט. Selenium יכול להתמודד עם תוכן דינמי שטוען עם JavaScript, ו-Requests מתאים לדפים סטטיים.
  2. ניתוח HTML: באמצעות BeautifulSoup, נוכל לנתח את ה-HTML כטקסט, ובכך להסיר את הרעש מה-HTML (כותרת, רגלית וכד').
  3. יצירת מודלים Pydantic: הקלד את מודל Pydantic שבו אנו עומדים לגרום. זה מוודא שהנתונים שנקלדו ומובנים עומדים בשפה המוגדרת מראש.
  4. יצירת פרומפטים ל-LLMs: תכנן פרומפט שידווח ל-LLM איזה מידע יש להוציא.
  5. עיבוד על ידי LLM: המודל קורא את ה-HTML, מבין אותו ומשתמש בהוראות לעיבוד ומבנה נתונים.
  6. פלט של נתונים מובנים: ה-LLM יספק את הפלט בצורה של אובייקטים מובנים המוגדרים על ידי מודל Pydantic.

תהליך זה עוזר להמיר HTML (נתונים לא מובנים) לנתונים מובנים באמצעות LLMs, ופותר בעיות כמו עיצוב לא סטנדרטי או שינוי דינאמי של מקור ה-HTML של האתר.

שילוב LangChain עם BeautifulSoup ו-Pydantic

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

השיטה הזו תוציא את ה-HTML הגולמי מהאתר הסטטי ותנקה אותו לפני שה-LLM מעבד אותו.

Python

 

from bs4 import BeautifulSoup
import requests


def extract_html_from_url(url):
    try:
        # שליפת תוכן HTML מהכתובת האינטרנטית באמצעות requests
        response = requests.get(url)
        response.raise_for_status()  # Raise an exception for bad responses (4xx and 5xx)

        # פירוק תוכן HTML באמצעות BeautifulSoup
        soup = BeautifulSoup(response.content, "html.parser")
        excluded_tagNames = ["footer", "nav"]
        # הוצאת אלמנטים עם שמות התגים 'footer' ו- 'nav'
        for tag_name in excluded_tagNames:
            for unwanted_tag in soup.find_all(tag_name):
                unwanted_tag.extract()

        # עיבוד הסופה כדי לשמור על hrefs בתגיות האנקר
        for a_tag in soup.find_all("a"):
            href = a_tag.get("href")
            if href:
                a_tag.string = f"{a_tag.get_text()} ({href})"

        return ' '.join(soup.stripped_strings)  # Return text content with preserved hrefs

    except requests.exceptions.RequestException as e:
        print(f"Error fetching data from {url}: {e}")
        return None

השלב הבא הוא להגדיר את אובייקטי Pydantic שאנו עומדים לגרום להם מהאתר. יש ליצור שני אובייקטים:

  • Activity: זהו אובייקט Pydantic המייצג את כל המטא-נתונים הקשורים לפעילות, עם התכונות וסוגי הנתונים שלהם מסופקים. סימנו כמה שדות כ-Optional במקרה שהם אינם זמינים עבור כל הפעילויות. מתן תיאור, דוגמאות וכל מטא-נתונים יעזור ל-LLM לקבל הגדרה טובה יותר של התכונה.
  • ActivityScraper: זהו הארגון Pydantic מסביב לActivity. המטרה של אובייקט זה היא להבהיר ל-LLM שהוא צריך לגרום לגרור מספר פעילויות.
Python

 

from pydantic import BaseModel, Field
from typing import Optional

class Activity(BaseModel):
    title: str = Field(description="The title of the activity.")
    rating: float = Field(description="The average user rating out of 10.")
    reviews_count: int = Field(description="The total number of reviews received.")
    travelers_count: Optional[int] = Field(description="The number of travelers who have participated.")
    cancellation_policy: Optional[str] = Field(description="The cancellation policy for the activity.")
    description: str = Field(description="A detailed description of what the activity entails.")
    duration: str = Field(description="The duration of the activity, usually given in hours or days.")
    language: Optional[str] = Field(description="The primary language in which the activity is conducted.")
    category: str = Field(description="The category of the activity, such as 'Boat Trip', 'City Tours', etc.")
    price: float = Field(description="The price of the activity.")
    currency: str = Field(description="The currency in which the price is denominated, such as USD, EUR, GBP, etc.")

    
class ActivityScrapper(BaseModel):
    Activities: list[Activity] = Field("List of all the activities listed in the text")

לבסוף, יש לנו את התיקון של ה-LLM. נשתמש בספריית LangChain, שמספקת כלים מצוינים להתחלה.

A key component here is the PydanticOutputParser. Essentially, this will translate our object into instructions, as illustrated in the Prompt, and also parse the output of the LLM to retrieve the corresponding list of objects.

Python

 

from langchain.prompts import PromptTemplate
from langchain.output_parsers import PydanticOutputParser
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()

llm = ChatOpenAI(temperature=0)
output_parser = PydanticOutputParser(pydantic_object = ActivityScrapper)

prompt_template = """
You are an expert making web scrapping and analyzing HTML raw code.
If there is no explicit information don't make any assumption.
Extract all objects that matched the instructions from the following html
{html_text}
Provide them in a list, also if there is a next page link remember to add it to the object.
Please, follow carefulling the following instructions
{format_instructions}
"""

prompt = PromptTemplate(
    template=prompt_template,
    input_variables=["html_text"],
    partial_variables={"format_instructions": output_parser.get_format_instructions}
)

chain = prompt | llm | output_parser

השלב האחרון הוא לקרוא לשרשרת ולהשיג את התוצאות.

Python

 

url = "https://www.civitatis.com/es/budapest/"
html_text_parsed = extract_html_from_url(url)
activites = chain.invoke(input={
    "html_text": html_text_parsed
})
activites.Activities

הנה איך הנתונים נראים. זה לוקח 46 שניות לגרור את כל הדף האינטרנטי.

Python

 

[Activity(title='Paseo en barco al anochecer', rating=8.4, reviews_count=9439, travelers_count=118389, cancellation_policy='Cancelación gratuita', description='En este crucero disfrutaréis de las mejores vistas de Budapest cuando se viste de gala, al anochecer. El barco es panorámico y tiene partes descubiertas.', duration='1 hora', language='Español', category='Paseos en barco', price=21.0, currency='€'),
 Activity(title='Visita guiada por el Parlamento de Budapest', rating=8.8, reviews_count=2647, travelers_count=34872, cancellation_policy='Cancelación gratuita', description='El Parlamento de Budapest es uno de los edificios más bonitos de la capital húngara. Comprobadlo vosotros mismos en este tour en español que incluye la entrada.', duration='2 horas', language='Español', category='Visitas guiadas y free tours', price=27.0, currency='€')
 ...
]

הפצה ומאגר מלא

I have created a quick demo using Streamlit available here.

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

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

תרצה לשחק עם זה!

מסקנה

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

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

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

הכלי הנכון לעבודה הנכונה!

Source:
https://dzone.com/articles/enhancing-web-scraping-with-large-language-models