Skip to main content

Add your description here

Project description

quickplay

Overview - 概要

quickplay is a scraping utility library built on Playwright and selectolax. quickplayはPlaywrightとselectolaxをベースにしたスクレイピングユーティリティライブラリです。

  • PlayPage — Playwright Page のラッパー。スクレイピング用。
  • SelectParser — selectolax HTMLParser のラッパー。ローカル抽出用。
  • browse() — Playwright(Chromium)起動ランナー。
  • browse_camoufox() — Camoufox(Firefox)起動ランナー。bot検知対策向け。
  • その他ユーティリティ — FromHere, sleep_between, append_csv, write_parquet, hash_name, save_html

Requirements - 必要条件

  • Python 3.12 or higher
  • Libraries: playwright, selectolax, pandas, camoufox(自動インストール)
  • write_parquet を使う場合は pandas の Parquet エンジンとして pyarrow(または fastparquet)が必要です。
  • Browser binaries(別途インストールが必要)

Installation - インストール

pip

pip install quickplay

uv (推奨)

uv add quickplay

ブラウザバイナリを別途インストールしてください。

Playwright(Chromium)

pip

python -m playwright install chromium

uv (推奨)

uv run playwright install chromium

Camoufox(Firefox)

pip

camoufox fetch

uv (推奨)

uv run camoufox fetch

Quick Reference - 主要メソッド一覧

PlayPage のメソッド

  • ss(selector: str) -> list[ElementHandle]
    指定したCSSセレクタにマッチするすべての要素をリストで返します。
    例: links = p.ss('a')

  • s(selector: str) -> ElementHandle | None
    指定したCSSセレクタにマッチする最初の要素を返します。見つからなければ None
    例: title_elem = p.s('h1')

  • text(elem: ElementHandle | None) -> str | None
    要素からテキスト内容を取得します(前後の空白は除去されます)。
    例: title = p.text(p.s('h1'))

  • attr(attr_name: str, elem: ElementHandle | None) -> str | None
    要素の指定された属性値を取得します。
    例: href = p.attr('href', link_elem)

  • url(elem: ElementHandle | None) -> str | None
    リンク要素 (<a>) の href絶対URLに正規化して返します。無効なリンク(javascript: など)は除外されます。
    例: next_url = p.url(p.s('a.next'))

  • goto(url: str | None) -> bool
    指定したURLに移動します。成功すれば True、失敗すれば False を返します。
    例: if p.goto('https://example.com'): ...

SelectParser のメソッド

  • nxt(self, selector: str, node: LexborNode | None) -> LexborNode | None
    ノードから、セレクタに一致する最初の弟ノードを取得します。

  • txt(self, node: LexborNode | None) -> str | None
    ノードからテキスト内容を(子孫ノードまで全て含め)取得します(前後の空白は除去されます)。

ユーティリティ関数

  • sleep_between(a: float, b: float) -> None
    ab 秒の間でランダムに待機します。サーバーに負荷をかけないための基本的なマナーです。
    例: sleep_between(1, 2)

  • append_csv(path: Path | str, row: dict) -> None
    dict 形式のデータを1行としてCSVファイルに追記します。ファイルが存在しない場合はヘッダーも自動で書き込みます。
    例: append_csv('data.csv', {'name': '太郎', 'age': 20})

  • write_parquet(path: Path | str, rows: list[dict]) -> None
    dict のリストを1つの Parquet ファイルに書き出します。
    例: write_parquet('data.parquet', [{'name': '太郎', 'age': 20}])

  • browse(fn: Callable[[Page], None], ...) -> None
    Playwrightのブラウザを起動し、引数で渡した関数を実行します。headlessuser_agent などのオプションを指定できます。
    例: browse(scrape, headless=True, block_resources={'image'})
    引数:

    def browse(
        # scrape(page) のような関数を渡す。
        fn: Callable[[Page], None],
        *,
        # ヘッドレスモードにするか。
        headless: bool = False,
        # ブラウザチャンネル('chrome' など)。
        channel: str = 'chrome',
        # {'width': 1920, 'height': 1080} など。Noneなら未設定。
        viewport: dict | None = {'width': 1920, 'height': 1080},
        # User-Agent文字列。Noneなら未設定。chrome://version/で確認できる。
        user_agent: str | None = None,
        # Accept-Languageヘッダー。Noneなら未設定。
        accept_language: str | None = 'ja-JP,ja;q=0.9',
        # デフォルトタイムアウト(ミリ秒)。
        timeout: int = 15000,
        # ブロックするリソースタイプ。例: {'image'}。
        block_resources: set[str] | None = None,
    ) -> None:
    
  • browse_camoufox(fn: Callable[[Page], None], ...) -> None
    Camoufox(Firefox)でブラウザを起動し、引数で渡した関数を実行します。bot検知が厳しいサイト向け。
    例: browse_camoufox(scrape, humanize=True, block_images=True)
    引数:

    def browse_camoufox(
        # scrape(page) のような関数を渡す。
        fn: Callable[[Page], None],
        *,
        # ヘッドレスモードにするか。
        headless: bool | Literal['virtual'] = False,
        # ブラウザのロケール(言語・地域設定)を指定
        # 英語サイト中心なら `'en-US,en'` への変更を検討
        locale: str | list[str] | None = 'ja-JP,ja',
        # カーソルの動きを人間らしく模倣するかどうか。
        # `True`(デフォルト): デフォルト設定(最大約1.5秒)で有効化。
        # `False`: 無効。カーソルが瞬時に移動する。高速化したい場合やカーソル操作をしないスクレイピングに
        # `float`: カーソル移動の最大秒数を指定して有効化。例: `2.0` なら最大2秒かけて移動。
        humanize: bool | float = True,
        # 画像リソースのリクエストをすべてブロックするかどうか。
        # `False`(デフォルト): 画像を読み込む。
        # `True`: 画像をすべてブロック。
        block_images: bool = False,
        # `False`(デフォルト): COOPを有効のまま。通常はこれでよい。
        # `True`: COOPを無効化。主な用途はCloudflareのTurnstile(チェックボックス認証)の突破。
        # 注意: セキュリティポリシーを緩める設定なので、必要な場合だけ使う。
        disable_coop: bool = False,
        # デフォルトタイムアウト(ミリ秒)。
        timeout: int = 15000,
        **kwargs,
    ) -> None:
    

Basic Usage - 基本的な使い方

from quickplay import *

fh = FromHere(__file__)

def scrape(page):
    p = PlayPage(page)
    p.goto('https://www.foobarbaz1.jp')

    pref_urls = [p.url(e) for e in p.ss('li.item > ul > li > a')]

    classroom_urls = []
    for i, url in enumerate(pref_urls, 1):
        print(f'{i}/{len(pref_urls)} pref_urls')
        if not p.goto(url):
            continue
        sleep_between(1, 2)
        links = [p.url(e) for e in p.ss('.school-area h4 a')]
        classroom_urls.extend(links)

    for i, url in enumerate(classroom_urls, 1):
        print(f'{i}/{len(classroom_urls)} classroom_urls')
        if not p.goto(url):
            continue
        sleep_between(1, 2)
        append_csv(fh('csv/out.csv'), {
            'URL': page.url,
            '教室名': p.text(p.s('h1 .text01')),
            '住所': p.text(p.s('.item .mapText')),
            '電話番号': p.text(p.s('.item .phoneNumber')),
            'HP': p.url(p.s_in('a', p.next(p.s_re('th', 'ホームページ')))),
        })


if __name__ == '__main__':
    browse(
        scrape,
        user_agent='Mozilla/5.0 ...',
        block_resources={'image'},
    )

Save HTML while scraping - スクレイピングしながらHTMLを保存する

from quickplay import *

fh = FromHere(__file__)

def scrape(page):
    p = PlayPage(page)
    p.goto('https://www.foobarbaz1.jp')

    item_urls = [p.url(e) for e in p.ss('ul.items > li > a')]

    for i, url in enumerate(item_urls, 1):
        print(f'{i}/{len(item_urls)} item_urls')
        if not p.goto(url):
            continue
        sleep_between(1, 2)
        if not p.wait('#logo', timeout=10000):
            continue
        file_name = f'{hash_name(url)}.html'
        if not save_html(fh('html') / file_name, page.content()):
            continue
        append_csv(fh('outurlhtml.csv'), {
            'URL': url,
            'HTML': file_name,
        })

if __name__ == '__main__':
    browse(scrape, block_resources={'image'})

Scrape from local HTML files - 保存済みHTMLからスクレイピングしてParquetに出力する

import pandas as pd

from quickplay import *

fh = FromHere(__file__)
p = SelectParser()

df = pd.read_csv(fh('outurlhtml.csv'))
results = []
for i, (url, path) in enumerate(zip(df['URL'], df['HTML']), 1):
    print(i)
    if not p.load(fh('html') / path):
        continue
    results.append({
        'URL': url,
        '教室名': p.txt(p.s('h1 .text02')),
        '住所': p.txt(p.s('.item .mapText')),
        '所在地': p.txt(p.nxt('dd', p.s_re('dt', r'所在地'))),
    })
write_parquet(fh('outhtml.parquet'), results)

License - ライセンス

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quickplay-1.2.7.tar.gz (8.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quickplay-1.2.7-py3-none-any.whl (8.3 kB view details)

Uploaded Python 3

File details

Details for the file quickplay-1.2.7.tar.gz.

File metadata

  • Download URL: quickplay-1.2.7.tar.gz
  • Upload date:
  • Size: 8.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.32.5

File hashes

Hashes for quickplay-1.2.7.tar.gz
Algorithm Hash digest
SHA256 dd34780fd1c91c679c6a224195fa058c8b6c3953e0d374f914cc5fce6013a3b5
MD5 59ae66bf406368cf4da0a05fad30dd2c
BLAKE2b-256 af7abf5e50dac00fb20f9bc21a98572260318bff22ddfeae60846f74118f5fe9

See more details on using hashes here.

File details

Details for the file quickplay-1.2.7-py3-none-any.whl.

File metadata

  • Download URL: quickplay-1.2.7-py3-none-any.whl
  • Upload date:
  • Size: 8.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.32.5

File hashes

Hashes for quickplay-1.2.7-py3-none-any.whl
Algorithm Hash digest
SHA256 9571777cf8eecad6641368489c20b6bda9031a74e15bbe7236c1f36235edfb18
MD5 d274ec290e67399820a8e86527c9372a
BLAKE2b-256 dc3ec7b6891b36db7338fe7c3e213de69e46606e0350cce34d431cca377feca5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page