何年もの間、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をヘッドレスモードで実行すると、必ずエラーがスローされる。これが意図的(アンチボットバイパスとして)なのか、それとも正当な問題なのかは分からない。
ページ相互作用
NODRIVERのドキュメントには数多くのページ・インタラクションが掲載されていますが、そのほとんどは部分的に動作するか、あるいは全く動作しません。ご覧のように、これは下のスクリーンショットのclick_mouse()
とmouse_click()の
両方に記載されています。
属性抽出
NODRIVERの最大の問題点は属性抽出です。前述したように、これは配列を出力し、hrefの
回避策で見たように非常に古臭いものです。これがattributeからの
リテラル出力です。本番レベルのスクレイピングでは、これに対処する必要があります。
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の素晴らしい成果を期待している。もっとヘビーデューティーなものをお探しなら、以下のブラウザをご覧ください。
- セレン2004年以来好調。SeleniumはChromedriverに依存していますが、戦闘テスト済みで本番に対応しています。Seleniumのウェブスクレイピングについてもっと知る。
- Playwright:Playwrightは、NODRIVERを使ったこのチュートリアルで見たものを、洗練された、すぐに使えるバージョンにした感じです。WebスクレイピングのためのPlaywrightの使い方を学んでください。
結論
NODRIVERはブラウザ自動化のためのエキサイティングな新ツールですが、急速に開発が進んでいるため、まだ成熟していない機能もあります。大規模で信頼性の高いウェブスクレイピングのためには、以下のような堅牢なソリューションの使用を検討してください:
- レジデンシャル・プロキシ:ジオブロックを回避するためのリアルデバイス接続。
- ウェブアンロッカー CAPTCHAソルバー内蔵のマネージドプロキシ。
- スクレイピング・ブラウザ:プロキシとCAPTCHAをサポートしたリモートブラウザ自動化。複数ステップのスクレイピングプロジェクトに最適なソリューションです。
- カスタムスクレーパー:コード不要のカスタムスクレイピングジョブを実行し、専門家によるデータ抽出を支援します。
無料トライアルに登録して、今すぐ始めましょう!
クレジットカードは必要ありません