Closed7

Webサイトからデータを抽出するサービス「Handinger」を試す

kun432kun432

LLMで使うことを前提としたWebスクレイピングについては過去に以下を試した。

Crawl4AI
https://zenn.dev/kun432/scraps/0d78afd06b6577

Jina Reader API
https://zenn.dev/link/comments/4b1860d9352685

SearchGraphAI
https://zenn.dev/kun432/scraps/ce65ff8231911d

Firecrawl
https://zenn.dev/kun432/scraps/58fce97899cfdd

Trafilatura
https://zenn.dev/kun432/scraps/2e104f0278b90c

今回「Handinger」という、有償だが新しいサービスを見つけたので、試してみる。

https://handinger.com/

HANDINGER

インターネットからデータを抽出する最も簡単で安価な方法

最も簡単

コーディングの知識は不要:HTTPエンドポイントを呼び出すだけで抽出可能:

  • マークダウン
    LLMモデルのトレーニングや、セカンドブレインへのコンテンツ保存に最適。
  • スクリーンショット
    視覚モデルのトレーニングやウェブサムネイルの取得に最適。
  • メタデータ
    ウェブサイトから情報を抽出(画像、タイトル、説明文など)。
  • HTML
    ウェブサイトから特定のコンテンツを抽出するのに最適。

最も安い

Handingerの費用は1URLあたり0.0005ドルで、毎月請求される。初期費用やAPIクレジットの取得は不要だ。

最低金額は10ドルだが、最初の2,000URLは無料だ。

よくある質問

登録にはクレジットカードが必要ですか?
はい、不正使用を防ぐためにクレジットカードが必要となります。ただし、毎月最初の2,000件のリクエストは無料ですので、料金を請求されることなく製品をお試しいただけます。

レートリミットはある?
はい、レートリミットはありますが、1分あたり1,000リクエストとかなり余裕のある設定です。これにより、すべてのユーザーに公平で信頼性の高いサービスを提供しながら、データを迅速に抽出することができます。

初期費用はかかる?
いいえ、初期費用はかかりません。ご利用いただいた分だけお支払いいただきます。

Handingerを使用するには開発者である必要がありますか?
そんなことはありません!これは単なるHTTPエンドポイントなので、コーディングなしで使用できます。APIの呼び出し方がわからない場合は、help@handinger.comまでお気軽にご連絡ください。喜んでお手伝いいたします。

どのようなウェブサイトからデータを抽出できますか?
弊社はすべてのウェブサイトをサポートしていますが、もし動作しないウェブサイトを見つけた場合は、help@handinger.comまでメールでお知らせください。補償するとともに、最善を尽くして修正します。

なぜHandingerはそんなに安いのですか?
ほとんどのウェブサイトは、データを抽出するのに非常に安価で済みますが、中にはより高価な方法が必要なサイトもあります。抽出方法を選択させるサービスが多い中、弊社ではそのリスクを負う方が良いと考えています。そのため、最も費用対効果の高いデータ抽出方法を見つけることに力を注いでいます。

Handingerの意味は?
「Handinger」は息子が弟の名前として呼んでいるもので、「PAW Patrol」のHumdinger市長のスペルミスです。ドメインが空いていて、思わず笑みがこぼれるような名前だったので、即決しました。

参考
https://pawpatrol.fandom.com/wiki/Mayor_Humdinger

kun432kun432

前提

  • アカウント登録+クレカ登録が必要になる
  • 登録してもいきなり10ドル課金されるわけではなく、おそらくこんな感じ。
    • 最初の2000URLまでは無料
    • 2001〜20000URLまでは$10
    • それ以降は使用した分だけ従量課金

アカウント作成するとAPIキーが作成される感じ。

Jinaなんかもそうだけど、サンプルコードがそのまま用意されていて、アカウント作らなくても(おそらく無料の)APIキーはとりあえず発行するみたいなサービス、個人的には嫌だなぁ、APIキーは自分で発行したい、作り直しとかローテーションとかもあると思うので。

kun432kun432

Colaboratoryでやってみる。用意されているエンドポイントは以下の4つ。

  • markdown
    • WebサイトのコンテンツをMarkdownテキストで返す
    • APIエンドポイント: https://api.handinger.com/markdown
  • image
    • Webサイトのスクリーンショットを取得して、画像URLを返す
    • APIエンドポイント: https://api.handinger.com/image
  • meta
    • Webサイトの最も共通のメタデータを取得し、JSONで返す
    • APIエンドポイント: https://api.handinger.com/meta
  • html
    • WebサイトのコンテンツをHTMLテキストで返す
    • APIエンドポイント: https://api.handinger.com/html

それぞれで個別にオプションがある。

では順にやっていく。以下のWikipediaのページを対象にやってみる。

https://ja.wikipedia.org/wiki/オグリキャップ

markdown

まずはシンプルに最もニーズがありそうなMarkdown化。

後述するオプションはなしで。

import requests
import urllib.parse

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/markdown?url={encoded_url}",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(response.text)
[](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#)

*   [ホーム](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8)
    
*   [おまかせ表示](https://ja.wikipedia.org/wiki/%E7%89%B9%E5%88%A5:%E3%81%8A%E3%81%BE%E3%81%8B%E3%81%9B%E8%A1%A8%E7%A4%BA)
    
*   [付近](https://ja.wikipedia.org/wiki/%E7%89%B9%E5%88%A5:%E4%BB%98%E8%BF%91)
    

*   [ログイン](https://ja.wikipedia.org/w/index.php?title=%E7%89%B9%E5%88%A5:%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3&returnto=%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97)
    

*   [設定](https://ja.wikipedia.org/w/index.php?title=%E7%89%B9%E5%88%A5:%E6%90%BA%E5%B8%AF%E6%A9%9F%E5%99%A8%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3&returnto=%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97)
    

*   [寄付](https://donate.wikimedia.org/wiki/Special:FundraiserRedirector?utm_source=donate&utm_medium=sidebar&utm_campaign=C13_ja.wikipedia.org&uselang=ja&utm_key=minerva)
    

*   [ウィキペディアについて](https://ja.wikipedia.org/wiki/Wikipedia:%E3%82%A6%E3%82%A3%E3%82%AD%E3%83%9A%E3%83%87%E3%82%A3%E3%82%A2%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
    
*   [免責事項](https://ja.wikipedia.org/wiki/Wikipedia:%E5%85%8D%E8%B2%AC%E4%BA%8B%E9%A0%85)
    

[![Wikipedia](/static/images/mobile/copyright/wikipedia-wordmark-ja.svg)](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8)

 

検索

オグリキャップ
=======

日本の種牡馬・元競走馬

*   [言語](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#p-lang "言語")
    
*   [ウォッチリストに追加](https://ja.wikipedia.org/w/index.php?title=%E7%89%B9%E5%88%A5:%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3&returnto=%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97)
    
*   [編集](https://ja.wikipedia.org/w/index.php?title=%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97&action=edit)
    

<table class="box-馬齢旧 plainlinks metadata ambox mbox-small-left ambox-style" role="presentation" style="width:AUTO"><tbody><tr><td class="mbox-text"><div class="mbox-text-span">この記事は「<b>旧馬齢表記</b>」が採用されており、国際的な表記法や2001年以降の日本国内の表記とは異なっています。<span class="hide-when-compact"> 詳しくは<a href="https://ja.wikipedia.org/wiki/%E9%A6%AC%E9%BD%A2#%E6%97%A5%E6%9C%AC%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E9%A6%AC%E9%BD%A2%E8%A1%A8%E8%A8%98" title="馬齢" target="_blank">馬齢#日本における馬齢表記</a>を参照してください。</span></div></td></tr></tbody></table>

**オグリキャップ**(欧字名:Oguri Cap、[1985年](https://ja.wikipedia.org/wiki/1985%E5%B9%B4 "1985年")
[3月27日](https://ja.wikipedia.org/wiki/3%E6%9C%8827%E6%97%A5 "3月27日")
 - [2010年](https://ja.wikipedia.org/wiki/2010%E5%B9%B4 "2010年")
[7月3日](https://ja.wikipedia.org/wiki/7%E6%9C%883%E6%97%A5 "7月3日")
)は、[日本](https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC "日本")
の[競走馬](https://ja.wikipedia.org/wiki/%E7%AB%B6%E8%B5%B0%E9%A6%AC "競走馬")
、[種牡馬](https://ja.wikipedia.org/wiki/%E7%A8%AE%E7%89%A1%E9%A6%AC "種牡馬")
[\[1\]](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-jbis-1)
(snip)

markdownには2つのオプションがある

  • readability: 関連しないコンテンツを削除する、が、重要な情報も削除してしまう可能性がある
  • inline: 画像URLをbase64表現に変換して埋め込む

readability=trueを付与してみる。

import requests
import urllib.parse

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/markdown?url={encoded_url}&readability=true",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(response.text)
**オグリキャップ**(欧字名:Oguri Cap、[1985年](https://ja.wikipedia.org/wiki/1985%E5%B9%B4 "1985年")
[3月27日](https://ja.wikipedia.org/wiki/3%E6%9C%8827%E6%97%A5 "3月27日")
 - [2010年](https://ja.wikipedia.org/wiki/2010%E5%B9%B4 "2010年")
[7月3日](https://ja.wikipedia.org/wiki/7%E6%9C%883%E6%97%A5 "7月3日")
)は、[日本](https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC "日本")
の[競走馬](https://ja.wikipedia.org/wiki/%E7%AB%B6%E8%B5%B0%E9%A6%AC "競走馬")
、[種牡馬](https://ja.wikipedia.org/wiki/%E7%A8%AE%E7%89%A1%E9%A6%AC "種牡馬")
[\[1\]](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-jbis-1)
。

| オグリキャップ |
| --- |
| [![](//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Oguri_Cap_in_Yushun_Stallion_station.jpg/250px-Oguri_Cap_in_Yushun_Stallion_station.jpg)](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Oguri_Cap_in_Yushun_Stallion_station.jpg)
1994年8月、[優駿スタリオンステーション](https://ja.wikipedia.org/wiki/%E5%84%AA%E9%A7%BF%E3%82%B9%E3%82%BF%E3%83%AA%E3%82%AA%E3%83%B3%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3 "優駿スタリオンステーション")
にて



 |
| 現役期間 | [1987年](https://ja.wikipedia.org/wiki/1987%E5%B9%B4 "1987年")
 - [1990年](https://ja.wikipedia.org/wiki/1990%E5%B9%B4 "1990年")
 |
| 欧字表記 | Oguri Cap[\[1\]](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-jbis-1)
 |
| 品種 | [サラブレッド](https://ja.wikipedia.org/wiki/%E3%82%B5%E3%83%A9%E3%83%96%E3%83%AC%E3%83%83%E3%83%89 "サラブレッド")
[\[1\]](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-jbis-1)
 |
| 性別 | [牡](https://ja.wikipedia.org/wiki/%E7%89%A1%E9%A6%AC "牡馬")
[\[1\]](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-jbis-1)
 |
(snip)

最初の例ではメニューと思しきものが含まれていたが、こちらでは含まれていない。Markdownとしてメインコンテンツだけ取りたい場合はこのオプションを有効にしておくのが良さそう。

次にinline=trueを試す

import requests
import urllib.parse

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/markdown?url={encoded_url}&readability=true&inline=true",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(response.text)

画像URL部分を抜粋するとbase64になっていない。

| [![](//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Oguri_Cap_in_Yushun_Stallion_station.jpg/250px-Oguri_Cap_in_Yushun_Stallion_station.jpg)](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Oguri_Cap_in_Yushun_Stallion_station.jpg)

別のURLで試してみた。自分のzennの過去記事。

https://zenn.dev/kun432/articles/20230921-vector-databases-jp-part-1

こちらだと、base64に変換されていた。

### プログラミング言語の選択

高速でレスポンスが良くスケーラブルなデータベースは、近年、GolangやRustのようなモダンな言語で書かれることが一般的である。ベクトル特化ベンダーの中で、Javaで書かれているのはVespaだけである。Chromaは、C++で構築されたOLAPデータベースであるClickhouseとオープンソースのベクトルインデックスである[HNSWLib](https://github.com/nmslib/hnswlib)
の上に構築されたPython/TypeScriptラッパーとなっている。

![](data:image/webp;base64,UklGRkqWA(snip)C5KAAAAA==)

興味深いことに、Pineconeも[\[2\]](https://zenn.dev/kun432/articles/20230921-vector-databases-jp-part-1#fn-044d-2)
、LanceDBのベースとなるストレージフォーマットであるLance[\[3\]](https://zenn.dev/kun432/articles/20230921-vector-databases-jp-part-1#fn-044d-3)
も、元々はC++で書かれていたにも関わらず、Rustで完全に一から書き直されている。明らかに、データベースコミュニティの多くがRust🦀を受け入れてきている!💪

ここの違いがなぜ起きるのかはわからない。

kun432kun432

image

URLからスクリーンキャプチャを取得する。

import requests
import urllib.parse

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/image?url={encoded_url}",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(response.text)
https://images.handinger.com/fimg/XXXXXXXXXXXXXXXXXXXX.webp

こんな感じでURLが返ってくるので、アクセスしてみる。

うーん、全体像にはならないのかなぁ?

自分のZennの記事でも試してみた。

なんとなくスマホ的サイズでしか取れないのかなという感じ。

このエンドポイントは他のオプションはなし。

kun432kun432

meta

メタデータの取得。

import requests
import urllib.parse
import json

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/meta?url={encoded_url}",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(json.dumps(json.loads(response.text), indent=2, ensure_ascii=False))
{
  "lang": "ja",
  "author": null,
  "title": "オグリキャップ",
  "image": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Oguri_Cap_in_Yushun_Stallion_station.jpg/1200px-Oguri_Cap_in_Yushun_Stallion_station.jpg",
  "url": "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97",
  "description": "1994年8月、優駿スタリオンステーションにて",
  "date": null,
  "logo": "https://ja.wikipedia.org/static/apple-touch/wikipedia.png",
  "datePublished": null,
  "dateModified": null,
  "feed": "https://ja.wikipedia.org/w/index.php?title=%E7%89%B9%E5%88%A5:%E6%9C%80%E8%BF%91%E3%81%AE%E6%9B%B4%E6%96%B0&feed=atom"
}

truncatedBodyというオプションがあり、本文の一部を含むか含まないかを指定できる。

import requests
import urllib.parse
import json

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/meta?url={encoded_url}&truncatedBody=true",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(json.dumps(json.loads(response.text), indent=2, ensure_ascii=False))
{
  "lang": "ja",
  "author": null,
  "title": "オグリキャップ",
  "image": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Oguri_Cap_in_Yushun_Stallion_station.jpg/1200px-Oguri_Cap_in_Yushun_Stallion_station.jpg",
  "url": "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97",
  "description": "1994年8月、優駿スタリオンステーションにて",
  "date": null,
  "logo": "https://ja.wikipedia.org/static/apple-touch/wikipedia.png",
  "datePublished": null,
  "dateModified": null,
  "feed": "https://ja.wikipedia.org/w/index.php?title=%E7%89%B9%E5%88%A5:%E6%9C%80%E8%BF%91%E3%81%AE%E6%9B%B4%E6%96%B0&feed=atom",
  "truncatedBody": "オグリキャップ\n1994年8月、優駿スタリオンステーションにて現役期間\n1987年 - 1990年欧字表記\nOguri Cap[1]品種\nサラブレッド[1]性別\n牡[1]毛色\n芦毛[1]生誕\n1985年3月27日[1]死没\n2010年7月3日(25歳没)父\nダンシングキャップ[1]母\nホワイトナルビー[1]母の父\nシルバーシャーク[1]生国\n日本(北海道三石町)[1]生産者\n稲葉不奈男[1]馬主\n小栗孝一→佐橋五十雄→近藤俊典[1]調教師\n鷲見昌勇(笠松)→瀬戸口勉(栗東)[1]厩務員\n三浦裕一(笠松)→川瀬友光(笠松)→池江敏郎(栗東)競走成績タイトル\nJRA賞年度代表馬(1990年)最優秀4歳牡馬(1988年)JRA賞特別賞(1989年)最優秀5歳以上牡馬(1990年)NARグランプリ特別表彰馬(1990年)顕彰馬(1991年選出)生涯成績\n32戦22勝[1]地方:12戦10勝中央:20戦12勝獲得賞金\n9億1251万2000円[1]地方:2281万円中央:8億8970万2000円\n勝ち鞍\nGI\n有馬記念\n1988年・1990年\nGI\nマイルCS\n1989年\nGI\n安田記念\n1990年\nGII\nNZT4歳S\n1988年\nGII\n高松宮杯\n1988年\nGII\n毎日王冠\n1988年・1989年\nGIII\nペガサスS\n1988年\nGIII\n毎日杯\n1988年\nGIII\n京都4歳特別\n1988年\nGIII\nオールカマー\n1989年\nテンプレートを表示\nオグリキャップ(欧字名:Oguri Cap、1985年3月27日 - 2010年7月3日)は、日本の競走馬、種牡馬[1]。\n1987年5月に岐阜県の地方競馬・笠松競馬場でデビュー。8連勝、重賞5勝を含む12戦10勝を記録した後、1988年1月に中央競馬へ移籍し、重賞12勝(うちGI4勝)を記録した。1988年度のJRA賞最優秀4歳牡馬[† 1]、1989年度のJRA賞特別賞[† 1]、1990年度のJRA賞最優秀5歳以上牡馬および年度代表馬[† 1]。1991年、JRA顕彰馬に選出。愛称は「オグリ」「芦毛の怪物」「スーパーホース」など多数。\n中央競馬時代はスーパークリーク、イナリワンの二頭とともに「平成三強」と総称され、自身と騎手である武豊の活躍を中心として起こった第二次競馬ブーム期において[2]、第一次競馬ブームの立役者とされるハイセイコーに比肩するとも評される高い人気を得た。\n日本競馬史上屈指のアイドルホースである。\n[3]。\n競走馬引退後は北海道新冠町の優駿スタリオンステーションで種牡馬となったが、産駒から中央競馬の重賞優勝馬を出すことができず、2007年に種牡馬を引退。種牡馬引退後は同施設で功労馬として繋養されていたが、2010年7月3日に右後肢脛骨を骨折し、安楽死の処置が執られた。\nオグリキャップの母・ホワイトナルビーは競走馬時代に馬主の小栗孝一が所有し、(snip)1992年、笠松競馬場でオグリキャップを記念した「オグリキャップ記念」が創設された。一時はダートグレード競走として行なわれていたが、現在は地方全国交流競走として行われている。また、2004年11月21日にはJRAゴールデンジュビリーキャンペーンの「名馬メモリアル競走」として「オグリキャップメモリアル」が施行された[† 79]"
}

なるほど、メインコンテンツ部分のテキストが追加で含まれる。

kun432kun432

html

htmlをそのまま?取得するのかな?

まずオプション何もなしで。

import requests
import urllib.parse

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/html?url={encoded_url}",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(response.text)
<!DOCTYPE html>
<html class="client-nojs skin-theme-clientpref-day mf-expand-sections-clientpref-0 mf-font-size-clientpref-small mw-mf-amc-clientpref-0" lang="ja" dir="ltr">
<head>
<meta charset="UTF-8">
<title>&#x30aa;&#x30b0;&#x30ea;&#x30ad;&#x30e3;&#x30c3;&#x30d7; - Wikipedia</title>
(snip)
</head>
<body class="mediawiki ltr sitedir-ltr mw-hide-empty-elt ns-0 ns-subject mw-editable page-&#x30aa;&#x30b0;&#x30ea;&#x30ad;&#x30e3;&#x30c3;&#x30d7; rootpage-&#x30aa;&#x30b0;&#x30ea;&#x30ad;&#x30e3;&#x30c3;&#x30d7; stable issues-group-B skin-minerva action-view skin--responsive mw-mf-amc-disabled mw-mf"><div id="mw-mf-viewport">
	<div id="mw-mf-page-center">
		<a class="mw-mf-page-center__mask" href="https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#" target="_blank"></a>
		<header class="header-container header-chrome">
			<div class="minerva-header">
				<nav class="navigation-drawer toggle-list view-border-box">
					<input type="checkbox" id="main-menu-input" class="toggle-list__checkbox" role="button" aria-haspopup="true" aria-expanded="false" aria-labelledby="mw-mf-main-menu-button">
					<label role="button" for="main-menu-input" id="mw-mf-main-menu-button" aria-hidden="true" data-event-name="ui.mainmenu" class="cdx-button cdx-button--size-large cdx-button--fake-button cdx-button--fake-button--enabled cdx-button--icon-only cdx-button--weight-quiet toggle-list__toggle">
    <span class="minerva-icon minerva-icon--menu-base20"></span>
<span></span>
</label>
(snip)

ちなみにrequestsでそのまま取得した場合。このへんはクライアントによって変わるだけかもしれない。

import requests

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"

response = requests.get(url)
print(response.text)

<!DOCTYPE html>
<html class="client-nojs vector-feature-language-in-header-enabled vector-feature-language-in-main-page-header-disabled vector-feature-sticky-header-disabled vector-feature-page-tools-pinned-disabled vector-feature-toc-pinned-clientpref-1 vector-feature-main-menu-pinned-disabled vector-feature-limited-width-clientpref-1 vector-feature-limited-width-content-enabled vector-feature-custom-font-size-clientpref-1 vector-feature-appearance-pinned-clientpref-1 vector-feature-night-mode-enabled skin-theme-clientpref-day vector-toc-available" lang="ja" dir="ltr">
<head>
<meta charset="UTF-8">
<title>オグリキャップ - Wikipedia</title>
(snip)
<body class="skin--responsive skin-vector skin-vector-search-vue mediawiki ltr sitedir-ltr mw-hide-empty-elt ns-0 ns-subject mw-editable page-オグリキャップ rootpage-オグリキャップ skin-vector-2022 action-view"><a class="mw-jump-link" href="#bodyContent">コンテンツにスキップ</a>
<div class="vector-header-container">
	<header class="vector-header mw-header">
		<div class="vector-header-start">
			<nav class="vector-main-menu-landmark" aria-label="サイト">
				
<div id="vector-main-menu-dropdown" class="vector-dropdown vector-main-menu-dropdown vector-button-flush-left vector-button-flush-right"  >
	<input type="checkbox" id="vector-main-menu-dropdown-checkbox" role="button" aria-haspopup="true" data-event-name="ui.dropdown-vector-main-menu-dropdown" class="vector-dropdown-checkbox "  aria-label="メインメニュー"  >
	<label id="vector-main-menu-dropdown-label" for="vector-main-menu-dropdown-checkbox" class="vector-dropdown-label cdx-button cdx-button--fake-button cdx-button--fake-button--enabled cdx-button--weight-quiet cdx-button--icon-only " aria-hidden="true"  ><span class="vector-icon mw-ui-icon-menu mw-ui-icon-wikimedia-menu"></span>

<span class="vector-dropdown-label-text">メインメニュー</span>
(snip)

HTMLの場合もmarkdownと同じオプションが指定できる。

  • readability: 関連しないコンテンツを削除する、が、重要な情報も削除してしまう可能性がある
  • inline: 画像URLをbase64表現に変換して埋め込む

readability=trueにしてみる。

import requests
import urllib.parse
import json

API_KEY="XXXXXXXXXX"

url = "https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"
encoded_url = urllib.parse.quote(url)

response = requests.get(
    f"https://api.handinger.com/html?url={encoded_url}&readability=true",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
print(response.text)
<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8' />
        <title>オグリキャップ - Wikipedia</title>
    </head>
    <body>
        <div><div><section>
<p><b>オグリキャップ</b>(欧字名:<span>Oguri Cap</span><a href="https://ja.wikipedia.org/wiki/1985%E5%B9%B4" title="1985年" target="_blank">1985年</a><a href="https://ja.wikipedia.org/wiki/3%E6%9C%8827%E6%97%A5" title="3月27日" target="_blank">3月27日</a> - <a href="https://ja.wikipedia.org/wiki/2010%E5%B9%B4" title="2010年" target="_blank">2010年</a><a href="https://ja.wikipedia.org/wiki/7%E6%9C%883%E6%97%A5" title="7月3日" target="_blank">7月3日</a>)は、<a href="https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC" title="日本" target="_blank">日本</a><a href="https://ja.wikipedia.org/wiki/%E7%AB%B6%E8%B5%B0%E9%A6%AC" title="競走馬" target="_blank">競走馬</a><a href="https://ja.wikipedia.org/wiki/%E7%A8%AE%E7%89%A1%E9%A6%AC" title="種牡馬" target="_blank">種牡馬</a><sup><a href="https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-jbis-1" target="_blank"><span>[</span>1<span>]</span></a></sup></p><table><tbody><tr><th>オグリキャップ</th></tr><tr><td>
<span><a href="https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Oguri_Cap_in_Yushun_Stallion_station.jpg" target="_blank"><img src="//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Oguri_Cap_in_Yushun_Stallion_station.jpg/250px-Oguri_Cap_in_Yushun_Stallion_station.jpg" srcset="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Oguri_Cap_in_Yushun_Stallion_station.jpg/375px-Oguri_Cap_in_Yushun_Stallion_station.jpg 1.5x, https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Oguri_Cap_in_Yushun_Stallion_station.jpg/500px-Oguri_Cap_in_Yushun_Stallion_station.jpg 2x" /></a></span><div><p>1994年8月、<a href="https://ja.wikipedia.org/wiki/%E5%84%AA%E9%A7%BF%E3%82%B9%E3%82%BF%E3%83%AA%E3%82%AA%E3%83%B3%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3" title="優駿スタリオンステーション" target="_blank">優駿スタリオンステーション</a>にて</p></div></td></tr><tr><th>現役期間</th><td>
(snip)
</tbody></table></td></tr><tr><td><a href="https://ja.wikipedia.org/wiki/Template:%E7%AB%B6%E8%B5%B0%E9%A6%AC" title="Template:競走馬" target="_blank">テンプレートを表示</a></td></tr></tbody></table>
<p><a href="https://ja.wikipedia.org/wiki/1987%E5%B9%B4" title="1987年" target="_blank">1987年</a>5月に<a href="https://ja.wikipedia.org/wiki/%E5%B2%90%E9%98%9C%E7%9C%8C" title="岐阜県" target="_blank">岐阜県</a><a href="https://ja.wikipedia.org/wiki/%E5%9C%B0%E6%96%B9%E7%AB%B6%E9%A6%AC" title="地方競馬" target="_blank">地方競馬</a><a href="https://ja.wikipedia.org/wiki/%E7%AC%A0%E6%9D%BE%E7%AB%B6%E9%A6%AC%E5%A0%B4" title="笠松競馬場" target="_blank">笠松競馬場</a>でデビュー。8連勝、<a href="https://ja.wikipedia.org/wiki/%E9%87%8D%E8%B3%9E" title="重賞" target="_blank">重賞</a>5勝を含む12戦10勝を記録した後、<a href="https://ja.wikipedia.org/wiki/1988%E5%B9%B4" title="1988年" target="_blank">1988年</a>1月に<a href="https://ja.wikipedia.org/wiki/%E4%B8%AD%E5%A4%AE%E7%AB%B6%E9%A6%AC" title="中央競馬" target="_blank">中央競馬</a>へ移籍し、重賞12勝(うち<a href="https://ja.wikipedia.org/wiki/%E7%AB%B6%E9%A6%AC%E3%81%AE%E7%AB%B6%E8%B5%B0%E6%A0%BC%E4%BB%98%E3%81%91" title="競馬の競走格付け" target="_blank">GI</a>4勝)を記録した。<a href="https://ja.wikipedia.org/wiki/1988%E5%B9%B4" title="1988年" target="_blank">1988年</a>度の<a href="https://ja.wikipedia.org/wiki/JRA%E8%B3%9E%E6%9C%80%E5%84%AA%E7%A7%803%E6%AD%B3%E7%89%A1%E9%A6%AC" title="JRA賞最優秀3歳牡馬" target="_blank">JRA賞最優秀4歳牡馬</a><sup><a href="https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-JRA-2" target="_blank"><span>[</span>† 1<span>]</span></a></sup><a href="https://ja.wikipedia.org/wiki/1989%E5%B9%B4" title="1989年" target="_blank">1989年</a>度の<a href="https://ja.wikipedia.org/wiki/JRA%E8%B3%9E%E7%89%B9%E5%88%A5%E8%B3%9E" title="JRA賞特別賞" target="_blank">JRA賞特別賞</a><sup><a href="https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-JRA-2" target="_blank"><span>[</span>† 1<span>]</span></a></sup><a href="https://ja.wikipedia.org/wiki/1990%E5%B9%B4" title="1990年" target="_blank">1990年</a>度の<a href="https://ja.wikipedia.org/wiki/JRA%E8%B3%9E%E6%9C%80%E5%84%AA%E7%A7%804%E6%AD%B3%E4%BB%A5%E4%B8%8A%E7%89%A1%E9%A6%AC" title="JRA賞最優秀4歳以上牡馬" target="_blank">JRA賞最優秀5歳以上牡馬</a>および年度代表馬<sup><a href="https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-JRA-2" target="_blank"><span>[</span>† 1<span>]</span></a></sup><a href="https://ja.wikipedia.org/wiki/1991%E5%B9%B4" title="1991年" target="_blank">1991年</a><a href="https://ja.wikipedia.org/wiki/JRA%E9%A1%95%E5%BD%B0%E9%A6%AC" title="JRA顕彰馬" target="_blank">JRA顕彰馬</a>に選出。愛称は「オグリ」「<a href="https://ja.wikipedia.org/wiki/%E8%8A%A6%E6%AF%9B" title="芦毛" target="_blank">芦毛</a>の怪物」「スーパーホース」など多数。
</p><p>中央競馬時代は<a href="https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%BC%E3%83%91%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%BC%E3%82%AF" title="スーパークリーク" target="_blank">スーパークリーク</a><a href="https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%8A%E3%83%AA%E3%83%AF%E3%83%B3" title="イナリワン" target="_blank">イナリワン</a>の二頭とともに「<a href="https://ja.wikipedia.org/wiki/%E5%B9%B3%E6%88%90%E4%B8%89%E5%BC%B7" title="平成三強" target="_blank">平成三強</a>」と総称され、自身と<a href="https://ja.wikipedia.org/wiki/%E9%A8%8E%E6%89%8B" title="騎手" target="_blank">騎手</a>である<a href="https://ja.wikipedia.org/wiki/%E6%AD%A6%E8%B1%8A" title="武豊" target="_blank">武豊</a>の活躍を中心として起こった<a href="https://ja.wikipedia.org/wiki/%E7%AB%B6%E9%A6%AC%E3%83%95%E3%82%A1%E3%83%B3#%E7%AC%AC%E4%BA%8C%E6%AC%A1%E7%AB%B6%E9%A6%AC%E3%83%96%E3%83%BC%E3%83%A0" title="競馬ファン" target="_blank">第二次競馬ブーム</a>期において<sup><a href="https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-%E6%9D%B1%E9%82%A6%E5%87%BA%E7%89%88%EF%BC%88%E7%B7%A8%EF%BC%892005-131-132-3" target="_blank"><span>[</span>2<span>]</span></a></sup><a href="https://ja.wikipedia.org/wiki/%E7%AB%B6%E9%A6%AC%E3%83%95%E3%82%A1%E3%83%B3#%E7%AC%AC%E4%B8%80%E6%AC%A1%E7%AB%B6%E9%A6%AC%E3%83%96%E3%83%BC%E3%83%A0" title="競馬ファン" target="_blank">第一次競馬ブーム</a>の立役者とされる<a href="https://ja.wikipedia.org/wiki/%E3%83%8F%E3%82%A4%E3%82%BB%E3%82%A4%E3%82%B3%E3%83%BC" title="ハイセイコー" target="_blank">ハイセイコー</a>に比肩するとも評される高い人気を得た。
日本競馬史上屈指のアイドルホースである。
<sup><a href="https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97#cite_note-%E9%96%A2%E5%8F%A32002-15-4" target="_blank"><span>[</span>3<span>]</span></a></sup></p><p>競走馬引退後は<a href="https://ja.wikipedia.org/wiki/%E5%8C%97%E6%B5%B7%E9%81%93" title="北海道" target="_blank">北海道</a><a href="https://ja.wikipedia.org/wiki/%E6%96%B0%E5%86%A0%E7%94%BA" title="新冠町" target="_blank">新冠町</a><a href="https://ja.wikipedia.org/wiki/%E5%84%AA%E9%A7%BF%E3%82%B9%E3%82%BF%E3%83%AA%E3%82%AA%E3%83%B3%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3" title="優駿スタリオンステーション" target="_blank">優駿スタリオンステーション</a><a href="https://ja.wikipedia.org/wiki/%E7%A8%AE%E7%89%A1%E9%A6%AC" title="種牡馬" target="_blank">種牡馬</a>となったが、産駒から中央競馬の重賞優勝馬を出すことができず、<a href="https://ja.wikipedia.org/wiki/2007%E5%B9%B4" title="2007年" target="_blank">2007年</a>に種牡馬を引退。種牡馬引退後は同施設で功労馬として繋養されていたが、2010年7月3日に右後肢<a href="https://ja.wikipedia.org/wiki/%E8%84%9B%E9%AA%A8" title="脛骨" target="_blank">脛骨</a>を骨折し、<a href="https://ja.wikipedia.org/wiki/%E5%AE%89%E6%A5%BD%E6%AD%BB" title="安楽死" target="_blank">安楽死</a>の処置が執られた。
</p>


</section>
(snip)

なるほど、余計なコンテンツをなるべく含めない形でHTMLになる。

Markdownは一応構造化された文書だけど、HTMLに比べると文書構造がかなり簡略化される。もしかするとHTMLのほうがより文書構造≒コンテキストを維持できたりするという場合もあるかもしれない。

例えば、パッと見た感じ、表(table)なんかはそのまま取れてるように思える。markdownでも表は取れるけど、tableのセル内に改行があるとmarkdownとしては破綻する。

この手のウェブサイトをmarkdownに変換してくれるツール、だいたいtableが弱いイメージがあって、もしかするとLLM側でよしなに解釈してくれるかもしれないけど、きれいに渡せるならばそれに越したことはないかなとも思う。

kun432kun432

まとめ

あくまでも個人的な印象

とりあえずmarkdown化抽出は他とそんなに大差はないと思う。となると、有償サービスの場合は、コストとか機能とか使い勝手になってくるかなと思う。

  • 有償だと、単純なコスト比較ならFirecrawlよりは安い(3000ページで$16、レートリミットもきつめ)が、Jina Reader・Crawl4AI・Trafilaturaは無料
    • Firecrawlはセルフホストもあるけど、業務で使う場合はAGPLライセンスがネックになるかも。
  • LLMとの連携機能はない。 LLMと連携させてより高度な抽出が必要ならScrapeGraphAIやCrawl4AI。
  • 使い勝手はJina Readerと同じような感じでシンプルに使えるが、機能がシンプルだからそうというのもある。高機能なものは当然複雑になる。

で、機能的になところでいうと、自分はhtmlで余計な部分を削除してくれる、ってのには少し価値を感じた。上にも書いたけど、

Markdownは一応構造化された文書だけど、HTMLに比べると文書構造がかなり簡略化される。もしかするとHTMLのほうがより文書構造≒コンテキストを維持できたりするという場合もあるかもしれない。

例えば、パッと見た感じ、表(table)なんかはそのまま取れてるように思える。markdownでも表は取れるけど、tableのセル内に改行があるとmarkdownとしては破綻する。

この手のウェブサイトをmarkdownに変換してくれるツール、だいたいtableが弱いイメージがあって、もしかするとLLM側でよしなに解釈してくれるかもしれないけど、きれいに渡せるならばそれに越したことはないかなとも思う。

という点で、HTMLのクリーニング的な意味合いで使えそうな気がする。ここはHandingerのユニークなところになるのかな?と思ったけど、Trafilaturaでもできるし、頑張るならばUnstructuredでもできるんだよな・・・

Trafilatura試した記事にも書いてるけど、サイトの作りとかで抽出したコンテンツの精度は変わってくると思うので、万能なものはないと思うし、ある程度の後処理をするか、割り切って使う、になるのではないかなと思う。となると、無料枠があるとはいえ何かしらの価値を見出して契約してまで使うかどうか、という判断になるかなぁ。

このスクラップは1ヶ月前にクローズされました