🎯 一款可定制、具备反检测功能的云浏览器,由自主研发的 Chromium驱动,专为网页爬虫AI 代理设计。👉立即试用
返回博客

Ollama 网络爬虫:在无需 API 密钥的情况下运行本地 LLM 爬虫

Alex Johnson
Alex Johnson

Senior Web Scraping Engineer

23-Jul-2026

TL;DR:

  • Ollama在您自己的机器上运行提取模型,因此抓取程序的LLM步骤不需要API密钥,也不需要按令牌计费。
  • Ollama不负责获取数据。 本地模型没有浏览器,也无法访问网页网络;它仅对您提供的文本进行结构化处理。
  • 这个差距在一个脚本中显示出来。 对一个JavaScript渲染的演示页进行简单的GET请求会得到0个引用块;通过使用js_render的Scrapeless通用抓取API访问同样的URL则可以得到全部10个——而这个渲染的HTML就是模型读取的内容。
  • 本指南中的提取是真实的。 一次实时运行将三个渲染的引用块传给本地的qwen2.5:0.5b模型,得到每个引用的干净JSON返回,里面包含文本和作者——没有任何云调用。
  • 小型模型更希望减少噪音。 在模型查看内容之前,先将HTML裁剪到内容区域;在目标片段上使用0.5B模型速度快且准确,而完整页面则无法适应。
  • 抓取方面,免费开始。app.scrapeless.com 创建您的Scrapeless API密钥。

为什么在本地运行抓取器的模型

一个LLM抓取程序将页面内容转化为结构化记录,而该模型不必驻留在他人的云端。Ollama 在您的硬件上通过一个小型HTTP API运行开放模型,因此提取步骤不需要API密钥、没有速率限制,也不需要按令牌计费——在处理许多页面或处理您宁愿不发送给第三方的数据时非常有用。

本地模型无法执行的操作是获取数据。它没有浏览器,不持有会话,在JavaScript渲染的页面上,普通HTTP请求返回的只是标记,没有任何内容。因此,Ollama网页抓取程序由两层组成:获取层返回忠实渲染的HTML,而本地模型则作为提取层,负责将其转化为记录。本指南使用Scrapeless通用抓取API作为第一层。如果您想让本地模型进行实时网络搜索——模型调用搜索工具并推理结果——那是另一项工作,涵盖在本地LLM网络搜索指南中;本文的主题是从特定页面提取结构化数据。

先决条件

  • 安装并运行Ollama,并下载一个小型工具友好的模型:ollama pull qwen2.5:0.5b
  • 安装Python 3.9或更高版本,并确保有requests库。
  • 从仪表盘获取Scrapeless API密钥,并将其导出为SCRAPELESS_API_KEY

安装

下载一个小型模型并安装Python的依赖项。Ollama服务器在运行后监听localhost:11434

bash Copy
ollama pull qwen2.5:0.5b
pip install requests

将您的密钥保存在环境中,而不是源代码中:

bash Copy
export SCRAPELESS_API_KEY="sk_your_scrapeless_key"

获取模型可以实际读取的页面

提取质量受获取精度的限制,因此首先要从这里开始。在JavaScript渲染的页面上,普通HTTP客户端接收的文档与阅读器所见的文档不同——内容仅在脚本构建DOM后到达,这一生命周期定义于HTML脚本规范。一个脚本可以计算出差异:

python Copy
# fetch_rendered.py — 普通GET与服务器端渲染,同一URL
import os

import requests

URL = "https://quotes.toscrape.com/js/"
MARKER = '<div class="quote">'

plain = requests.get(URL, timeout=60).text
print("plain GET chars:", len(plain), "| quote blocks:", plain.count(MARKER))

resp = requests.post(
    "https://api.scrapeless.com/api/v2/unlocker/request",
    headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
    json={"actor": "unlocker.webunlocker", "input": {"url": URL, "js_render": True}},
    timeout=120,
)
resp.raise_for_status()
rendered = resp.json().get("data", "")
print("rendered chars:", len(rendered), "| quote blocks:", rendered.count(MARKER))

运行将为普通获取输出0个引用块,而对渲染获取的结果则为10:

text Copy
plain GET chars: 5806 | quote blocks: 0
rendered chars: 8940 | quote blocks: 10

渲染、解锁和代理路由都在那一次POST的服务器端完成——通用抓取API是获取层,而渲染的HTML就是本地模型提取的内容。

使用本地模型进行提取

现在将内容交给Ollama。保持小模型准确性的两个关键因素是:将HTML修剪到内容区域,以便模型不读取页面外观,并请求format: "json"以便输出可解析。Ollama的/api/generate端点接受模型名称和提示,并返回完成,具体记录在Ollama API参考中:

python Copy
# extract_local.py — 使用本地Ollama模型获取、修剪和提取
import json
import os
import re

import requests

resp = requests.post(
    "https://api.scrapeless.com/api/v2/unlocker/request",
    headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
    json={"actor": "unlocker.webunlocker", "input": {"url": "https://quotes.toscrape.com/js/", "js_render": True}},
    timeout=120,
)
resp.raise_for_status()
html = resp.json().get("data", "")

# 修剪到前面三个引用块 —— 小型本地模型在噪音更少的情况下效果更好。
blocks = re.findall(r'<div class="quote">.*?</small>', html, re.S)[:3]
snippet = "\n".join(blocks)

completion = requests.post(
    "http://localhost:11434/api/generate",
    json={
        "model": "qwen2.5:0.5b",
        "prompt": '从此HTML中提取每个引用到JSON,格式为完全相同的'
                  '{"quotes":[{"text":"...","author":"..."}]}。只回复JSON。\n\nHTML:\n' + snippet,
        "stream": False,
        "format": "json",
        "options": {"temperature": 0, "num_predict": 400},
    },
    timeout=600,
)
data = json.loads(completion.json()["response"])

records = data["quotes"]
print("记录数量:", len(records))
print("第一个作者:", records[0]["author"])
print("第一个文本:", records[0]["text"])

本地运行返回了三个记录,第一条的文本和作者完整:

text Copy
记录数量: 3
第一个作者: 阿尔伯特·爱因斯坦
第一个文本: 我们创造的世界是我们思维过程的结果。没有改变我们的思维,就无法改变它。

这就是整个爬虫,模型部分没有触及网络:一次POST请求到Scrapeless进行获取和渲染,一次调用localhost进行提取。根据硬件处理能力调整每次调用的块数——在CPU上,0.5B模型比云端端点慢,因此尽量批量处理小块并保持输入紧凑。

在免费计划上获取您的API密钥:app.scrapeless.com

高级模式

  • 根据硬件匹配模型。 qwen2.5:0.5b在CPU上足够快;如果您有内存和耐心,3B或7B模型在更复杂的页面上提取更可靠。请求的格式不变——只有model字符串改变。
  • 在提示之前修剪。 隔离内容容器是小模型质量的最大杠杆。发送重复的块,而不是整个文档,这样token成本和错误率都会降低。
  • 保持format: "json"temperature: 0 JSON模式限制输出为可解析的JSON,而零温度保持提取过程在多次运行中稳定;这两个对爬虫来说都是不可选的。
  • 在Python中循环,而不是在提示中。 每个请求一个内容区域可以防止记录混合在一起,并使坏提取可归因于特定页面。

故障排除

  • Connection refused在localhost:11434。 Ollama服务器未运行。启动它(ollama serve),并确认使用ollama list拉取了模型。
  • 没有块可提取。 您的获取返回了预渲染的HTML。像第一个脚本那样计算已知元素;几乎空的获取是渲染问题,通过js_render解决,而不是模型问题。
  • 模型返回文本而不是JSON。 您丢失了format: "json"。有了它,Ollama可以限制输出;没有它,您是在解析善意。
  • 提取缓慢或掉记录。 模型对于输入大小太小。每次调用修剪到更少的块,或切换到更大模型——小型本地模型在速度上牺牲了准确性,而更短、更清晰的提示是您恢复这两者的方法。

结论

Ollama赢得了作为提取层的地位,它在您所处的地方运行:在您自己的硬件上开启模型,无需密钥和每个token账单,将页面内容转换为JSON。决定这一切是否可能的层是获取——第一个脚本的0与10的计数决定了这一点——而一次服务器渲染的POST填补了空白。将两者连接起来,一个渲染的页面变成了结构化记录,而模型部分完全保持在localhost上。
创建一个免费的Scrapeless账户以获取API密钥, 开发者文档 介绍了unlocker.webunlocker参数。当您计划一个定期作业时,请查看 Scrapeless定价

常见问题解答

问:Ollama可以自己抓取网站吗?

不可以。Ollama在本地运行语言模型;它没有针对任意页面的HTTP客户端,也不渲染任何JavaScript。它结构化您提供的文本。将其与抓取层配对——这里是Scrapeless通用抓取API,它在服务器端渲染页面——然后本地模型负责提取。

问:这与给本地LLM网页搜索有何不同?

方向。网页搜索设置允许模型调用搜索工具并通过结果推理以回答问题;此设置获取您选择的特定页面并让模型从中提取结构化字段。一个是增强搜索的回答,另一个是抓取管道——上述链接的本地LLM网页搜索指南涵盖了前者。

问:我应该使用哪个本地模型进行提取?

最小的模型,它能容纳您的架构。使用严格JSON提示和temperature: 0的提取不需要大量推理,因此0.5B模型在修剪的片段上运行良好,正如上面的运行所示。仅当页面混乱到小模型无法提取字段时,才切换到3B或更大的模型。

问:我需要GPU吗?

不需要。本指南中的运行使用了0.5B模型在CPU上。GPU使较大模型更实用且更快,但在CPU上运行的小模型足以构建和测试管道。

问:使用本地模型抓取是否合法?

在本地运行模型并不会改变收集规则。仅获取公共页面,尊重网站条款和机器人排除协议标准化的robots指令,保持数量有限,并在适用的法律下处理任何个人数据。

在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。

最受欢迎的文章

目录