XPathクローリング完全ガイド2026: ウェブデータ精密抽出の要点

XPath를 사용한 웹 크롤링 방법을 처음부터 실전까지 완벽하게 정리했습니다. Python lxml/requests 예제, CSS 선택자와의 비교, 주요 표현식 참조까지 모두 2026년 기준으로 작성되었습니다.

45
XPathクローリング完全ガイド2026: ウェブデータ精密抽出の要点

웹 크롤링을 처음 시작할 때 대부분 CSS Selector를 먼저 배웁니다. 그런데 실전에서 조금 복잡한 페이지를 만나면 CSS Selector만으로는 원하는 요소를 집어내기 어려운 상황이 생깁니다. 특정 텍스트를 포함한 요소만 선택하거나, 특정 자식 요소를 가진 부모 ノード를逆に探したり、条件付きフィルタリングをしなければならない時です.

これらの場合に必要なのがXPathです.

XPathはXML/HTMLドキュメントで特定のノードを探索するための標準言語です. CSS Selectorより表現力が強力であり、一部の場合にはCSSではまったく不可能な選択をすることができます. 2026年現在でもPython lxml、Scrapy、Playwright、Seleniumなどの主要なクローリングツールはすべてXPathをサポートしています.

この記事ではXPathの基本概念から実践的なクローリングコード、デバッグのヒントまで一度にまとめます.


1. XPathとは?

XPath(XML Path Language)はW3C標準であり、XMLおよびHTMLドキュメントのツリー構造を探索するためのクエリ言語です. 1999年に初めて発表されて以来、Web標準の中核技術として確立されています.

WebページのHTMLはツリー構造です. htmlルートから始まり、body、さまざまなdiv、span、aタグが親子関係で接続されます. XPathはこのツリー構造をファイルシステムパスのように表現します.

たとえば、ファイルシステムで/home/user/documents/report.txtのようにパスを指定するように、HTMLでは/html/body/div/pのようにノードを特定します.

CSS Selector vs XPath: いつ何を使うか?

機能 CSS Selector XPath
基本要素選択 簡潔 可能
特定のテキストを含む要素の選択 不可能 contains(text(), 'キーワード')
親ノード逆方向選択 不可能 ..またはparent::
兄弟ノードアクセス 制限的 following-sibling::preceding-sibling::
条件付きフィルタリング 基本的なもののみ 複雑な条件可能
学習難易度 簡単 中級
ブラウザパフォーマンス 速い やや遅い

一般的なWebクローリングではCSS Selectorを基本として使用し、CSSでは表現できない場合はXPathを補助として使用する戦略が効果的です.


2. XPathの主要構文リファレンス

基本パス式

/html/body/div          # 절대 경로 (루트부터 전체 경로)
//div                   # 문서 전체에서 모든 div 요소
//div[@class='title']   # class 'title' div
//a[@href]              # href 속성이 있는 모든 a 태그

//(二重スラッシュ)が重要です. 実践では絶対パス(/html/body/...)よりも//を使用した相対パスがはるかに多く使われます. ページ構造が変わっても比較的安定しているためです.

属性セレクター

//div[@id='main']                    # id 'main' div
//input[@type='submit']              # type 'submit' input
//a[contains(@class, 'btn')]         # class 'btn' 포함된 a
//img[@src and @alt]                 # src alt 속성 모두 있는 img
//a[not(@href)]                      # href 없는 a 태그

contains()はCSSの[class*="btn"]に似ていますが、テキスト内容にも適用できるため、はるかに柔軟です.

テキストセレクター

//h2[text()='이벤트 공지']                    # 정확히 '이벤트 공지' 텍스트인 h2
//p[contains(text(), '할인')]                  # '할인' 텍스트를 포함하는 p
//button[normalize-space(text())='구매하기']   # 공백 제거  '구매하기' 버튼

これがXPathの主要な利点です. CSS Selectorはテキスト内容で要素を選択することはできませんが、XPathはtext()contains()を組み合わせて自由にテキストベースの選択が可能です.

軸(Axis)探索

//span[@class='price']/parent::div          # 특정 span 부모 div
//td[contains(@class, 'total')]/../td[1]    # 형제 td  번째
//h3/following-sibling::p                   # h3 다음에 오는 형제 p 태그
//li[last()]                                # 마지막 li 항목
//li[position() <= 5]                       #  5 li 항목

親逆方向探索はXPathでのみ可能な機能です. たとえば、特定のクラスのボタンを含むカードコンテナ全体を取得したい場合に便利です.


3. PythonでのXPathクローリング(lxml)

基本的なインストールと構造

import requests
from lxml import html

url = "https://example.com/products"
response = requests.get(url, headers={
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
})

tree = html.fromstring(response.content)

# XPath로 데이터 추출
titles = tree.xpath('//h2[@class="product-title"]/text()')
prices = tree.xpath('//span[@class="price"]/text()')
links = tree.xpath('//a[@class="product-link"]/@href')

for title, price, link in zip(titles, prices, links):
    print(f"{title} | {price} | {link}")

lxml.html.fromstring()でHTMLをパースした後、.xpath()メソッドにXPath式を渡せばよいです. 戻り値はリストです.

テキスト vs @属性選択

# 요소 텍스트 추출: /text()
titles = tree.xpath('//h1/text()')

# 속성값 추출: /@속성명
hrefs = tree.xpath('//a/@href')
images = tree.xpath('//img/@src')

# 요소 객체 자체를 가져올 때 (하위 탐색 필요 시)
product_cards = tree.xpath('//div[@class="product-card"]')
for card in product_cards:
    title = card.xpath('.//h2/text()')  # 점(.)은 현재 요소 기준
    price = card.xpath('.//span[@class="price"]/text()')
    print(title[0] if title else "N/A", price[0] if price else "N/A")

必ず知っておくべきこと: 要素オブジェクトをループで処理する際に内部.xpath()にはピリオド(.)を付けて、現在の要素を基準に探索する必要があります. ピリオドなしで//h2/text()を使用すると、ドキュメント全体から再度検索します.

contains()で柔軟な選択

# class에 특정 단어가 포함된 경우
items = tree.xpath('//*[contains(@class, "item")]')

# 텍스트에 특정 단어가 포함된 링크
discount_links = tree.xpath('//a[contains(text(), "할인")]/@href')

# 여러 조건 조합 (and/or)
main_buttons = tree.xpath('//button[contains(@class, "btn") and @type="submit"]')

4. 動的ページクローリング: Playwright + XPath

静的HTMLはrequests + lxmlで十分ですが、JavaScriptでレンダリングされる動的ページはPlaywrightやSeleniumが必要です. これらのツールはどちらもXPathをサポートしています.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://target-site.com")

    # XPath로 요소 선택
    # locator 방식 (권장)
    price = page.locator('xpath=//span[@class="final-price"]').first.text_content()

    # evaluate로 XPath 직접 실행
    result = page.evaluate("""
        () => {
            const el = document.evaluate(
                '//h1[@class="product-name"]/text()',
                document,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;
            return el ? el.nodeValue : null;
        }
    """)

    print(price, result)
    browser.close()

Playwrightのlocator('xpath=...')はXPath式の前にxpath=接頭辞を付ける必要があります.


5. XPathデバッグ: ブラウザで直接テスト

クローリングコードを書く前にXPathが正しいかブラウザで最初に確認できます.

Chromeデベロッパーツールの使用方法:
1. F12または右クリック → 検証
2. Consoleタブを選択
3. 以下のコードを入力:

// 단일 요소 찾기
$x('//h1[@class="title"]')

// 모든 매칭 요소 텍스트 출력
$x('//span[@class="price"]').map(e => e.textContent)

// 첫 번째 매칭 텍스트
$x('//div[@class="product-name"]')[0]?.textContent

$x()はChromeとFirefoxの両方で使用できる組み込みXPathテスト関数です. コードを書く前に、選択したい要素が正しく選択されていることを必ず確認してください.


6. 実践例: Eコマース商品データの抽出

import requests
from lxml import html

def scrape_product_list(url):
    headers = {"User-Agent": "Mozilla/5.0 (compatible; DataCollector/1.0)"}
    resp = requests.get(url, headers=headers, timeout=10)
    tree = html.fromstring(resp.content)

    # 상품 카드 전체 목록 가져오기
    cards = tree.xpath('//li[contains(@class, "product-item")]')

    results = []
    for card in cards:
        name = card.xpath('.//strong[@class="product-name"]/text()')
        price = card.xpath('.//span[contains(@class, "price")]/text()')
        rating = card.xpath('.//span[@class="rating"]/text()')
        reviews = card.xpath('.//span[@class="review-count"]/text()')
        link = card.xpath('.//a[@class="product-link"]/@href')

        results.append({
            "name": name[0].strip() if name else None,
            "price": price[0].strip() if price else None,
            "rating": rating[0].strip() if rating else None,
            "reviews": reviews[0].strip() if reviews else None,
            "url": link[0] if link else None,
        })

    return results

products = scrape_product_list("https://example-shop.com/category/shoes")
print(f"수집된 상품 수: {len(products)}")

7. よくあるエラーと解決方法

IndexError: list index out of range

# 잘못된 방법
title = tree.xpath('//h1/text()')[0]  # 요소 없으면 에러 발생

# 올바른 방법
titles = tree.xpath('//h1/text()')
title = titles[0] if titles else None

要素は表示されるがXPathで取得できない場合

原因はほとんどが名前空間または動的レンダリングの問題です.

# 네임스페이스가 있는 경우
namespaces = {'ns': 'http://www.w3.org/1999/xhtml'}
result = tree.xpath('//ns:div[@id="content"]', namespaces=namespaces)

# 실제로 화면에는 있지만 XPath로 안 잡힐 때 → 동적 렌더링 확인
# requests로 받은 HTML에는 없고, 브라우저에서만 보이는 경우
# → Playwright/Selenium으로 전환 필요

テキスト抽出時の空白問題

# normalize-space()로 앞뒤 공백 및 연속 공백 제거
clean_text = tree.xpath('normalize-space(//h1/text())')

# Python에서 후처리
texts = [t.strip() for t in tree.xpath('//p/text()') if t.strip()]

8. XPathの限界と代替手段

XPathは強力ですが、限界もあります.

構造の変更に弱い: 絶対パス(/html/body/div[2]/div[3]/ul/li)を使用すると、サイトのリデザインで全体のXPathが無効になります. 可能な限り@id@class属性ベースのXPathを使用してください.

JavaScriptレンダリング: XPathはHTMLパースツールであり、レンダリングツールではありません. 動的にロードされるコンテンツはrequests + lxmlの組み合わせでは収集できません.

大規模クローリング: 数千ページ以上を収集する場合は、lxml単独よりもScrapyを使用する方がはるかに効率的です. ScrapyはXPathとCSS Selectorの両方をサポートし、非同期処理、ミドルウェア、パイプラインを備えています.


ハッシュスクレイパーでXPathなしでクローリングする

XPathを学ぶこと自体は有益ですが、プロダクションクローラーを直接メンテナンスするコストは思ったよりも高くつきます. サイト構造が変わるたびにXPathを更新する必要があり、JavaScriptレンダリング処理、IPブロック回避などを別途処理する必要があります.

ハッシュスクレイパーはこのプロセスをAPI一度の呼び出しで処理します. 別のXPathやCSS SelectorなしにURLだけを渡すと、JavaScriptでレンダリングされたHTMLをマークダウン、JSON、HTML形式で返します.

import requests

response = requests.post(
    "https://api.hashscraper.com/v1/scrape",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "url": "https://target-site.com/products",
        "renderJs": True,
        "outputFormat": "markdown"
    }
)

data = response.json()
print(data["content"])  # 정제된 마크다운으로 반환

自分でクローラーを構築することが難しい場合や、クローリングインフラの管理に時間を費やしたくない場合は、ハッシュスクレイパー無料トライアルを始めてみてください.


まとめ

  • XPathはCSS Selectorでは解決できない複雑な選択に使用します
  • テキストベースの選択、親逆方向探索、条件付きフィルタリングが主要な利点です
  • Python: lxml + .xpath()の組み合わせが最も一般的
  • 動的ページ: Playwrightのlocator('xpath=...')を使用
  • デバッグ: Chromeコンソールの$x()を使用して迅速にテスト
  • 大規模クローリングは直接XPathを管理するよりもハッシュスクレイパーAPIの活用を検討してください

この記事が役立った場合は、Playwrightクローリング完全ガイドScrapyクローリング完全ガイドも合わせて読んでみてください.

Comments

Add Comment

Your email won't be published and will only be used for reply notifications.

続きを読む

Get notified of new posts

We'll email you when 해시스크래퍼 기술 블로그 publishes new content.

Your email will only be used for new post notifications.