Ollama Vision ウェブスクレイピング: ローカルモデルでスクリーンショットを読み取る
Senior Cybersecurity Analyst
TL;DR:
- これはローカルモデルとスクリーンショットの組み合わせであり、このサイトの既存のガイドでは単独ではカバーされていません。 Ollama ウェブスクレイピング はレンダリングされた HTML テキスト上でローカルモデルを実行しますが、スクリーンショットではありません。クラウドビジョン API はスクリーンショットを読み取りますが、画像ごとに請求され、キーが必要です。このガイドは、実際のブラウザのスクリーンショットに対してローカルの視覚対応モデルを実行します — クラウドキーなし、トークンごとの請求なし、HTML も全くありません。
- ここでのすべての実行は CPU のみで Ollama を使用し、
ollama psで確認できます。 この環境では Ollama に GPU オフロードは利用できず、呼び出し間でのタイミングは大きく変動します — メモリにモデルがまだ格納されているかどうかによって、10 秒台から数分までの範囲です。 - Ollama の画像フィールドはクラウドフォーマットではありません。 Ollama の
/api/generateにあるimagesフィールドは、data:image/png;base64,プレフィックスなしの生の base64 文字列のリストを取ります — これはほとんどのクラウドビジョン API が使用する OpenAI 互換の規則とは逆です。 - サブ 2B の視覚モデルは、異なる方法でタスクの両端で信頼性がありません。 ページを1文で説明するように求められると、実際のページとは合致しない構造的な詳細を名前付けしました。構造化された JSON レコードを求められると — クラウドビジョンの兄弟がクリーンに処理する正確なタスク — プロンプトのプレースホルダー テキストを反響させ、その後全く JSON ではない出力に漂流しました。
- スクリーンショットは依然として実際のレンダリングされたブラウザから来ています。 Scrapeless スクレイピングブラウザは、クラウドビジョンパイプラインが行うのと同じように CDP 経由でページをキャプチャします。ピクセルを読み取る場所だけが、その後の変更点となります。
- 取得側では無料で開始可能です。 app.scrapeless.com で Scrapeless API キーを作成してください。
なぜローカルモデルをスクリーンショットと組み合わせるのか
「AI ウェブスクレイピング」について通常は別々で真実で、めったに一緒には真実ではない2つのことがあります。 Ollama を介して実行されるローカルモデルは呼び出しごとに何もコストがかからず、サードパーティに何も送信しません — しかし、このサイトのローカルモデルガイドは、これまでのところレンダリングされた HTML テキストを読んでおり、ピクセルではありません。ビジョンモデルはDOMの代わりにスクリーンショットを読み取りますが、このサイトのビジョンモデルガイドはこれまでのところ、画像ごとに請求されクラウドプロバイダーキーが必要なクラウドAPIを呼び出しています。この投稿は、どちらもカバーしていない組み合わせです:目の前のマシン上で完全に実行される視覚対応モデルが、実際のブラウザのスクリーンショットを読み取り、パイプラインのどこにもクラウド推論の請求がありません。
既存の2つのガイドは、それぞれが得意とすることについて有用なままです。Ollama ウェブスクレイピング は、必要な値がすでにレンダリングされた DOM のテキストである場合に正しい選択です — ローカルモデルはトリミングされた HTML スニペットで高速かつ正確です。このサイトの GPT Vision ウェブスクレイピングガイド は、本当に視覚的な価値があり、それを読むために能力のある有料モデルを必要とする場合に正しい選択です。このガイドは第3のケースのためのもので、バリューは視覚的ですがクラウド依存はゼロであることを望み、そのために能力とトレードオフすることに同意する場合です。そのトレードオフはリアルであり、このガイドは機能する部分だけを示すのではなく、誠実に報告します。
前提条件
- Ollama がインストールされ実行されており、視覚対応モデルをプルしていること:
ollama pull moondream。 - Python 3.9 以降が
playwrightとrequestsとともに必要です。 - ダッシュボードからの Scrapeless API キーが
SCRAPELESS_API_KEYとしてエクスポートされています。 app.scrapeless.com で無料のキーを入手してください。 - GPU は必要ありません。このガイドのすべての実行は CPU のみで Ollama を使用しました。
インストール
bash
pip install playwright requests
ollama pull moondream
playwright は、CDP 経由でリモートブラウザに接続してこのガイドで使用されるため、ローカル Chromium のダウンロードは必要ありません。 moondream はコンパクトな視覚対応モデルで、離散 GPU なしでプルして実行できるサイズです。このガイドの目的です。
構成
bash
export SCRAPELESS_API_KEY="your_scrapeless_api_key"
これは、このパイプラインが必要とする唯一のキーです。Ollama のローカル API は、認証情報を一切受け付けません。
スクレイピングブラウザでスクリーンショットをキャプチャ
スクリーンショットは依然として忠実である必要があるため、実際のブラウザから取得されます。Chrome DevTools プロトコルを介して Scrapeless スクレイピングブラウザに接続し、ページを開いて、レンダリングされたビューポートをキャプチャします — 同じキャプチャ手順はクラウドビジョンの兄弟が使用します。 Chrome DevTools プロトコル:
python
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright
def browser_url():
return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
{"token": os.environ["SCRAPELESS_API_KEY"], "sessionTTL": 180, "proxyCountry": "US"})
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(browser_url())
page = browser.new_page(viewport={"width": 1280, "height": 900})
page.goto("https://quotes.toscrape.com/", wait_until="networkidle")
png = page.screenshot()
browser.close()
print("screenshot bytes:", len(png))
print("PNG signature ok:", png[:8] == b"\x89PNG\r\n\x1a\n")
text
screenshot bytes: 55462
PNG signature ok: True
あなたのAPIキーを無料プランで取得してください: app.scrapeless.com
ローカルビジョンモデルでスクリーンショットを読む
PNGをBase64エンコードし、Ollamaのローカル /api/generate エンドポイントに直接ポストします。ここが2つの軸が実際に交わる場所です: 画像は実際のクラウドレンダリングブラウザから来ていますが、それを読み取るモデルはこのマシンから一度も出ていきません。リクエストの形式はOllama APIリファレンスに文書化されており、imagesフィールドはプレーンなbase64文字列を取ります。data:image/png;base64,... URLではありません:
python
import base64, os, time
from urllib.parse import urlencode
import requests
from playwright.sync_api import sync_playwright
def browser_url():
return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
{"token": os.environ["SCRAPELESS_API_KEY"], "sessionTTL": 180, "proxyCountry": "US"})
t0 = time.time()
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(browser_url())
page = browser.new_page(viewport={"width": 1280, "height": 900})
page.goto("https://quotes.toscrape.com/", wait_until="networkidle")
png = page.screenshot()
browser.close()
capture_s = round(time.time() - t0, 1)
img_b64 = base64.b64encode(png).decode()
t1 = time.time()
resp = requests.post(
"http://localhost:11434/api/generate",
json={
"model": "moondream",
"prompt": "Describe what this webpage shows in one sentence.",
"images": [img_b64],
"stream": False,
"options": {"temperature": 0, "num_predict": 60},
},
timeout=300,
)
resp.raise_for_status()
data = resp.json()
inference_s = round(time.time() - t1, 1)
print("capture seconds:", capture_s)
print("vision inference seconds:", inference_s)
print("description:", data["response"].strip())
text
capture seconds: 11.5
vision inference seconds: 54.7
description: A webpage titled "Quotes to Scrape" displays a list of quotes and their corresponding tags, organized into five sections.
タイトル、引用の存在、およびそれぞれの下のタグはすべてレンダリングされたページの実際の要素です。その上に追加される特定の構造「5つのセクションに整理されている」は、実際のページに対して検証できません: quotes.toscrape.comはフロントページに10の引用ブロックをレンダリングし、何のグループ化も行っていません。このモデルはページの一般的な主題、タグのある引用サイトを正しく捉え、実際には存在しない特定の構造的詳細を述べます。
このクラスの呼び出し中のollama psは100% CPUを報告します: この環境ではOllamaにGPUのオフロードは利用できません。このような呼び出しのタイミングはモデルの状態によっても変わります。Ollamaの/api/generateエンドポイントは、各リクエストの後にkeep_aliveの間モデルをメモリに保持します。デフォルトでは5分で、上記のOllama APIリファレンスに文書化されています。モデルがまだメモリに保持されている間に行われた呼び出しは、ディスクからの再ロードをスキップし、何も保持されていないコールは、最初のトークンが返される前にそのロード時間を支払います。
構造化抽出が崩れる場所
動作する説明は、信頼できる抽出と同じではありません。同じモデルに、クラウドビジョンの兄弟がクリーンなパスで処理する完全なタスク — 引用記録のJSON配列 — を求めると、正直な結果はこのガイドにも含まれます:
python
import base64, json, os, time
from urllib.parse import urlencode
import requests
from playwright.sync_api import sync_playwright
def browser_url():
return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
{"token": os.environ["SCRAPELESS_API_KEY"], "sessionTTL": 180, "proxyCountry": "US"})
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(browser_url())
page = browser.new_page(viewport={"width": 1280, "height": 900})
page.goto("https://quotes.toscrape.com/", wait_until="networkidle")
png = page.screenshot()
browser.close()
img_b64 = base64.b64encode(png).decode()
t1 = time.time()
resp = requests.post(
"http://localhost:11434/api/generate",
json={
"model": "moondream",
"prompt": 'From this screenshot of a quotes page, return JSON '
'{"quotes":[{"author":"...", "text":"..."}]} for the first 3 quotes '
'you can see. Return ONLY JSON.',
"images": [img_b64],
"stream": False,
"format": "json",
"options": {"temperature": 0, "num_predict": 150},
},
timeout=600,
)
resp.raise_for_status()
data = resp.json()
inference_s = round(time.time() - t1, 1)
print("vision inference seconds:", inference_s)
print("raw response:", data["response"][:200])
try:
parsed = json.loads(data["response"])
print("parsed quotes:", len(parsed.get("quotes", [])))
except json.JSONDecodeError as e:
print("JSON parse failed:", e)
text
vision inference seconds: 79.6
raw response: {"quotes":[{"author":"...","text":"..."},{"author":"","text":"","}}] } [0.12, 0.13, 1.0, 0.87] ) ; return [0.12, 0.13, 1.0, 0.87] ; return [0.12, 0.13, 1.0, 0.87] ; return [0.12, 0.13, 1.0, 0.87] ; re
JSON parse failed: Unterminated string starting at: line 1 column 65 (char 64)
最初のオブジェクトは、プロンプトの"..."プレースホルダー構文をそのままエコーします。指示の中のエリプシスがスロットを埋めるための値ではなく、コピーする値のように見えます。2番目のオブジェクトは適切に閉じず、レスポンスはその後、引用、著者、またはJSONとは全く無関係な4桁の配列と迷子のreturnステートメントに漂流します — 出力は、このタスクの壊れた試みよりも異なるタスクの残り物のように読み取れます。このガイドの背後のすべてのライブ実行を通じて、基礎となるパターンは、正確なガーベッジの形が変わる中でも維持されました: 本物の引用テキストや著者名は一度も戻らず、レスポンスは一度も有効なJSONとして閉じませんでした。それは本物の結果であり、切り捨てられたログではありません: moondreamはおよそ10億パラメータのモデルであり、大きなクラウドビジョンモデルが数秒で3つのクリーンで正しく属性されたレコードを返せるスキーマに従った動作は、この小さなモデルには再現されません。出力長の上限を引き上げてもパターンは修正されず、主にモデルに漂流するための余裕を与えます。
このサイトのGPT Visionウェブスクレイピングガイドは、その貿易の反対側を示しています。OpenAIのAPIを通じて実行されるホスティングされたマルチモーダルモデル、GPT-4o-miniは、Playwrightスクリーンショットを実際に埋め込む構造化された製品と価格フィールドに変換します。その比較は、無料の10億パラメータのローカルモデルに対して、はるかに能力の高い有料モデルの一部であり、ローカルで実行する理由の一部でもあります。
ローカルビジョン vs. クラウドビジョン vs. ローカルテキスト
このサイトの3つのガイドでは、手書きのセレクターなしでページから構造化データを取得するための3つの異なるトレードオフをカバーしています:
| モデルの場所 | 読み取り | コールごとのコスト | 構造化JSONの正確性 | |
|---|---|---|---|---|
| Ollamaウェブスクレイピング | ローカル | レンダリングされたHTMLテキスト | 無料 | 整理されたHTMLで信頼性あり |
| GPT Visionウェブスクレイピングガイド | クラウド | スクリーンショット | 画像ごとに、クラウドキーが必要 | はるかに大きな有料モデル — このガイドではベンチマークされていません |
| このガイド | ローカル | スクリーンショット | 無料 | このモデルのサイズでは信頼できない |
| どの三つも普遍的に正しいわけではありません。もし値がDOM内のテキストであれば、DOMを解析してください — ローカルテキストモデルやプレーンセレクタは、どんなビジョンパイプラインよりも速く、安価です。もし値が本当に視覚的で精度が重要であれば、クラウドビジョンモデルはその画像ごとのコストを正当化します。このサイズのローカルビジョンモデルはいずれよりも狭いケースに適合します:探索的または低リスクの読み取りで、人間や下流のチェックが時折の誤った詳細を捉えることができる場面です。一方、無監視で出力を信頼するパイプラインではありません。上記の証拠に基づき、これは緩やかな1文の説明でも厳格な複数フィールドのスキーマでも同様です — 失敗モードは各々異なって見えるだけです。 |
結論
ローカルモデルとスクリーンショットを組み合わせることで、このサイトの既存のガイド間の実際のギャップが埋まります。パイプラインの中の何もクラウドモデルには触れません:Scrapeless Scraping Browserはまだページを表示し、クラウドビジョンパイプラインが行う方法と同じようにキャプチャします。そしてOllamaはこのマシン上で結果として得られたPNGを完全に読み取ります。その組み合わせが実際に有用であるのは、ここでの証拠から見て、クラウドビジョンモデルよりも狭い範囲です — 1文の説明がページには存在しない構造的な詳細を加え、厳格なJSONスキーマが自身のプレースホルダーテキストを反映し、まったくJSONでない出力に流れていきました。このサイズのモデルは、確認する予定の探索的な読み取りに使用し、結果を無監視で信頼するパイプラインには使用しないでください。また、抽出が正確である必要がある場合は、クラウドビジョンガイドを参照してください。
無料のScrapelessアカウントを作成してAPIキーを取得し、Scraping Browser製品ページでCDPセッションがサポートする内容を確認し、Scrapelessの料金をレビューしてから、スケールでブラウザ側を実行してください。
ローカル抽出パイプラインを構築している他の開発者とノートを比較するためにコミュニティに参加してください:Discord · Telegram。
FAQ
Q: このガイドとクラウドGPTビジョンガイドの実際の違いは何ですか?
モデルが実行される場所とそのコストです。このサイトのGPTビジョンウェブスクレイピングガイドは、API経由でホストされたマルチモーダルモデルにスクリーンショットを送信し、画像ごとに請求します。このガイドは、同じ種類のスクリーンショットをOllamaを通じてlocalhostで実行されているモデルに送信し、APIキーなしでコールごとのコストがありません。両方とも、HTMLではなくピクセルを読み取ります。
Q: このガイドとローカルOllamaテキスト抽出ガイドの違いは何ですか?
モデルの読み取る内容です。Ollama Web ScrapingはレンダリングされたHTMLを取得し、ローカルモデルにテキストを渡して解析させます。このガイドはHTMLをモデルには全く送信せず、ローカルモデルにスクリーンショットを渡し、画像を読み取るように要求します。
Q: ローカルビジョンモデルを実行するのにGPUは必要ですか?
いいえ、しかしそれがないと待ち時間が大きく変動することを予想してください。このガイドでの全ての実行はmoondreamをCPUのみで使用し、推論中にollama psが100% CPUを報告したことを確認しました。このガイドの背後にあるコールは、同じ種類のリクエストで10秒台から数分までの範囲でした。Ollamaは各リクエストの後にkeep_aliveの間モデルを常駐させているため、まだ読み込まれている間のコールはコールドコールが支払うディスクロード時間をスキップします — それだけで、大部分の揺れが説明されます。OllamaがアクセスできるGPUは、すべてのケースを大幅に短縮します。
Q: OllamaのAPI内のimagesフィールドがクラウドビジョンリクエストとは異なって見えるのはなぜですか?
異なる規約を使用しているからです。Ollamaの/api/generateはimagesをプレフィックスなしの生のbase64文字列のリストとして受け取ります。このサイトのGPTビジョンウェブスクレイピングガイドを含むほとんどのOpenAI互換のクラウドビジョンAPIは、data:image/png;base64,...の完全なURLをimage_urlコンテンツ部分内に期待します。この二つのフォーマット間でコードをポーティングする際にこれを調整せずに行うと、最初のエラーになります。
Q: 構造化された抽出がエラーの代わりに空のフィールドを返したのはなぜですか?
リクエスト自体は成功しました — Ollamaはresponseフィールドを持つ200を返したので、raise_for_status()は決して発火しません。モデルは生成するよう指示されたJSONの形を埋めましたが、値は設定されず、その空の形を繰り返し続け、出力長の上限が文字列の途中で切断されるまで繰り返しました。これはモデルの能力の失敗であり、HTTPの失敗ではなく、上記のコードがjson.loads()を別々にチェックする理由です。
Q: より大きなローカルビジョンモデルは構造的抽出の問題を解決できますか?
おそらく、コストをかけて。llava:7bのような7Bクラスのローカルビジョンモデルは、JSONスキーマを保持し、正確に埋める能力が高いですが、より多くのRAMまたはVRAMが必要であり、同じハードウェア上でトークンごとの速度も遅くなります。このガイドが構築されているトレードオフ — 本当に無料で、真にローカル — はモデルが成長するにつれて維持が難しくなります。ある時点で、クラウドビジョンモデルの1枚あたりのコストが、大規模なローカルモデルが快適に動作するために必要なハードウェアよりも安価になります。
Q: これは生産的なスクレイピングパイプラインに使用すべきですか?
このモデルサイズでは監視なしでは使用すべきではありません。ここでの証拠に基づくと、1文の説明も構造的なスキーマも完全に信頼できるものではありませんでした — 説明はページには存在しない構造的詳細を加え、スキーマは自身のプレースホルダーテキストを反響した後、非JSON出力に漂いました。厳密なスキーマ抽出は、クラウドビジョンガイドやOllama Web ScrapingによるDOM解析にルーティングし、結果を人間がまだ確認するところでゼロコストの exploratory read用にこのようなローカルビジョンモデルを保持するか、ローカルに留まる必要がある場合はより大きなローカルモデルに移行してください。
Q: ローカルモデルでスクリーンショットを読むことは合法ですか?
モデルをローカルで実行することは、ページ自体の収集ルールを変更しません。公共のページのみをキャプチャし、サイトの利用規約やロボット排除プロトコルで標準化されたロボット指令を尊重し、結果を読み取るモデルがどこで実行されようとも、リクエストの量を制限してください。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



