【Webドライバー不要】pydollでスクレイピングを試してみる

# 0. はじめに

いつものようにXこと旧Twitterで情報を漁っていたら、pydollというスクレイピングライブラリを見つけましたので今回はこいつを動かしてみます

https://github.com/autoscrape-labs/pydoll

- 動作環境
・ OS : Windows11 pro
・ python : 3.12.8
・ pydoll-python : 1.7.0
・ Jupyter Notebook(ipykernel)


# 1. pydollとは？

ブラウザ自動化といえば、SeleniumやPlaywrightなどが有名ですが、これらはWebDriverや外部バイナリの管理が煩雑で、非同期処理や人間らしい操作の再現に課題がありました。
Pydollは、WebDriverを使用せずに、Chromiumベースのブラウザを自動化するPythonライブラリです。

作者のredditを見つけましたが、スクレイピングしている時にCAPTCHAに苦しめられたそうで、その対策も入っているようです

https://www.reddit.com/r/Python/comments/1j689ag/i_built_a_python_library_for_realistic_web/

# 2. pydollの実力を試してみる

導入は簡単　`pip install pydoll-python`

このライブラリはCAPTCHAに強いとのことなので、botチェッカーサイトで試してみることにする。

なおこのライブラリは`Pythonの非同期プログラミングに基づいた設計`がされている為、`async/await`構文を使う必要があります。

```python:pydollでbotチェッカーサイトにアクセスしてみる(練習.ipynb)
import re
import asyncio
from pydoll.browser.chrome import Chrome

# Jupyter Notebookで非同期関数を実行するための関数
import nest_asyncio
nest_asyncio.apply()

browser = None
page = None

async def start_browser():
    """ ブラウザを立ち上げる関数 """
    global browser, page
    if browser is None:  # まだブラウザが起動していない場合のみ実行
        browser = Chrome()
        await browser.start()
        page = await browser.get_page()
        print("ブラウザを起動しました")
    return browser, page


async def access_url(url):
    """ URLにアクセスする関数 """
    global browser, page
    
    # ブラウザがまだ起動していなければ起動
    if browser is None:
        await start_browser()
    
    # 指定されたURLに移動
    await page.go_to(url)
    print(f"{url}にアクセスしました")
    return page


async def get_text_by_css(css_selector):
    """ CSSセレクタ要素から文字を取得する関数 """
    global page
    try:
        # CSSセレクタで要素を取得
        element = await page.find_element(By.CSS_SELECTOR, css_selector)
        
        # 要素のテキストを取得
        try:
            # inner_htmlプロパティ
            text = await element.inner_html
            # HTMLタグを除去して純粋なテキストを返す
            clean_text = re.sub(r'<[^>]*>', '', text).strip()
            return clean_text
        except Exception as e:
            print(f"テキスト取得に失敗: {e}")
            return None
            
    except Exception as e:
        print(f"要素の取得に失敗: {e}")
        return None

async def close_browser():
    """ ブラウザを立ち下げる関数 """
    global browser
    if browser:
        await browser.stop()
        browser = None
        page = None
        print("ブラウザを終了しました")


# 最初にブラウザを起動
browser, page = await start_browser()

# URLにアクセス
url = "https://www.browserscan.net/bot-detection"
page = await access_url(url)

# 「Browser bot detection guide」の文字を取得
text_element = 'h1[class="_1tl1b6r"]'
text = await get_text_by_css(text_element)
print(f"要素：{text_element}に書かれている文字は{text}です")

# ブラウザを立ち下げる
await close_browser()
```

```CMD:Jupyter出力
ブラウザを起動しました

https://www.browserscan.net/bot-detectionにアクセスしました

"要素：h1[class="_1tl1b6r"]に書かれている文字はBrowser bot detection guideです

ブラウザを終了しました
```

そして以下が実施にアクセスされたページであるが、Test Resultが「Normal」と書かれているので、このサイト基準ではこのアクセスはbotと見なされていないことになります

![スクリーンショット 2025-04-21 210910.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/8136ba65-28fd-42e1-83fa-222bc68fae7d.png)


なお、同サイトにseleniumでアクセスすると以下のようになりました

```python:selenium
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://www.browserscan.net/bot-detection")
```

以下図のようにWebdriverが検知され、Botとして検知されていることがわかります。

![スクリーンショット 2025-04-21 2131a29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/34d79035-b398-4d01-bab2-db06fcf1de80.png)


# 3. おわりに
pydollを使うと、確かにwebdriverを使用せずに高速アクセスできることが確認できました。
このライブラリは今後個人的にも使っていこうと思います。

ただし<font color="Red">**悪用は厳禁**</font>であり、robots.txt等をしっかり調べた上で取得の際も相手に迷惑が掛からないように気を付けてスクレイピングしましょう


https://qiita.com/kuk_a_i_ai/items/31311152723dd210d0b0