**Show HN: wxpath – XPathによる宣言型ウェブクローリング**

2026/01/15 1:52

**Show HN: wxpath – XPathによる宣言型ウェブクローリング**

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

改訂要約

wxpath は、XPath 式を使用してウェブサイトのデータをナビゲートおよび抽出できる軽量で宣言的な Web クロールライブラリです。主に 2 つのトラバーサル演算子に基づいています:

url(...)
は URL を取得し、lxml.html.HtmlElement を返します。
///url(...)
は指定された深さまで(幅優先的に)ディープクロールを実行します。クロールはデフォルトで非同期(asyncio/aiohttp 経由)で実行されますが、
wxpath_async_blocking_iter
ヘルパーを使用して同期実行も可能です。礼儀正しいデフォルト設定が自動的に有効化されます—robots.txt が尊重され、カスタム HTTP ヘッダー(例:User‑Agent)は
CRAWLER_SETTINGS.headers
で設定できます。

API は lxml 要素、elementpath データ型(マップ、配列)、辞書、リスト、および provenance‑tracked WxStr 文字列などの構造化オブジェクトを返します。XPath 3.1 機能は

elementpath
ライブラリを介してサポートされ、
wx:backlink(.)
のような関数が使用可能です。
progress=True
を設定すると tqdm バーで進捗状況を可視化できます。

ユーザーはコマンドラインツール(

wxpath
)を通じて XPath クエリと深さ、並列度、ヘッダー、robots.txt の遵守、およびキャッシュに関するオプションを受け取ります。フックを使用して URL の事前処理や取得した HTML の後処理をカスタマイズできます。組み込みの
JSONLWriter
フックは結果を行区切り JSON で記録します。永続化は sqlite(単一ワーカー)または redis(複数ワーカー)を介して追加でき、
SETTINGS.http.client.cache.enabled
のような設定で制御されます。

総じて、wxpath は開発者に対し、ボイラープレートコードを書かずに効率的かつ礼儀正しい Web スクレイピングを行うための簡潔で拡張可能な方法を提供します。

本文

wxpath – XPathで宣言的に Web クロール

wxpath は、クロール経路を直接 XPath で記述できる宣言型ウェブクローラです。
命令的なループを書かずに「何をたどり」「何を抽出する」ことを一つの式で表現します。
エンジンはその式を並行して実行(幅優先っぽい)し、発見次第結果をストリームとして返します。

NOTE – プロジェクトはまだ開発初期です。コア概念は安定していますが、API と機能は変更される可能性があります。
デッドロックしたクロールや予期せぬ挙動の報告・新機能提案をお願いします。実装保証はありません。

目次


import wxpath
from wxpath.settings import CRAWLER_SETTINGS

# 礼儀正しさのためのカスタムヘッダー(例:Wikipedia が要求)
CRAWLER_SETTINGS.headers = {
    'User-Agent': 'my-app/0.4.0 (contact: you@example.com)'
}

path_expr = """
url('https://en.wikipedia.org/wiki/Expression_language')
  ///url(//main//a/@href[starts-with(., '/wiki/') and not(contains(., ':'))])
    /map{
        'title':                 (//span[contains(@class, "mw-page-title-main")]/text())[1] ! string(.),
        'url':                   string(base-uri(.)),
        'short_description':     //div[contains(@class, 'shortdescription')]/text() ! string(.),
        'forward_links':         //div[@id="mw-content-text"]//a/@href ! string(.)
    }
"""

for item in wxpath.wxpath_async_blocking_iter(path_expr, max_depth=1):
    print(item)

出力

{
  "title": "Computer language",
  "url": "https://en.wikipedia.org/wiki/Computer_language",
  "short_description": "Formal language for communicating with a computer",
  "forward_links": [
    "/wiki/Formal_language",
    "/wiki/Communication",
    ...
  ]
}

式は以下を行います:

  1. https://en.wikipedia.org/wiki/Expression_language
    を起点にする。
  2. <main>
    内の
    /wiki/
    で始まり、コロン(
    :)
    を含まないリンクをフィルタ。
  3. 各リンクへ遷移し、以下を抽出:
    • title
    • URL
    • short description
  4. max_depth
    に到達したら停止。

データは取得次第すぐにストリームで返されます。


言語設計

詳細は

DESIGN.md
を参照してください。
宣言型クローラをゼロから設計する際のコア概念と手順が記載されています。

url(...) と ///url(...) の解説

演算子目的
url(...)
ユーザー指定または動的に生成された URL を取得し、さらに XPath 処理に使える
lxml.html.HtmlElement
を返す。
///url(...)
深い クロールを示す:実行時に指定した
max_depth
までリンクを辿り続ける。
複数回の
url()
で連鎖する代わりに、単一式でより深いグラフ探索を記述できる。
過度な展開は避け、
max_depth
や predicate を使って制御してください。

一般的な流れ

  1. 評価 – wxpath は式を セグメント(遷移/抽出ステップ)のリストへパース。
  2. クロールタスク
    url(...)
    が静的/動的 URL を生成し、全体で重複除外を試みる。
  3. XPath セグメント – 前の
    url(...)
    から取得したドキュメントに対して実行。
  4. 深いクロール
    ///url(...)
    が幅優先で
    max_depth
    まで展開。
  5. Yield – 準備が整い次第結果を返す。

非同期クロール

wxpath は

asyncio
/
aiohttp
を基盤に構築されています。

import asyncio
from wxpath import wxpath_async

items = []

async def main():
    path_expr = "url('https://en.wikipedia.org/wiki/Expression_language')///url(//@href[starts-with(., '/wiki/')])//a/@href"
    async for item in wxpath_async(path_expr, max_depth=1):
        items.append(item)

asyncio.run(main())

ブロッキング、同時実行リクエスト

asyncio
ループが無い環境向け。

from wxpath import wxpath_async_blocking_iter

path_expr = "url('https://en.wikipedia.org/wiki/Expression_language')///url(//@href[starts-with(., '/wiki/')])//a/@href"
items = list(wxpath_async_blocking_iter(path_expr, max_depth=1))

礼儀正しいクロール

デフォルトで

robots.txt
を尊重します。

engine = WXPathEngine(..., robotstxt=True)

CLI フラグで有効/無効を切り替え可能です。


出力タイプ

Python API は以下のような構造化オブジェクトを返します:

  • lxml.*
    ,
    lxml.html.*
  • elementpath.datatypes.*
    (XPath 3.1 機能用)
  • WxStr
    – 由来情報付き文字列
  • 辞書 / マップ
  • リストやその他 XPath ネイティブ値

CLI はこれらを平坦化し、JSON として表示します。


XPath 3.1 対応

wxpath は elementpath ライブラリを利用し、マップ・配列などの高度な機能をサポートします。

path_expr = """
    url('https://en.wikipedia.org/wiki/Expression_language')
    ///url(//div[@id='mw-content-text']//a/@href)
    /map{ 
        'title':          (//span[contains(@class, "mw-page-title-main")]/text())[1], 
        'short_description': (//div[contains(@class, "shortdescription")]/text())[1],
        'url':            //link[@rel='canonical']/@href[1]
    }
"""

結果例

{
  "title": "Computer language",
  "short_description": "Formal language for communicating with a computer",
  "url": "https://en.wikipedia.org/wiki/Computer_language"
}

プログレスバー

tqdm
を使って進行状況を表示。

items = wxpath.wxpath_async_blocking("…", progress=True)

出力例

> 100%|██████████████████████████████████████████████████████▎|
469/471 [00:05<00:00, 72.00it/s, depth=2, yielded=457]

CLI

ターミナルから直接実験できるコマンドラインインターフェースです。

wxpath --depth 1 \
    --header "User-Agent: my-app/0.1 (contact: you@example.com)" \
    "url('https://en.wikipedia.org/wiki/Expression_language') \
     ///url(//div[@id='mw-content-text']//a/@href[starts-with(., '/wiki/') \
        and not(matches(@href, '^(?:/wiki/)?(?:Wikipedia|File|Template|Special|Template_talk|Help):'))]) \
     /map{ \
         'title':(//span[contains(@class, 'mw-page-title-main')]/text())[1], \
         'short_description':(//div[contains(@class, 'shortdescription')]/text())[1], \
         'url':string(base-uri(.)), \
         'backlink':wx:backlink(.), \
         'depth':wx:depth(.) \
     }"

JSONL 出力

{"title":"Computer language","short_description":"Formal language for communicating with a computer",
 "url":"https://en.wikipedia.org/wiki/Computer_language","backlink":"https://en.wikipedia.org/wiki/Expression_language",
 "depth":1.0}
...

よく使う CLI オプション

オプション説明
--depth <depth>
最大クロール深度
`--verbose [truefalse]`
`--debug [truefalse]`
--concurrency <n>
同時取得数
--concurrency-per-host <n>
ホストあたりの同時取得数
--header "Key:Value"
カスタムヘッダー(複数可)
`--respect-robots [truefalse]`
`--cache [truefalse]`

永続化とキャッシュ

大規模クロールや途中で中断・再開したい場合に有効です。

バックエンド

バックエンド用途例
SQLite小規模クローラ、ワーカ 1 本 (
engine.crawler.concurrency == 1
)
Redis大規模クローラ、多数ワーカー

SQLite を使用しながら

min(engine.crawler.concurrency, engine.crawler.per_host) > 1
の場合は警告が表示されます。

インストール

pip install wxpath[cache-sqlite]   # または cache-redis

キャッシュを有効化

from wxpath.settings import SETTINGS

# SQLite がデフォルト
SETTINGS.http.client.cache.enabled = True

# Redis バックエンドの場合
SETTINGS.http.client.cache.backend = "redis"
SETTINGS.http.client.cache.redis.address = "redis://localhost:6379/0"

# 通常通り wxpath を実行
items = list(wxpath_async_blocking_iter('...', max_depth=1, engine=engine))

設定

settings.py
に全設定項目が記載されています。


フック(実験的)

wxpath はクロール/抽出挙動を変更できるプラグイン可能なフックシステムを備えています。

フックの登録

from wxpath import hooks

@hooks.register
class OnlyEnglish:
    def post_parse(self, ctx, elem):
        lang = elem.xpath('string(/html/@lang)').lower()[:2]
        return elem if lang in ("en", "") else None

フックは同期/非同期のいずれかで実装し、すべて同じスタイルである必要があります。混在は未サポートです。

既定フック

JSONLWriter
(別名
NDJSONWriter
)は抽出データを改行区切り JSON ファイルへ書き込みます。

from wxpath import hooks
hooks.register(hooks.JSONLWriter)

インストール

Python 3.10+ が必要です。

pip install wxpath[cache-sqlite]   # もしくは cache-redis

その他の例

EXAMPLES.md
に多様な使用パターンを掲載しています。


比較

COMPARISONS.md
で他ツールとの比較が記載されています。


高度な: エンジン & クローラ設定

エンジンやクローラは自由にカスタマイズ可能です。

from wxpath import wxpath_async_blocking_iter
from wxpath.core.runtime import WXPathEngine
from wxpath.http.client.crawler import Crawler

crawler = Crawler(
    concurrency=8,
    per_host=2,
    timeout=10,
    respect_robots=False,
    headers={
        "User-Agent": "my-app/0.1.0 (contact: you@example.com)",
    },
)

engine = WXPathEngine(crawler=crawler)

path_expr = "url('https://en.wikipedia.org/wiki/Expression_language')//url(//main//a/@href)"
items = list(wxpath_async_blocking_iter(path_expr, max_depth=1, engine=engine))

プロジェクト哲学

原則

  • ボイラープレートなしで宣言的クロール/スクレイピングを実現
  • 軽量かつ組み合わせやすい設計
  • 高速クローリングのため非同期化

目標

  • URL のグローバル重複除外(最善策)
  • フロンティアが枯渇または
    max_depth
    に到達したら終了
  • 同時リクエストを実装
  • 発見次第結果をストリーム化

警告

  • ウェブサイトのポリシーに従い、デフォルトでスクレイピング制限(スロットリング)を有効にしています。
  • ///
    で深くクロールすると探索爆発が起こる可能性があります。predicate と
    max_depth
    を活用してください。
  • エッジケースでデッドロック/ハングが発生する場合があります。報告してください。
  • タイムアウト、
    max_depth
    、XPath フィルタを使ってクロール範囲を制限しましょう。

商用サポート / コンサルティング

wxpath でクローラやデータフィードの構築・運用支援が必要な場合は
rodrigopala91@gmail.com までご連絡ください。


寄付

wxpath が役立ったと感じたら、開発への寄付を検討してください。


バージョニング

wxpath はセマンティックバージョニングに従います:

<MAJOR>.<MINOR>.<PATCH>

1.0.0 未満は
0.<MAJOR>.<MINOR|PATCH>
形式です。


ライセンス

MIT © 2026

同じ日のほかのニュース

一覧に戻る →

2026/01/21 3:16

**2019年 「見えないままに隠された26000年前の天文モニュメント」**

## Japanese Translation: **概要:** フーバーダムの西側にあるモニュメント・プラザは、地球の25,772年周期の軸進動をタレーズ床にマッピングした芸術的な敬意表現です。設計の中心には旗竿があり、これは進動円の中心として機能します。その周囲には巨大な翼付きブロンズ像が配置されています。床はダム開業時(1936年)のポラリス、ピラミッド建設中のトゥバン、そして将来の北極星としてプロジェクトされたベガを示しており、技術図面には惑星位置が正確に配置されているため、1日単位での日付計算が可能です。1931年に米国再利用局(U.S. Bureau of Reclamation)から委託され、1936年に完成したモニュメントは後にモニュメント・プラザと名付けられました。アーティストのオスカー J. W. ハンセン氏の意図表明は抽象的であり、歴史家エメー・ウッドワードが提供したアーカイブ写真には「セーフティアイランド」という早期建設名が示されています。デザインはロング・ナウ(Long Now)の10,000年時計コンセプトを反映しており、天体周期の公衆展示に類似するものとしてインスピレーションを与える可能性があります。米国再利用局が計画図をInternet Archiveへ公開したことは、ダム文書へのオープンアクセス化の動向を示しています。訪問者には短い音声解説のみが提供されるため、詳細な科学内容はほぼ隠蔽されており、教育的広報は限定的です。それでもプラザは20世紀初頭の大規模インフラプロジェクトにおける芸術と科学の統合を示す具体例として、歴史家・天文学者・エンジニアに貴重な実証を提供します。

2026/01/21 6:34

**日本のスナックバーの秘密世界へようこそ** 「おかかん」と呼ばれることもある日本のスナックバーは、地元ならではの味と創造性を堪能できる隠れた宝石です。小さな飲食店が揃うこれらのお店では、フライドライスボール(おにぎり)や塩気のあるペストリー、甘いスイーツなど、手軽で美味しい一口料理を提供しつつ、親切なサービスも楽しめます。 - **雰囲気**:街角の居心地の良い隅っこや静かな路地裏が主流です。 - **メニューの見どころ**: - 海苔と醤油をトッピングしたフライドライスボール - 蜂蜜でコーティングされた甘いかぼちゃロール - 豚肉と竹笹の餡が入った塩味の餃子 - **特徴**: - 多くのお店では、新鮮な地元産食材を使用しています。 - 季節ごとにメニューが変わるローテーションもあります。 おかかんへ足を踏み入れることは、単なるスナックの取得以上の体験です。便利さと伝統が交差する日本の食文化を垣間見る瞬間なのです。

## Japanese Translation: スナックバー―第二次世界大戦後に厳しい酒類法を回避するために登場した、女性が経営する小規模カフェ―は、日本独自の社会的ハブとして確立しました。全国には約10万店舗が存在し、コンビニエンスストアの数を2倍以上上回ります。これらは「ママさん」と呼ばれる年配女性によって運営され、家庭的な雰囲気でシンプルなお菓子や飲み物を提供します。主目的は食べ物や飲み物だけでなく、会話と個人的つながりを得られる居心地の良い空間を提供することです。 このコンセプトは日本の戦後経済成長期に急速に広がりました。1960年代後半には全国的にスナックバーが普及し、コミュニティのハブとなり、その後1980年代中頃から1990年代初頭まで存続しました。特徴として「ボトルキープ」システムがあります:常連客は自分のウイスキーや焼酎をラベル付けして保管し、次回訪問時に利用できます。伊良谷真由子(Mayuko Igarashi)氏などの研究者は2021年以降、1200件以上の店舗を巡り、旅行者とこれまで地元住民限定だった場所を結びつけています。 スナックバーはCOVID-19以前から人気低下やホスト人口の高齢化、カラオケバーやチェーン居酒屋との競争など課題に直面していますが、新しいトレンドが存続を支えています。アニメテーマのスナック、SNSプロモーション、LGBTQ+来客へのより包括的な対応などです。著名例として新橋の「Aeru」のウララ氏は14年間でタロットリーディングと現代のマッチメイキング手法を用いて90組以上のカップルを紹介しています。 デジタルライフの圧力にもかかわらず、スナックバーはママさんとの真の人間関係や親密な会話が評価され続けています。旅行者は、豪華ホテルや寿司教室など高価な観光活動よりも、これらの場所での思い出深い体験を重視しており、地元経済と伝統的ホスピタリティ慣行の保存に対する継続的な関連性を示しています。

2026/01/21 1:48

**UNIXパイプ・カードゲーム**

## Japanese Translation: 記事は、子どもに Unix パイプコマンドチェーンの構築方法を教えるカードベースのボードゲームについて説明しています。デッキには、`cat`、`grep`、`tail`、**`head`、`wc`、`sort`、`uniq`** などの主要な Unix コマンドを表すカードと、特定行の表示、出現回数のカウント、非表示コマンドチェーンの作成といったタスクが含まれています。ローカルの Unix システムが利用できない場合は、ブラウザベースの jslinux を使用できます。 ゲームプレイは時計回りに進行します:プレイヤーはカードを引き、最短または最長の有効パイプラインを目指すかどうかを選択し、タスクを完了した最初のプレイヤーがポイントを獲得します。例として、最も頻出する行を見つけるチェーンを示すラウンドがあります: ``` cat 03.txt | sort | uniq -c | sort -n | tail -1 ``` ゲームは €5,00 EUR(現在完売)で販売されており、印刷可能な PDF(`unix-pipe-cards.pdf`、`unix-pipe-box.pdf`)も入手できます。 GitHub 上のソースコードリポジトリ(`github.com/jackdoe`)、共著者 Jackie、連絡メールアドレス (`b0000@fastmail.com`) と CC BY 4.0 ライセンスが製品に付属しています。 「UNIX Pipe Game – Process Substitution」という拡張パックでは、プロセス置換用のコマンド(`paste`、`tr`、`cut`、`bc`)を追加します。 著者は Python の基礎、C ポインタ、機械語、ランレングス符号化、関数合成、RISCV アセンブラなどをカバーする追加のカードゲームも公開しており、子ども向けにプログラミング概念をゲーミフィケーションする広範な取り組みを示しています。