LLM增强的Web抓取

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

我记得在构建应用程序时,深入研究 HTML 代码,并尝试找出最佳解决方案来抓取所有数据。我面临的一个主要挑战是应对网站的频繁更改:例如,我抓取的亚马逊页面每 1 至 2 周更改一次。

当我开始阅读关于大型语言模型(LLMs)的内容时,我有一个想法:“我能否利用 LLMs 来避免我在使用 LLMs 结构网页数据时遇到的那些陷阱?”

让我们看看是否可以。

1、网络抓取工具和技术

当时,我主要使用 Requests、BeautifulSoup 和 Selenium。每个工具都有不同的用途,针对不同的网络环境。

  • Requests 是一个用于轻松执行 HTTP 请求的 Python 库。该库可以对提供的 URL 执行 GET 和 POST 操作。它通常与 BeautifulSoup 或 Selenium 等库结合使用,以获取 HTML 源代码。
  • BeautifulSoup 是一个用于解析 HTML 和 XML 文档的 Python 库,它从页面源代码构造解析树,允许您轻松访问页面上的各个元素。通常与 Requests 或 Selenium 等库结合使用,提供 HTML 源代码。
  • Selenium 主要用于涉及大量 JavaScript 的网站。与 BeautifulSoup 不同,Selenium 不仅仅分析 HTML 代码,而是通过模拟用户操作(如点击和滚动)与网站互动。这使得从动态生成内容的网站提取数据变得更加容易。

这些工具在我尝试从网站提取数据时是不可或缺的。然而,它们也带来了一些挑战:代码、标签和结构元素需要定期更新,以适应网站布局的变化,从而增加了长期维护的复杂性。

2、什么是大型语言模型(LLMs)?

大型语言模型(LLMs)是新一代的计算机程序,它们通过阅读和分析大量的文本数据来学习。在这个时代,LLMs 具备了以人类语言书写的能力,使得它们成为处理语言和理解人类语言的高效代理。这种出色的能力在需要文本上下文的重要情况下表现得尤为突出。

3、将 LLMs 集成到网络抓取中

在网络抓取过程中,通过集成 LLMs 可以在很大程度上优化流程。我们需要从网页获取 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 模型形式提供结构化对象的输出。

此工作流程将 HTML(非结构化数据)转换为结构化数据,解决了网页源 HTML 非标准设计或动态修改的问题。

4、LangChain/BeautifulSoup/Pydantic 集成

这是一个示例所选的静态网页。目的是以结构化方式抓取并列出所有活动。

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

from bs4 import BeautifulSoup
import requests

def extract_html_from_url(url):
    try:
        # 使用 requests 从 URL 获取 HTML 内容
        response = requests.get(url)
        response.raise_for_status()  # 对于不良响应(4xx 和 5xx)引发异常

        # 使用 BeautifulSoup 解析 HTML 内容
        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()

        # 处理 soup,保留锚标签中的 href
        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)  # 返回带有保留 href 的文本内容

    except requests.exceptions.RequestException as e:
        print(f"从 {url} 获取数据时出错: {e}")
        return None

接下来是定义将从网页抓取的 Pydantic 对象。需要创建两个对象:

  • Activity:这是一个表示活动元数据的 Pydantic 对象,其属性和数据类型已指定。对于并非所有活动都可用的字段,我们将其标记为可选。提供描述、示例和任何元数据将帮助 LLM 更好地定义属性。
  • ActivityScraper:这是围绕 Activity 的 Pydantic 包装器。此对象的目的是确保 LLM 理解需要抓取多个活动。
from pydantic import BaseModel, Field
from typing import Optional

class Activity(BaseModel):
    title: str = Field(description="活动的标题。")
    rating: float = Field(description="用户的平均评分(满分 10 分)。")
    reviews_count: int = Field(description="收到的总评论数。")
    travelers_count: Optional[int] = Field(description="参与活动的游客人数。")
    cancellation_policy: Optional[str] = Field(description="活动的取消政策。")
    description: str = Field(description="活动内容的详细描述。")
    duration: str = Field(description="活动的持续时间,通常以小时或天为单位。")
    language: Optional[str] = Field(description="活动进行的主要语言。")
    category: str = Field(description="活动的类别,如 '船游'、'城市旅游' 等。")
    price: float = Field(description="活动的价格。")
    currency: str = Field(description="价格所用的货币,如 USD、EUR、GBP 等。")

class ActivityScrapper(BaseModel):
    Activities: list[Activity] = Field("文本中列出的所有活动的列表")

最后是配置 LLM。我们将使用 LangChain 库,它提供了一个优秀的工具包来入门。

关键组件是 PydanticOutputParser。这将把我们的对象转换为指令,如提示中所示,并解析 LLM 的输出以检索相应的对象列表。

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

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

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 秒。

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

5、演示和完整仓库

我使用 Streamlit 创建了一个快速演示,地址在这里

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

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

随意玩吧!

6、结束语

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

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

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


原文链接:Enhancing Web Scraping With Large Language Models: A Modern Approach

汇智网翻译整理,转载请标明出处