作者 | 崔皓
審校 | 重樓
開篇
在AIGC(人工智能與通用計算)應(yīng)用中,大型語言模型(LLM)占據(jù)著舉足輕重的地位。這些模型,如GPT和BERT系列,通過處理和分析龐大的數(shù)據(jù)集,已經(jīng)極大地推動了自然語言理解和生成的邊界。它們在多種應(yīng)用中表現(xiàn)出色,如文本生成、語言翻譯、情感分析等,對提高工作效率和展開創(chuàng)新的應(yīng)用場景起著關(guān)鍵作用。
然而,LLM在處理實時數(shù)據(jù)方面存在一定的局限性。這些模型主要基于大量歷史數(shù)據(jù)進行訓(xùn)練,因此,在理解和分析實時或最新信息時可能不夠靈敏。在應(yīng)對新興話題或最新發(fā)展趨勢時,LLM可能無法提供最準確的信息,因為這些內(nèi)容可能尚未包含在其訓(xùn)練數(shù)據(jù)中。此外,LLM在快速處理和反應(yīng)實時變化方面也面臨挑戰(zhàn),尤其是在需要分析和反映最新市場動態(tài)、政策變化或社會事件時。
既然我們已經(jīng)意識到了大型語言模型(LLM)在處理實時數(shù)據(jù)方面的局限性,那么下一步就是探索如何通過Web Research技術(shù)突破這一限制。下面的內(nèi)容將專注于如何通過網(wǎng)絡(luò)爬蟲技術(shù)結(jié)合LLM,實現(xiàn)對實時網(wǎng)絡(luò)資源的有效獲取和分析。
整體思路
Web Research 結(jié)合 LLM 的整體思路是復(fù)雜的過程,旨在利用大型語言模型的自然語言處理能力,實現(xiàn)對互聯(lián)網(wǎng)數(shù)據(jù)的高效處理和分析。如下圖所示,我們將整個過程進行拆解:
1. 實時網(wǎng)絡(luò)請求:首先,對目標網(wǎng)站發(fā)起實時請求,以獲取最新的數(shù)據(jù)和內(nèi)容。
2. 獲取HTML頁面:使用網(wǎng)站的URLs來訪問和加載HTML頁面,此時,網(wǎng)頁的數(shù)據(jù)將被加載到內(nèi)存中。
3. 內(nèi)容轉(zhuǎn)換:隨后,將加載的HTML頁面轉(zhuǎn)換為文本信息,為后續(xù)的處理步驟做準備。這通常涉及去除HTML標記和格式化內(nèi)容,以提取純文本數(shù)據(jù)。
4. 數(shù)據(jù)存儲和分類:轉(zhuǎn)換后的文本數(shù)據(jù)可以存儲在向量庫中,以便于進行高效的檢索和分析。同時,可以利用LLM對內(nèi)容進行分類和組織,以便快速訪問相關(guān)信息。
5.生成摘要:最后,利用LLM的功能調(diào)用來生成文本數(shù)據(jù)的摘要。這不僅包括提取關(guān)鍵信息,還可能涉及對數(shù)據(jù)進行綜合和解釋,以便用戶能夠快速理解內(nèi)容的核心要點。
通過這樣的流程,我們能夠結(jié)合LLM的強大文本處理功能和網(wǎng)絡(luò)爬蟲技術(shù)的實時數(shù)據(jù)訪問能力,有效地處理和分析大量的在線信息。這種方法不僅提高了信息處理的速度和準確性,而且通過摘要和分類,使得用戶能夠更容易地獲取和理解需要的數(shù)據(jù)。
關(guān)鍵問題
為了驗證Web爬蟲和大型語言模型結(jié)合的研究思路是否切實可行,可以以知名新聞網(wǎng)站W(wǎng)all Street Journal(華爾街日報)為例進行實證分析。假設(shè)從該網(wǎng)站的首頁,獲取實時的新聞信息,并且將這些信息進行抽取,最終保存為包括“標題”和“摘要”的結(jié)構(gòu)化信息, 以便后續(xù)查找和分析。從過程描述中發(fā)現(xiàn),將面臨三個主要的技術(shù)挑戰(zhàn):加載、轉(zhuǎn)換以及通過LLM進行內(nèi)容抽取。
1.加載HTML:我們可以訪問 https://www.wsj.com,使用網(wǎng)絡(luò)爬蟲工具獲取網(wǎng)站的HTML內(nèi)容。這一步涉及發(fā)送HTTP請求并接收返回的網(wǎng)頁代碼。
2. 轉(zhuǎn)換為文本:分析該網(wǎng)站的HTML結(jié)構(gòu)表明,文章標題和摘要信息通常包含在`<span>`標簽中。如下圖所示,文章的標題是在`<span>`標簽中。
如下圖所示,我們觀察到,文章的摘要也是保存在<span>標簽中。
因此需要利用HTML解析庫,如BeautifulSoup,從HTML中提取這些標簽的內(nèi)容,并將其轉(zhuǎn)換為純文本格式。
3. LLM處理:有了純文本數(shù)據(jù)后,我們將使用大型語言模型來進一步處理這些文本。這可能包括內(nèi)容分類、關(guān)鍵信息提取、摘要生成等。
在這個例證中,我們將如何確保網(wǎng)絡(luò)爬蟲精準地抓取所需信息,以及如何調(diào)整大型語言模型以精確處理和提取有價值的內(nèi)容,都是需要解決的問題。通過成功實施這一流程,我們不僅驗證了LLM與Web爬蟲結(jié)合的有效性,還進一步探索了如何通過自動化工具提高研究和分析的效率。
數(shù)據(jù)加載
通過上面對關(guān)鍵問題的分析,讓我們先為即將進行的技術(shù)旅程做好準備。從網(wǎng)頁內(nèi)容的加載到信息的轉(zhuǎn)換,再到利用LLM提取關(guān)鍵數(shù)據(jù),都是構(gòu)建有效網(wǎng)絡(luò)研究工具的關(guān)鍵環(huán)節(jié)。
首先,我們將面對的挑戰(zhàn)是如何高效地加載網(wǎng)頁內(nèi)容。異步HTML加載器(AsyncHtmlLoader)扮演著至關(guān)重要的角色。使用aiohttp庫構(gòu)建的AsyncHtmlLoader能夠進行異步HTTP請求,非常適合于簡單輕量級的網(wǎng)頁抓取工作。這意味著它能夠同時處理多個URL的請求,提高了數(shù)據(jù)抓取的效率,特別是當我們需要從多個網(wǎng)站快速獲取信息時。
對于那些更復(fù)雜的網(wǎng)站,其中的內(nèi)容可能依賴于JavaScript渲染,我們可能需要更強大的工具,例如AsyncChromiumLoader。這個加載器利用Playwright來啟動一個Chromium實例,它不僅可以處理JavaScript渲染,還可以應(yīng)對更復(fù)雜的Web交互。Playwright是一個強大的庫,支持多種瀏覽器自動化操作,其中Chromium就是一個被廣泛支持的瀏覽器。
Chromium可以在無頭模式下運行,即沒有圖形用戶界面的瀏覽器,這在網(wǎng)頁抓取中很常見。在無頭模式下,瀏覽器后臺運行,執(zhí)行自動化任務(wù),而用戶不會看到任何的瀏覽器窗口。這樣的操作對于服務(wù)器端的抓取任務(wù)尤其有用,因為它們可以模擬瀏覽器中的完整用戶交互過程,而不需要實際顯示界面。
無頭模式,或稱為“無界面模式”,是一種在不打開圖形界面的情況下運行應(yīng)用程序的方式。想象一下,你的電腦在執(zhí)行一些任務(wù),如下載文件、刷新數(shù)據(jù)或運行一個復(fù)雜的計算過程,而這一切都在沒有打開任何窗口的情況下靜靜進行。這正是無頭模式的工作原理。
在Web開發(fā)和自動化測試領(lǐng)域,無頭模式尤為有用。例如,開發(fā)者可能需要測試一個網(wǎng)頁在不同瀏覽器中的表現(xiàn),但并不需要真正地視覺上檢查這些網(wǎng)頁,而是要檢查代碼的運行結(jié)果。在這種情況下,他們可以使用無頭模式的瀏覽器來模擬用戶的行為,如點擊鏈接、填寫表單等,同時瀏覽器本身不會在屏幕上顯示。
實際上,我們介紹了AsyncHtmlLoader和AsyncChromiumLoader兩種加載器,本例中我們使用前者就足夠了,其示例代碼如下:
from langchain.document_loaders import AsyncHtmlLoader
urls = ["https://www.wsj.com"]
loader = AsyncHtmlLoader(urls)
docs = loader.load()
代碼創(chuàng)建一個加載器實例并傳入需要抓取的URL列表。隨后,調(diào)用`load`方法就會異步加載這些頁面的內(nèi)容。
文本轉(zhuǎn)換
解決了數(shù)據(jù)加載的問題,讓我們把目光轉(zhuǎn)向文本轉(zhuǎn)換。文本轉(zhuǎn)換是網(wǎng)絡(luò)爬蟲技術(shù)中的一個重要環(huán)節(jié),它負責將抓取的HTML內(nèi)容轉(zhuǎn)換成便于處理的純文本格式。在這一階段,我們可以選用不同的工具,根據(jù)不同的需求來實現(xiàn)這一轉(zhuǎn)換。
首先是HTML2Text,這是一個直接將HTML內(nèi)容轉(zhuǎn)換為純文本的工具,生成的格式類似于Markdown。這種轉(zhuǎn)換方法適合于那些目標是提取可讀文本而不需要操作特定HTML標簽的場景。它簡化了轉(zhuǎn)換流程,能夠迅速提供一個干凈的文本版本,適合閱讀和進一步分析。
而Beautiful Soup則提供了更細粒度的控制能力。使用Beautiful Soup,我們可以執(zhí)行特定標簽的提取、刪除和內(nèi)容清理,這對于需要從HTML內(nèi)容中提取特定信息的場景來說非常適合。例如,如果我們需要從一個新聞網(wǎng)站中提取文章標題和摘要,而這些內(nèi)容是通過`<span>`標簽來標識的,Beautiful Soup就可以精確地定位這些標簽并提取它們的內(nèi)容。
在實際操作中,我們可以先使用AsyncHtmlLoader來加載目標網(wǎng)站的文檔。接著,我們可以使用Html2TextTransformer來對加載的HTML文檔進行轉(zhuǎn)換。如下代碼所示:
from langchain.document_loaders import AsyncHtmlLoader
from langchain.document_transformers import Html2TextTransformer
urls = ["https://www.wsj.com"]
loader = AsyncHtmlLoader(urls)
docs = loader.load()
html2text = Html2TextTransformer()
docs_transformed = html2text.transform_documents(docs)
以上代碼演示了如何將加載的HTML文檔轉(zhuǎn)換為文本。這樣,我們就可以得到一個文本版本的文檔,其中包含了從原始HTML中提取出來的文本內(nèi)容。
信息抽取
當我們準備好了數(shù)據(jù)之后,接下來的重要步驟是數(shù)據(jù)的抽取,這是大型語言模型(LLM)發(fā)揮作用的時刻。網(wǎng)絡(luò)爬蟲面臨的挑戰(zhàn)之一是現(xiàn)代網(wǎng)站布局和內(nèi)容不斷變化,這要求我們不停地修改爬蟲腳本以適應(yīng)這些變化。通過結(jié)合OpenAI的功能調(diào)用(Function)和抽取鏈(Extraction Chain),我們可以避免在網(wǎng)站更新時不斷更改代碼。
為了確保我們能夠使用OpenAI Functions特性,我們選擇使用`gpt-3.5-turbo-0613`模型。同時,為了降低LLM的隨機性,我們將溫度參數(shù)(temperature)設(shè)置為0。
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613")
接下來,我們定義一個數(shù)據(jù)抽取模式(Schema),以指定我們想要抽取的數(shù)據(jù)類型。在這里,關(guān)鍵字的命名非常重要,因為它們告訴LLM我們想要的信息類型。所以,描述時要盡可能詳細。
例如,在本例中,我們想要從華爾街日報網(wǎng)站抽取新聞文章的標題和摘要。
from langchain.chains import create_extraction_chain
schema = {
"properties": {
"news_article_title": {"type": "string"},
"news_article_summary": {"type": "string"},
},
"required": ["news_article_title", "news_article_summary"],
}
然后,我們可以定義一個抽取函數(shù),它使用定義的模式和LLM來運行內(nèi)容抽取。
def extract(content: str, schema: dict):
return create_extraction_chain(schema=schema, llm=llm).run(content)
通過這種方式,LLM可以從文本中精確地抽取出我們需要的信息,并生成我們需要的結(jié)構(gòu)化數(shù)據(jù)。這種結(jié)合了LLM的抽取鏈的方法,不僅提高了數(shù)據(jù)處理的準確性,也極大地簡化了我們處理網(wǎng)站內(nèi)容變化的工作。
代碼實施
解決三個關(guān)鍵文字之后,我們將生成整體代碼如下,代碼展示了如何使用Playwright結(jié)合LangChain庫來實現(xiàn)一個完整的網(wǎng)絡(luò)爬蟲和內(nèi)容抽取的工作流。
import pprint
from langchain.text_splitter import RecursiveCharacterTextSplitter
def scrape_with_playwright(urls, schema):
loader = AsyncChromiumLoader(urls)
docs = loader.load()
bs_transformer = BeautifulSoupTransformer()
docs_transformed = bs_transformer.transform_documents(
docs, tags_to_extract=["span"]
)
print("Extracting content with LLM")
# Grab the first 1000 tokens of the site
splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=1000, chunk_overlap=0
)
splits = splitter.split_documents(docs_transformed)
# Process the first split
extracted_content = extract(schema=schema, content=splits[0].page_content)
pprint.pprint(extracted_content)
return extracted_content
urls = ["https://www.wsj.com"]
extracted_content = scrape_with_playwright(urls, schema=schema)
下面是代碼解釋:
1. 首先,導(dǎo)入了必要的庫和工具,包括用于打印的`pprint`和LangChain中的文本拆分器`RecursiveCharacterTextSplitter`。
2. 定義了一個`scrape_with_playwright`函數(shù),該函數(shù)接收`urls`和`schema`作為參數(shù)。這里的`urls`是想要爬取的網(wǎng)站地址列表,而`schema`定義了想要從這些網(wǎng)頁中抽取的數(shù)據(jù)結(jié)構(gòu)。
3. 在函數(shù)內(nèi)部,創(chuàng)建了一個`AsyncChromiumLoader`實例并傳入了URL列表。這個加載器負責異步獲取每個URL對應(yīng)網(wǎng)頁的HTML內(nèi)容。
4. 接著,使用Beautiful Soup轉(zhuǎn)換器`BeautifulSoupTransformer`來處理加載的HTML文檔。在這個例子中,我們特別關(guān)注于`<span>`標簽,因為我們假設(shè)這些標簽包含了新聞文章的標題和摘要信息。
5. 使用`RecursiveCharacterTextSplitter`創(chuàng)建一個分割器實例,它基于給定的`chunk_size`(這里是1000個字符)來拆分文檔內(nèi)容。這是為了處理大型文檔時,能夠?qū)⑵浞指畛尚K以適應(yīng)LLM處理的限制。
6. 處理拆分后的第一部分內(nèi)容,并通過`extract`函數(shù)(需要定義)來抽取出符合`schema`定義的數(shù)據(jù)。
7. 最后,使用`pprint`打印出抽取的內(nèi)容,并將其作為函數(shù)的返回值。
這個流程從頭到尾將網(wǎng)頁爬取、內(nèi)容轉(zhuǎn)換和數(shù)據(jù)抽取整合在一起,形成了一個端到端的解決方案,可以在不需要人工干預(yù)的情況下從網(wǎng)頁中提取有結(jié)構(gòu)的數(shù)據(jù)。
查看結(jié)果如下圖所示,由于網(wǎng)頁內(nèi)容比較多,我們選取其中一組數(shù)據(jù)來觀察,這里將新聞的標題和摘要進行了分割。
同時,結(jié)合之前研究網(wǎng)站頁面的截圖進行參考如下,“House Authorizes Formally Opening GOP’s Biden Impeachment Probe”這篇文章被我們通過網(wǎng)頁加載、文本轉(zhuǎn)換,大模型抽取的方式獲得了。
總結(jié)
本文詳細說明了利用網(wǎng)絡(luò)爬蟲技術(shù)和LLM結(jié)合的流程,通過案例分析驗證了這一思路的可行性。從實時獲取華爾街日報網(wǎng)站的數(shù)據(jù)開始,文章闡述了如何通過異步HTML加載器、文本轉(zhuǎn)換工具、以及LLM進行精準的內(nèi)容抽取,最終形成一個自動化、高效的網(wǎng)絡(luò)研究工具。這不僅展示了LLM與網(wǎng)絡(luò)爬蟲技術(shù)結(jié)合的強大潛力,還探討了如何提高研究和分析效率。
作者介紹
崔皓,51CTO社區(qū)編輯,資深架構(gòu)師,擁有18年的軟件開發(fā)和架構(gòu)經(jīng)驗,10年分布式架構(gòu)經(jīng)驗。