网络搭化的技术以获取可靠信息的chatgpt
#python #ai #webscraping #chatgpt

自Openai的Chatgpt发行及其REST API以来,技术界一直被这种范式转移技术的巨大功能所包围,并将其推向极限。但是,对于尽可能多的优势,Chatgpt具有两个明显的弱点:1)其训练数据截止为2021,这意味着它在最近的时代没有信息知识,而2)它容易幻觉或构成信息。

为了避免此问题,软件开发人员和及时的工程师都承担了补充Chatgpt知识库的任务,这些信息可以提供更相关,可靠和知情的响应。这个过程涉及技术和及时工程的组合,我们将在本系列中进行深入讨论。

在本文中,我们将调查如何编写一个程序来刮擦互联网的内容,以补充LLM之外的LLM之外的LLM,超出其培训数据。具体来说,我们将从Nourish by WebMD收集信息和处理文章,以创建有关营养资源的数据库,该数据将用于营养聊天机器人。


这是我关于创建营养聊天机器人的系列的一部分

  • 第1部分:网络剪贴技术以获取可靠信息的Chatgpt
  • 第2部分:利用向量嵌入和相似性搜索来补充Chatgpt的培训数据(即将推出)
  • 第3部分:用于提供上下文信息(即将推出)的CHATGPT提示设计技术

Nourish by WebMD提供了与营养和饮食良好有关的大量文章。每篇文章都可以方便地分解为多个子标题,每个标题下方的文本为主要文章主题提供了其他相关信息。由于每个子头部都包含有关与主要主题相关的子主题的特定信息,因此可以说,而不是选择保存整个文章作为一个“文档”,我们希望通过标题将文章分解为多个文档。

所有文章均列在WebMD的Health & Diet Medical Reference上,该文章在撰写本文时分为23页。此引用中的每个页面都包含我们需要刮擦的其他文章。

要执行网络刮擦,我们将使用BeautifulSoup库以及内置的requests库。回想一下,我们必须通过参考文献中的每个分页页面迭代。然后,我们将使用html2text将每个页面的普通html转换为标记内容,然后通过markdown标题将页面分为多个文档。

您可以在Jupyter笔记本或Google Colab之类的平台上进行此项目。另外,您可以在Pycharm或VS代码等IDE中创建一个新的Python项目。我建议使用jupyter笔记本与本文一起遵循。

本文中的代码也可以供您在Google Colab上遵循(并运行)。

入门

让我们首先安装此项目的必要依赖项:

pip install bs4 html2text

接下来,我们将定义一些自定义请求标头来欺骗我们在提出请求时使用的Web-Browser客户端:

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Accept-Language': 'en-US,en;q=0.9',
}

通过参考爬行

由于我们要刮擦的每篇文章都位于WebMD的Health & Diet Medical Reference中,并且参考本身是分页的,因此我们首先需要创建一个Web-Crawler程序来确定我们需要刮擦的每个链接。

为此

import requests
from bs4 import BeautifulSoup


def get_links_from_page(index):
  # Send a GET request to the page we want to crawl
  url = f"https://www.webmd.com/diet/medical-reference/default.htm?pg={index}"
  response = requests.get(url, headers=headers)

  # Parse the HTML content using BeautifulSoup
  soup = BeautifulSoup(response.content, 'html.parser')

  # Find the ul element with the links to articles
  ul_element = soup.find('section', class_='dynamic-index-feed').find('ul', class_='list')

  # Find all the anchors (a tags) within the ul element
  anchors = ul_element.find_all('a')

  # Extract the href attribute from each link
  links = [anchor['href'] for anchor in anchors]

  return links

接下来,我们将创建一个get_all_links_from_reference函数,该函数将在参考中的所有23页中迭代并获取所有链接到文章。

all_links = []

def get_all_links_from_reference():
  for index in range(1, 24):
    all_links.extend(get_links_from_page(index))

运行它后,我们现在拥有WebMD健康和饮食参考中的所有链接,现在我们可以继续刮擦各个文章的内容。

刮擦和处理文章

如前所述,我们将将每篇文章分解为多个“文档”,这些“文档”由本文中的标题分开。让我们做一个实用程序Document类,以帮助我们构建代码并跟踪文章的标题和URL以及文档的内容:

class Document:
  def __init__(self, title, url, content):
    self.title = title
    self.url = url
    self.content = content

我们还将写一个简短的功能,该功能利用requests和Beautifulsoup通过其URL刮擦给定文章:

import requests
from bs4 import BeautifulSoup


def scrape_webpage(url):
  response = requests.get(url, headers=headers)
  soup = BeautifulSoup(response.content, 'html.parser')
  return soup

我们现在想开始将HTML处理到文档中的工作。首先,让我们编写一个将网页转换为标记文本的函数:

from html2text import html2text


def webpage_to_markdown(soup):
  # Find the article body, either by `class_='article__body'` or `class_='article-body'`
  article_body = soup.find(class_='article__body')
  if article_body is None:
    article_body = soup.find(class_='article-body')

  # Extract the HTML content from the article body
  html_content = str(article_body)

  # Convert the HTML content into markdown
  markdown_content = html2texthtml2text(html_content, bodywidth=0)
  return markdown_content

为了使内容更容易为chatgpt提供,我们将制作一个函数,从sarkdown内容剥离链接,并仅用链接的文本代替它们。我们可以使用正则表达式这样做,例如:

import re


def strip_links_from_markdown(markdown_content):
  # Make a RegEx pattern
  link_pattern = re.compile(r'\[(.*?)\]\((.*?)\)')

  # Find all matches in markdown_content
  matches = link_pattern.findall(markdown_content)

  for _match in matches:
    full_match = f'[{_match[0]}]({_match[1]})'

    # Replace the full link with just the text
    markdown_content = markdown_content.replace(full_match, _match[0])

  return markdown_content

最后,将文章通过宣传标题将文章分为多个文档。

def split_markdown_by_headings(markdown_content):
  # Define the regular expression pattern to match H1 and H2 headings
  pattern = r'(#{1,2}.*)'

  # Split the Markdown text based on the headings
  sections = re.split(pattern, markdown_content)

  # Combine each heading with its corresponding text
  combined_sections = []
  for i in range(1, len(sections), 2):
    heading = sections[i].strip()  # Get the heading from sections[i]
    text = sections[i + 1].strip() if i + 1 < len(
        sections) else ''  # Get the text from sections[i + 1] if it exists, otherwise use an empty string
    combined_section = f"{heading}\n{text}"  # Combine the heading and text using a newline character
    combined_sections.append(combined_section)  # Add the combined section to the list

  if len(combined_sections) == 0:
    combined_sections = [markdown_content]

  return combined_sections

现在,我们拥有参考文献中的所有逻辑和刮擦和过程文章。我们可以将其放在一个函数中,create_documents_from_webpage

def create_documents_from_webpage(url):
  # Wrap function in a try-except block to handle any potential exceptions
  try:
    soup = scrape_webpage(url)

    # Extract the title from the article
    title = soup.find('h1').get_text().strip()

    # Convert the webpage HTML to markdown
    markdown_content = webpage_to_markdown(soup)

    # Strip links from the markdown content
    markdown_content = strip_links_from_markdown(markdown_content)

    # Split the article up headings
    contents_by_heading = split_markdown_by_headings(markdown_content)
    docs = []
    for content in contents_by_heading:
      docs.append(Document(title=title, url=url, content=content))
    return docs
  except:
    return []

使用此功能,我们可以提供参考文献中的任何URL,它将生成一个文档列表,其中包括每个子标题的内容。

生成资源的数据库

现在,我们拥有刮擦和处理文章所需的所有逻辑,我们可以继续生成聊天机器人将使用的营养资源数据库。为此,我们必须迭代参考文献中的每篇文章,并保存所有创建的文档。

我们将在generate_databank函数中整理所有以前的工作:

def generate_databank():
  docs = []

  # Get all of the links in the Reference
  all_links = get_all_links_from_reference()

  # Iterate through every link in the Reference
  for link in all_links:
    # Add all of the documents created from the article
    docs_from_article = create_documents_from_webpage(link)
    docs.extend(docs_from_article)

  return docs

随时添加其他调试评论,例如当前正在处理的链接,剩下多少个链接,添加了多少个文档等等,等等。

运行generate_databank后,我们现在有一个营养资源的数据库!

请记住,这可能是一个记忆密集的过程,根据您的计算机,您可能需要考虑在像Google Colab这样的托管环境中运行此程序。我能够在我的2023 M2 Pro MacBook Pro上运行此程序,但结果可能会因您的特定设置而有所不同。

结论

通过遵循本文中的步骤,我们利用了现实世界的网络剪贴技术来从Internet收集和处理信息,并创建一个源数据库;此数据库将用于为我们的营养聊天机器人提供可靠的信息。

我们使用美丽的小组库和requests库来爬网,浏览WebMD Health&Diet Medical Reference,并写了功能以将网页转换为Markdown Text,从Markdown内容中脱离链接,并通过Markdown标题将文章分开。最后,我们通过在参考文献中的所有页面上迭代并保存所有创建的所有文档,从而生成了营养来源的数据库。

在本系列的下一篇文章中,我们将使用sentence-transformers和faiss探索矢量存储索引,以将我们创建的数据库连接到LLM,例如ChatGpt。