掌握新科技:使用大型语言模型增强网页抓取

发表时间: 2024-05-28 17:47

探索大型语言模型 (LLM) 与 Web 抓取的集成,以及使用 LLM 有效地将复杂的 HTML 转换为结构化的 JSON。

在我担任数据工程师的早期(可以追溯到 2016 年),我负责从不同的网站抓取数据。网络抓取就是利用自动化的工具从网站(通常是从其 HTML)中获取大量数据。

我记得围绕应用程序进行构建,深入研究 HTML 代码,并试图找出抓取所有数据的最佳解决方案。我的主要挑战之一是处理网站的频繁更改:例如,我抓取的亚马逊页面每隔一到两周就会更改一次。

当我开始阅读有关大型语言模型 (LLM) 的文章时,我突然想到的一个想法是,“我能否避免使用 LLM 从网页中构建数据时遇到的所有陷阱?

让我们看看我能不能。

网页抓取工具和技术

当时,我使用的主要工具是 RequestsBeautifulSoupSelenium。每个服务都有不同的用途,并针对不同类型的 Web 环境。

  • Requests 是一个 Python 库,可用于轻松发出 HTTP 请求。此库对请求中提供的 URL 执行 GET 和 POST 操作。它经常用于获取可由 BeautifulSoup 解析的 HTML 内容。
  • BeautifulSoup 是一个用于解析 HTML 和 XML 文档的 Python 库,它从页面源构建解析树,让您轻松访问页面上的各种元素。通常,它与提供 HTML 源代码的其他库(如 Requests 或 Selenium)配对。
  • Selenium 主要用于涉及大量 JavaScript 的网站。与 BeautifulSoup 不同,Selenium 不简单地分析 HTML 代码:它通过模拟用户操作(如点击和滚动)与网站进行交互。这有助于从动态创建内容的网站中提取数据。

当我尝试从网站中提取数据时,这些工具是必不可少的。然而,它们也带来了一些挑战:代码、标签和结构元素必须定期更新以适应网站布局的变化,使长期维护变得复杂。

什么是大型语言模型 (LLM)?

大型语言模型 (LLM) 是下一代计算机程序,可以通过读取和分析大量文本数据来学习。在这个年龄段,他们天赋异禀,能够以类似人类的叙述方式写作,使他们成为处理语言和理解人类语言的有效代理人。在那种情况下,出色的能力闪耀着光芒,文本上下文非常重要。

将 LLM 集成到 Web 抓取中

在实现 LLM 时,可以在很大程度上优化 Web 抓取过程。我们需要从网页中获取 HTML 代码并将其输入到 LLM 中,LLM 将提取它所引用的对象。因此,这种策略有助于使维护变得容易,因为标记结构可以演变,但内容本身通常不会改变。

以下是这种集成系统的架构:

  1. 获取 HTML:使用 Selenium 或 Requests 等工具获取网页的 HTML 内容。Selenium 可以处理使用 JavaScript 加载的动态内容,而 Requests 适用于静态页面。
  2. 解析 HTML:使用 BeautifulSoup,我们可以将此 HTML 解析为文本,从而消除 HTML 中的噪音(页脚、页眉等)。
  3. 创建 Pydantic 模型:键入我们要抓取的 Pydantic 模型。这样可以确保类型化和结构化的数据符合预定义的架构。
  4. 为 LLM 生成提示:设计一个提示,告知 LLM 必须提取哪些信息。
  5. LLM 处理:模型读取 HTML,理解它,并使用指令进行数据处理和结构化。
  6. 结构化数据的输出:LLM 将以结构化对象的形式提供输出,这些对象由 Pydantic 模型定义。

此工作流有助于使用 LLM 将 HTML(非结构化数据)转换为结构化数据,从而解决非标准设计或动态修改 Web 源 HTML 等问题。

LangChain 与 BeautifulSoup 和 Pydantic 的集成

这是为示例选择的静态网页。这个想法是抓取那里列出的所有活动并以结构化的方式呈现它们。

此方法将从静态网页中提取原始 HTML,并在 LLM 处理它之前对其进行清理。

from bs4 import BeautifulSoupbr
import requestsbr
br
br
def extract_html_from_url(url):br
    try:br
        # Fetch HTML content from the URL using requestsbr
        response = requests.get(url)br
        response.raise_for_status()  # Raise an exception for bad responses (4xx and 5xx)br
br
        # Parse HTML content using BeautifulSoupbr
        soup = BeautifulSoup(response.content, "html.parser")br
        excluded_tagNames = ["footer", "nav"]br
        # Exclude elements with tag names 'footer' and 'nav'br
        for tag_name in excluded_tagNames:br
            for unwanted_tag in soup.find_all(tag_name):br
                unwanted_tag.extract()br
br
        # Process the soup to maintain hrefs in anchor tagsbr
        for a_tag in soup.find_all("a"):br
            href = a_tag.get("href")br
            if href:br
                a_tag.string = f"{a_tag.get_text()} ({href})"br
br
        return ' '.join(soup.stripped_strings)  # Return text content with preserved hrefsbr
br
    except requests.exceptions.RequestException as e:br
        print(f"Error fetching data from {url}: {e}")br
        return None

下一步是定义我们将从网页中抓取的 Pydantic 对象。需要创建两个对象:

  • Activity这是一个 Pydantic 对象,表示与活动相关的所有元数据,并指定了其属性和数据类型。我们已标记了一些字段,以防它们不适用于所有活动。提供描述、示例和任何元数据将有助于 LLM 更好地定义属性。Optional
  • ActivityScraper:这是围绕 的 Pydantic 包装器。此对象的目标是确保 LLM 了解抓取多个活动需要它。Activity
from pydantic import BaseModel, Fieldbr
from typing import Optionalbr
br
class Activity(BaseModel):br
    title: str = Field(description="The title of the activity.")br
    rating: float = Field(description="The average user rating out of 10.")br
    reviews_count: int = Field(description="The total number of reviews received.")br
    travelers_count: Optional[int] = Field(description="The number of travelers who have participated.")br
    cancellation_policy: Optional[str] = Field(description="The cancellation policy for the activity.")br
    description: str = Field(description="A detailed description of what the activity entails.")br
    duration: str = Field(description="The duration of the activity, usually given in hours or days.")br
    language: Optional[str] = Field(description="The primary language in which the activity is conducted.")br
    category: str = Field(description="The category of the activity, such as 'Boat Trip', 'City Tours', etc.")br
    price: float = Field(description="The price of the activity.")br
    currency: str = Field(description="The currency in which the price is denominated, such as USD, EUR, GBP, etc.")br
br
    br
class ActivityScrapper(BaseModel):br
    Activities: list[Activity] = Field("List of all the activities listed in the text")

最后,我们有了 LLM 的配置。我们将使用 LangChain 库,它提供了一个出色的入门工具包。

这里的一个关键组件是 .从本质上讲,这会将我们的对象转换为指令,如 所示,并且还解析 LLM 的输出以检索相应的对象列表。PydanticOutputParserPrompt

from langchain.prompts import PromptTemplatebr
from langchain.output_parsers import PydanticOutputParserbr
from langchain_openai import ChatOpenAIbr
from dotenv import load_dotenvbr
br
load_dotenv()br
br
llm = ChatOpenAI(temperature=0)br
output_parser = PydanticOutputParser(pydantic_object = ActivityScrapper)br
br
prompt_template = """br
You are an expert making web scrapping and analyzing HTML raw code.br
If there is no explicit information don't make any assumption.br
Extract all objects that matched the instructions from the following htmlbr
{html_text}br
Provide them in a list, also if there is a next page link remember to add it to the object.br
Please, follow carefulling the following instructionsbr
{format_instructions}br
"""br
br
prompt = PromptTemplate(br
    template=prompt_template,br
    input_variables=["html_text"],br
    partial_variables={"format_instructions": output_parser.get_format_instructions}br
)br
br
chain = prompt | llm | output_parser

最后一步是调用链并检索结果。

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

下面是数据的样子。抓取整个网页需要 46 秒。

[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='€'),br
 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='€')br
 ...br
]

演示和完整存储库

我使用此处提供的 Streamlit 创建了一个快速演示。

在第一部分中,您将了解该模型。您可以根据需要添加任意数量的行,并指定每个属性的名称、类型和描述。这将自动生成一个 Pydantic 模型,用于 Web 抓取组件。

下一部分允许您输入 URL 并通过单击网页上的按钮来抓取所有数据。抓取完成后会出现一个下载按钮,允许您以 JSON 格式下载数据。

随意玩吧!

结论

LLM 为从非结构化数据(如网站、PDF 等)中高效提取数据提供了新的可能性。LLM的网页抓取自动化不仅可以节省时间,还可以确保检索到的数据的质量。

但是,将原始 HTML 发送到 LLM 可能会增加令牌成本并使其效率低下。由于 HTML 通常包含各种标签、属性和内容,因此成本会迅速上升。

因此,对 HTML 进行预处理和清理,删除所有不必要的元数据和未使用的信息至关重要。这种方法将有助于将 LLM 用作 Web 的数据提取器,同时保持合理的成本。

适合工作的工具!


原文标题:Enhancing Web Scraping With Large Language Models: A Modern Approach

原文链接:https://dzone.com/articles/enhancing-web-scraping-with-large-language-models

作者:Nacho Corcuera

编译:LCR