2025年のNODRIVERによるウェブスクレイピング

NODRIVERを使ってウェブスクレイピングをマスターしましょう。このガイドでは、セットアップ、主要機能、データ抽出ワークフローを合理化する方法について説明します。
4 分読
web scraping with NODRIVER blog image

何年もの間、Undetected Chromedriverは安全なブラウジングとアンチボットバイパスの定番であった。Undetected Chromedriverの開発者は、その後NODRIVERを開発しました。NODRIVERを使えば、SeleniumやWebdriverに依存する必要がなくなる。簡単なpipインストールで、全てが準備できるはずです。

このガイドでは、次のことを学ぶ:

  • NODRIVERとは?
  • 他のヘッドレス・ブラウザとの違いは?
  • NODRIVERの使い方
  • NODRIVERの限界とは?
  • NODRIVERをプロキシで使うには?
  • NODRIVERの堅実な代替品

NODRIVERとは何か?

NODRIVERとは何か?

NODRIVERはUndetected Chromedriverの完全な非同期後継である。すべてのkwargsのデフォルトとして「ベスト・プラクティス」を使用し、わずかなコード量ですぐに動作するように設計されている。

NODRIVERは次のような特徴を誇っている:

  • パフォーマンス
  • 外部依存なし(Chromedriverすらない)
  • アンチボット・バイパス
  • 永続的セッションクッキー
  • 使用するたびに新鮮なブラウザ・インスタンス

NODRIVERは何が違うのか?

NODRIVERは、Undetected Chromedriverや他のヘッドレスブラウザとも根本的に異なるアーキテクチャを使用している。従来、これらの他のブラウザはSeleniumやChrome DevTools Protocol(CDP)に依存していた。

NODRIVERはDevToolsプロトコルの独自の実装を使用している。ドキュメントでは、これは実際には「chrome(っぽい)自動化ライブラリ」と呼ばれています。NODRIVERでは、Seleniumに依存することもなく、CDPに直接依存することもありません。NODRIVERはCDPのカスタム実装を使用します。NODRIVERを使うために必要なのは、pipとクロームベースのブラウザだけです。

NODRIVERによるスクレイピング

1.はじめに

始める前に、Pythonとブラウザがインストールされていることを確認する必要がある。この記事を読んでいるということは、すでにこれらがインストールされているのだろう。NODRIVERはpipで直接インストールできます。

pip install nodriver

2.基本構造

私たちの基本的な構造は、PlaywrightやPuppeteerで得られるものと本当によく似ています。PythonでPlaywrightを使うことに興味があれば、Amazonのリストをスクレイピングするための完全なガイドをここで見ることができます。NODRIVERはPlaywrightとよく似ていますが、まだ開発中です。

これが基本的な構成だ。

import nodriver

async def main():
    #start the browser
    browser = await nodriver.start()

    base_url = "https://quotes.toscrape.com"

    #navigate to a page
    page = await browser.get(base_url)

    ###logic goes here###

    #close the browser
    await page.close()

if __name__ == '__main__':

    #in their docs, they advise directly against asyncio.run()
    nodriver.loop().run_until_complete(main())

3.ページの取得

上記の基本スケルトンでお気づきのように、browser.get()は ページ・オブジェクトを返す。複数のページを同時に開くこともできます。創意工夫を凝らせば、高度な並行操作も可能です。

以下のスニペットはあくまで理論的なものである。

#navigate to a page
page_1 = await browser.get(base_url)
page_2 = await browser.get(a_different_url)

####do stuff with the different pages#####

4.ダイナミックコンテンツ

動的コンテンツを処理するには、2つの選択肢があります。.sleep()メソッドで任意の時間を待つか、.wait_for()でページ上の特定のセレクタを待つかです。

#wait an arbitrary amount of time
await tab.sleep(1)

#wait for a specific element
await tab.wait_for("div[data-testid='some-value']")

注:上のスニペットでは、変数名としてpageの代わりにtabを使っている。これらは互換性がある。どちらもタブ・オブジェクトです。NODRIVERのタブについては、こちらで詳しく説明しています。

5.要素を見つける

NODRIVERはページ上の要素を見つけるための様々なメソッドを提供してくれる。いくつかのレガシーなメソッドを扱っている最中のようだ。

要素を見つけるためのテキストベースの方法は4種類ある。そのうちの2つは将来的になくなる可能性が高い。

#find an element using its text
my_element = page.find("some text here")

#find a list of elements by their text
my_elements = page.find_all("some text here")

#find an element using its text
my_element = page.find_element_by_text("some text here")

#find a list of elements using their text
my_elements = page.find_element_by_text("some text here")

上記のメソッドと同様に、要素を見つけるためのセレクタ・ベースのメソッドも4つある。そのうちの2つはおそらく消えるでしょう。NODRIVERの開発者がCDPと明確に連携したいのであれば、query_selectorメソッドはおそらく存続するでしょう。

#find a single element using its css selector
my_element = page.select("div[class='your-classname']")

#find a list of elements using a css selector
my_elements = page.select_all("div[class='your-classname']") 

#find a single element using its css selector
my_element = page.query_selector("div[class='your-classname']")

#find a list of elements using a css selector
my_elements = page.query_selector_all("div[class='your-classname']") 

上で見たように、ページ上の要素をどのように見つけたいとしても、その方法は複数ある可能性が高い。いずれ、NODRIVERの開発者たちはこの点を改善するかもしれない。とはいえ、現時点では、彼らの解析方法はスイス軍のチェーンソーのようなものだ。

6.データの抽出

NODRIVERはデータを抽出するためにいくつかの方法を提供しています。.attributes特質を使って属性を直接抽出することができますが、これはあまり使い勝手が良くありません – JSONオブジェクトではなく配列を返します。

リンク・オブジェクトからhrefを抽出するために私が作ったハッキーな回避策を紹介しよう。不格好だが、うまくいく。attributesメソッドは近いうちに、もう少し機能的なものに置き換えられると期待している。

next_button = await page.select("li[class='next'] > a")

#this returns an array
attributes = next_button.attributes

#use array indexing to find the href object and its value
for i in range(len(attributes)):
    if attributes[i] == "href":
        next_url = attributes[i+1]

注意: 他のほとんどのヘッドレス・ブラウザはget_attribute()メソッドを含んでいます。しかし、このメソッドはNODRIVERではまだ動作していません。

テキスト・データの抽出方法を説明しよう。お気づきかもしれないが、ここではawaitを使っていない。これは将来、他のCDPスタイルのブラウザに合わせるために変更されると思う。現在の形では、textは単なる属性であり、メソッドではありません。awaitを属性で使用すると、実際にはエラーが投げられます。これはPuppeteerとPlaywrightの両方に反するように感じますが、これがNODRIVERの現状です。

#find the quote element
quote_element = await quote.query_selector("span[class='text']")
#extract its text
quote_text = quote_element.text

7.データの保存

データを小さなJSONファイルに格納します。引用を抽出する場合、各引用にはタグのリストがあり、リストはCSV形式ではあまりうまくいきません。

import json

with open("quotes.json", "w", encoding="utf-8") as f:
    json.dump(scraped_data, f, ensure_ascii=False, indent=4)

8.すべてをまとめる

では、これらのコンセプトをすべてまとめて、実際に動くスクリプトにしてみましょう。以下の例では、QutoesからScrape(チュートリアルをスクレイピングするためだけに作られたサイト)にデータを抽出するために、上記のコンセプトを使用しています。以下のコードをコピー&ペーストして、NODRIVERが実際にどのように動作するかを感じてください。

import nodriver
import json

async def main():

    #list to hold scraped data
    scraped_data = []


    browser = await nodriver.start()

    next_url = "/"

    base_url = "https://quotes.toscrape.com"

    #while we still have urls to scrape
    while next_url:

        #go to the page
        page = await browser.get(f"{base_url}{next_url}")

        #find quote divs using a selector
        quotes = await page.select_all("div[class='quote']")

        #iterate through the quotes
        for quote in quotes:

            #find the quote element and extract its text
            quote_element = await quote.query_selector("span[class='text']")
            quote_text = quote_element.text

            #find the author and extract the text
            author_element = await quote.query_selector("small[class='author']")
            author = author_element.text

            #find the tag elements
            tag_elements = await quote.query_selector_all("a[class='tag']")
            tags = []

            #iterate through the tags and extract their text
            for tag_element in tag_elements:
                text = tag_element.text
                tags.append(text)

            #add our extracted data to the list of scraped data
            scraped_data.append({
                "quote": quote_text,
                "author": author,
                "tags": tags
            })

        #check the page for a "next" button
        next_button = await page.select("li[class='next'] > a")

        #if it doesn't exist, close the browser and break the loop
        if next_button == None:
            await page.close()
            next_url = None

        #if it does, follow this block instead
        else:
            attributes = next_button.attributes

            #loop through the attributes to find your desired attribute, its value is the next index
            for i in range(len(attributes)):
                if attributes[i] == "href":
                    next_url = attributes[i+1]

    #write the data to a json file
    with open("quotes.json", "w", encoding="utf-8") as f:
        json.dump(scraped_data, f, ensure_ascii=False, indent=4)


if __name__ == '__main__':

    nodriver.loop().run_until_complete(main())

上記のスクリプトを実行すると、以下のようなオブジェクトを含むJSONファイルが得られる。

[
    {
        "quote": "“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”",
        "author": "Albert Einstein",
        "tags": [
            "change",
            "deep-thoughts",
            "thinking",
            "world"
        ]
    },
    {
        "quote": "“It is our choices, Harry, that show what we truly are, far more than our abilities.”",
        "author": "J.K. Rowling",
        "tags": [
            "abilities",
            "choices"
        ]
    },

NODRIVERの現在の限界

現在、NODRIVERには特筆すべき重大な制限がある。それらについて説明しよう。

ヘッドレスモード

NODRIVERをヘッドレスモードで実行すると、必ずエラーがスローされる。これが意図的(アンチボットバイパスとして)なのか、それとも正当な問題なのかは分からない。

Pythonエラーのトレースバックがターミナルウィンドウに表示され、ファイルパスと行番号が参照されたNodriverスクリプトの最大再帰深度を超えたエラーが示されました。このエラーは、ヘッドレスセッションの準備とワンショットリクエストの送信に関する問題を示唆しています。

ページ相互作用

NODRIVERのドキュメントには数多くのページ・インタラクションが掲載されていますが、そのほとんどは部分的に動作するか、あるいは全く動作しません。ご覧のように、これは下のスクリーンショットのclick_mouse()mouse_click()の両方に記載されています。

非同期関数mouse_clickとclick_mouseのパラメータと使い方を示すコード・スニペット。ボタンの選択、修飾キー、待機用の内部イベントの詳細を含む。

属性抽出

NODRIVERの最大の問題点は属性抽出です。前述したように、これは配列を出力し、hrefの回避策で見たように非常に古臭いものです。これがattributeからのリテラル出力です。本番レベルのスクレイピングでは、これに対処する必要があります。

値'/page/2/'を持つハイパーリンク属性を配列形式で示すコードのスニペット。

NODRIVERによるプロキシの使用

現在のところ、NODRIVERのプロキシサポートはせいぜい限られています。NODRIVER はプロキシ接続のためのcreate_context()メソッドを提供しています。

以下のスニペットは、彼らの問題ページからのものだ。しかし、何時間たっても接続できない。

tab = await  browser.create_context("https://www.google.nl", proxy_server='socks5://myuser:mypass@somehost')

# or add  new_window=True if you would like a new window

彼らのドキュメントを見ると、プロキシに関するセクションがある[1]。公式なプロキシのセクションがあっても、実際のドキュメントはありません。これは近い将来修正されるものと思われる。

有効な代替案

現在のところ、本番用としてはまだ準備ができていないが、将来的にはNODRIVERの素晴らしい成果を期待している。もっとヘビーデューティーなものをお探しなら、以下のブラウザをご覧ください。

結論

NODRIVERはブラウザ自動化のためのエキサイティングな新ツールですが、急速に開発が進んでいるため、まだ成熟していない機能もあります。大規模で信頼性の高いウェブスクレイピングのためには、以下のような堅牢なソリューションの使用を検討してください:

無料トライアルに登録して、今すぐ始めましょう!

クレジットカードは必要ありません

あなたは下記にもご興味がおありかもしれません

web scraping with claude blog image
ウェブデータ

2025年のクロードによるウェブスクレイピング

Pythonを使ってWebスクレイピングを自動化し、構造化データを楽に抽出するClaude AIの使い方を学ぶ。
18 分読
Building AI-Ready Vector Datasets for LLMs blog image
AI

LLMのためのAI対応ベクトルデータセット構築:Bright Data、Google Gemini、Pineconeを使ったガイド

大規模言語モデル(LLM)は、私たちが情報にアクセスし、インテリジェントなアプリケーションを構築する方法を変革しています。LLMの可能性を最大限に引き出すには、特にドメイン固有の知識や独自のデータを使用する場合、高品質で構造化されたベクトルデータセットを作成することが重要です。LLMの性能と精度は、入力データの品質に直接結びついています。準備不足のデータセットは劣悪な結果をもたらす可能性があり、一方、十分にキュレーションされたデータセットはLLMを真のドメイン・エキスパートに変えることができます。 このガイドでは、AIに対応したベクターデータセットを生成するための自動パイプラインの構築方法を順を追って説明する。 課題:LLMのためのデータ収集と準備 LLMは膨大な汎用テキストコーパスで学習されますが、商品関連のクエリへの回答、業界ニュースの分析、顧客フィードバックの解釈など、特定のタスクやドメインに適用すると、不足することがよくあります。LLMを真に役立てるには、ユースケースに合わせた高品質のデータが必要です。 このデータは通常、ウェブ上に分散していたり、複雑なサイト構造の背後に隠されていたり、ボット対策によって保護されていたりする。 当社の自動ワークフローは、データセット作成の最も困難な部分を処理する合理化されたパイプラインでこれを解決します: コア技術の概要 パイプラインを構築する前に、関連するコアテクノロジーと、それぞれがワークフローをどのようにサポートしているかを簡単に見ておこう。 ブライトデータスケーラブルなウェブデータ収集 AIに対応したベクターデータセットを作成するための最初のステップは、関連性のある高品質なソースデータを収集することです。ナレッジベースやドキュメンテーションのような内部システムから得られるものもあるが、大部分は公共のウェブから得られることが多い。 しかし、最近のウェブサイトは、CAPTCHA、IPレート制限、ブラウザフィンガープリントなどの高度なボット対策メカニズムを使用しているため、大規模なスクレイピングは困難である。 Bright Dataは、データ収集の複雑さを抽象化するWeb Unlocker APIでこの課題を解決します。プロキシのローテーション、CAPTCHAの解決、ブラウザのエミュレーションを自動的に処理するため、データへのアクセス方法ではなく、データに集中することができます。 Google Gemini: インテリジェント・コンテンツ・トランスフォーメーション Geminiは、Googleによって開発された強力なマルチモーダルAIモデルのファミリーであり、様々なタイプのコンテンツを理解し処理することに優れている。私たちのデータ抽出パイプラインにおいて、Geminiは3つの重要な機能を果たします: このAIを活用したアプローチは、特に以下のような使用例において、脆弱なCSSセレクタや壊れやすい正規表現に依存する従来の方法よりも大きな利点をもたらす: AIがデータ抽出プロセスにどのような変化をもたらしているかについては、Using AI for Web Scrapingをご覧ください。スクレイピングのワークフローにGeminiを実装するための実践的なチュートリアルをお探しの場合は、包括的なガイドをご覧ください:GeminiによるWebスクレイピングをご覧ください。 文の変形意味埋め込み文の生成 エンベッディングは、高次元空間におけるテキスト(または他のデータタイプ)の密なベクトル表現である。これらのベクトルは意味的な意味を捉え、コサイン類似度やユークリッド距離のようなメトリクスを用いて測定される、類似したテキスト片を近接したベクトルで表現することを可能にする。この特性は、セマンティック検索、クラスタリング、検索拡張生成(RAG)のようなアプリケーションで重要である。 Sentence Transformersライブラリは、高品質の文や段落の埋め込みを生成するための使いやすいインターフェースを提供する。Hugging Face Transformersの上に構築され、意味タスクのために微調整された幅広い事前学習済みモデルをサポートしています。 このエコシステムで最も人気があり、効果的なモデルの1つがオールMiniLM-L6-v2である: より大きなモデルはより微妙なエンベディングを提供するかもしれないが、all-MiniLM-L6-v2は性能、効率、コストの間で非常に優れたバランスを提供する。その384次元ベクトルは ほとんどの実用的なユースケース、特に初期段階の開発やリソースに制約のある環境では、このモデルで十分すぎる。エッジケースにおける精度のわずかな低下は、通常、スピードとスケーラビリティの大幅な向上によって相殺されます。そのため、AIアプリケーションの最初のイテレーションを構築する場合や、控えめなインフラストラクチャでパフォーマンスを最適化する場合は、all-MiniLM-L6-v2を使用することをお勧めします。 Pineconeベクトル埋め込み画像の保存と検索 テキストがベクトル埋め込みデータに変換されると、それを効率的に保存、管理、照会するための専用のデータベースが必要になります。従来のデータベースはこのために設計されていません。ベクトル・データベースは、埋め込みデータの高次元の性質を扱うために特別に設計されており、RAGパイプライン、セマンティック検索、パーソナライゼーション、その他のAI駆動型アプリケーションに不可欠なリアルタイムの類似性検索を可能にします。 Pineconeは、開発者フレンドリーなインターフェイス、低レイテンシの検索パフォーマンス、完全に管理されたインフラストラクチャで知られる人気のベクトルデータベースです。ベクトル検索インフラストラクチャの複雑さを抽象化することで、複雑なベクトルインデックスと検索を効率的に管理します。主なコンポーネントは以下の通りです: Pineconeは2つのデプロイメントアーキテクチャを提供する:ServerlessとPod-Based です。ほとんどのユースケース、特に開始時や動的な負荷に対処する場合は、シンプルさとコスト効率からサーバーレスが推奨されます。 セットアップと前提条件 パイプラインを構築する前に、以下のコンポーネントが適切に設定されていることを確認する。 前提条件 各APIキーの生成方法については、以下のツール固有の設定セクションを参照してください。 必要なライブラリのインストール このプロジェクトのコアとなるPythonライブラリをインストールする: これらのライブラリーは提供している: 環境変数の設定 プロジェクトのルート・ディレクトリに.envファイルを作成し、APIキーを追加する: ブライトデータ設定 Bright DataのWeb Unlockerを使用するには: 実装例と統合コードについては、Web Unlocker GitHub […]
6 分読
AI

LLMにおけるスーパーバイズド・ファインチューニングとは?

このPythonガイドでは、概念、ツール、ワークフロー、そしてAIプロジェクトを向上させる実践的な例を取り上げています。
7 分読