Python Webスクレイピング 2025 第1部:Playwright入門と環境構築

約45分で読めます by ぽんたぬき
Python Webスクレイピング 2025 第1部:Playwright入門と環境構築

はじめに

2025年のPythonを使ったWebスクレイピングは、従来の手法から大きく進歩しています。JavaScript重要度の高い動的サイトの増加、パフォーマンス要求の高まり、そして法的・倫理的配慮の重要性が増す中、新しいツールと手法が必要となっています。

本シリーズでは、2025年の最新トレンドに基づいた包括的なWebスクレイピングガイドをお届けします。第1部では、Playwrightによる最先端の動的サイト対応と基本的な環境構築について、コードの詳細解説とともに説明します。

🚀 2025年のスクレイピング技術トレンド

従来の課題と新しいソリューション

従来の問題点

  • Seleniumの重い動作:ブラウザ起動に時間がかかり、メモリ使用量が多い
  • JavaScriptレンダリングサイトへの対応不足:動的コンテンツが正しく取得できない
  • 同期処理による低いスループット:一度に1つのページしか処理できない
  • 検出回避技術の複雑さ:bot検出を回避するための設定が煩雑

2025年の解決策

  • Playwright:軽量高速なブラウザ自動化ツール
  • 非同期処理(asyncio):複数のページを同時に処理可能
  • スマートな要素待機:要素が表示されるまで自動的に待機
  • 統合型ソリューション:Scrapy-Playwrightなどの高レベルフレームワーク

なぜPlaywrightなのか?

2024年から2025年にかけて、Playwrightは1日あたり2万回以上のダウンロードを記録し、Seleniumに代わる新しいスタンダードとして急速に普及しています。

Playwrightの主な利点

  • マルチブラウザサポート:Chrome、Firefox、Safari相当のWebKit対応
  • 自動待機機能:要素が操作可能になるまで自動的に待機(flakiness削減)
  • 高速実行:Seleniumと比較して2-3倍高速
  • モダンAPI:async/await対応の現代的な設計
  • 企業サポート:Microsoftによる開発とメンテナンス

🛠️ 環境構築(2025年版)

最新Python環境の準備

# Python環境管理(推奨)
# pyenvとPoetryの組み合わせを使用する理由:
# - pyenv: 複数のPythonバージョンを管理
# - Poetry: 依存関係とパッケージ管理を効率化

# pyenvのインストール(Pythonバージョン管理)
curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash

# Poetryのインストール(パッケージ管理)
curl -sSL https://install.python-poetry.org | python3 -

# Python 3.11以上を推奨(型ヒントとパフォーマンス改善のため)
pyenv install 3.11.7
pyenv global 3.11.7

# プロジェクト初期化
# pyproject.tomlファイルが作成され、依存関係が管理される
poetry init

# 必要なパッケージのインストール
# playwright: ブラウザ自動化
# aiohttp: 非同期HTTP通信
# beautifulsoup4: HTML解析
# pandas: データ操作
poetry add playwright aiohttp asyncio beautifulsoup4 pandas

# フレームワーク使用時(オプション)
# scrapy: 大規模スクレイピングフレームワーク
# scrapy-playwright: ScrapyとPlaywrightの統合
poetry add scrapy scrapy-playwright

# Playwrightブラウザのインストール
# 実際のブラウザバイナリをダウンロード
poetry run playwright install

基本的なインポートと設定の詳細解説

# 2025年標準構成 - 各インポートの役割を解説

# 非同期処理の核となるライブラリ
import asyncio  # 非同期プログラミングのためのライブラリ

# HTTP通信用(非同期対応)
import aiohttp  # 高速な非同期HTTP通信ライブラリ

# Playwright関連
from playwright.async_api import async_playwright  # 非同期版のPlaywright API

# HTML解析
from bs4 import BeautifulSoup  # HTMLパーサー(要素の抽出に使用)

# データ処理
import pandas as pd  # データフレーム操作(CSV出力、統計処理等)
import json         # JSON形式のデータ処理
import time         # 時間関連の処理(遅延、計測等)

# 日時処理
from datetime import datetime, timedelta  # 日付・時刻の操作

# 型ヒント(コードの可読性と安全性向上)
from typing import List, Dict, Optional, Union

# ログ出力
import logging      # エラーログや処理状況の記録

# データクラス(構造化データの定義)
from dataclasses import dataclass, field

# ファイルパス操作
from pathlib import Path  # モダンなファイル操作

# ログ設定の詳細解説
logging.basicConfig(
    level=logging.INFO,  # INFO以上のレベルを出力
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    # フォーマット: 時刻 - ロガー名 - レベル - メッセージ
)
logger = logging.getLogger(__name__)  # モジュール固有のロガーを作成

🎯 Playwright入門:動的サイト対応の決定版

設定クラスの詳細解説

@dataclass
class ScrapingConfig:
    """
    スクレイピング設定クラス
    
    @dataclassデコレータを使用する理由:
    - 自動的に__init__, __repr__, __eq__メソッドを生成
    - 型ヒント対応
    - デフォルト値の簡潔な記述
    """
    headless: bool = True  # ブラウザをヘッドレスモードで実行(画面表示なし)
    timeout: int = 30000   # タイムアウト時間(ミリ秒)
    user_agent: str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"  # User-Agent設定
    # viewportのデフォルト値をfactory関数で設定(辞書の参照問題を回避)
    viewport: Dict[str, int] = field(default_factory=lambda: {"width": 1920, "height": 1080})
    proxy: Optional[Dict[str, str]] = None  # プロキシ設定(任意)

メインスクレイピングクラスの詳細解説

class ModernWebScraper:
    """
    2025年版Webスクレイピングクラス
    
    非同期コンテキストマネージャーとして実装する理由:
    - リソースの確実な開放
    - with文による直感的な使用
    - 例外処理時の安全なクリーンアップ
    """
    
    def __init__(self, config: ScrapingConfig = None):
        """
        初期化メソッド
        
        Args:
            config: スクレイピング設定(Noneの場合デフォルト設定を使用)
        """
        self.config = config or ScrapingConfig()  # 設定が渡されなければデフォルトを使用
        self.browser = None      # ブラウザインスタンス
        self.context = None      # ブラウザコンテキスト(タブ群の管理)
        self.session_data = {}   # セッションデータ(Cookie等の保存)
    
    async def __aenter__(self):
        """
        非同期コンテキストマネージャー開始
        
        async with文で呼び出される際に実行される
        ブラウザの起動とコンテキストの作成を行う
        """
        # Playwrightインスタンスを起動
        self.playwright = await async_playwright().start()
        
        # ブラウザ起動(Chromiumを使用)
        # headless=Trueで非表示モード、Falseで画面表示
        self.browser = await self.playwright.chromium.launch(
            headless=self.config.headless,
            proxy=self.config.proxy  # プロキシ設定があれば適用
        )
        
        # ブラウザコンテキスト作成
        # コンテキスト = 独立したブラウザセッション(Cookie、ローカルストレージ等を管理)
        self.context = await self.browser.new_context(
            user_agent=self.config.user_agent,  # User-Agent設定
            viewport=self.config.viewport        # 画面解像度設定
        )
        
        # デフォルトタイムアウト設定(すべての操作に適用)
        self.context.set_default_timeout(self.config.timeout)
        
        logger.info("Playwright scraper initialized")
        return self  # selfを返すことでwith文の変数に代入される
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """
        非同期コンテキストマネージャー終了
        
        with文を抜ける際に自動実行される
        リソースの適切な解放を行う
        
        Args:
            exc_type: 例外の型
            exc_val: 例外の値
            exc_tb: トレースバック
        """
        # 順番に終了処理を実行(重要:逆順で閉じる)
        if self.context:
            await self.context.close()  # コンテキスト終了
        if self.browser:
            await self.browser.close()  # ブラウザ終了
        if self.playwright:
            await self.playwright.stop()  # Playwright終了
        logger.info("Playwright scraper closed")
    
    async def scrape_page(self, url: str, wait_selector: str = None) -> Dict:
        """
        単一ページのスクレイピング
        
        Args:
            url: スクレイピング対象のURL
            wait_selector: 待機対象のCSSセレクター(動的コンテンツ対応)
            
        Returns:
            スクレイピング結果の辞書
        """
        # 新しいページ(タブ)を作成
        page = await self.context.new_page()
        
        try:
            # ページ読み込み開始
            logger.info(f"Loading page: {url}")
            
            # wait_until="domcontentloaded"の説明:
            # - "load": すべてのリソース(画像等)の読み込み完了まで待機
            # - "domcontentloaded": HTMLの解析完了まで待機(推奨)
            # - "networkidle": ネットワーク通信が停止するまで待機
            await page.goto(url, wait_until="domcontentloaded")
            
            # 動的コンテンツの読み込み待機
            if wait_selector:
                # 指定されたCSSセレクターの要素が表示されるまで待機
                # JavaScript実行後に表示される要素に対応
                await page.wait_for_selector(wait_selector, timeout=10000)
            
            # ページの基本情報を取得
            title = await page.title()           # <title>タグの内容
            html_content = await page.content()  # ページのHTML全体
            
            # JavaScriptの実行結果を取得
            # page.evaluate()でブラウザ内でJavaScriptコードを実行
            js_data = await page.evaluate("""
                () => {
                    // ブラウザ内で実行されるJavaScriptコード
                    return {
                        url: window.location.href,        // 現在のURL
                        userAgent: navigator.userAgent,   // User-Agent
                        timestamp: Date.now(),             // タイムスタンプ
                        viewport: {
                            width: window.innerWidth,      // ビューポート幅
                            height: window.innerHeight     // ビューポート高さ
                        }
                    }
                }
            """)
            
            # 成功時の戻り値
            return {
                'url': url,
                'title': title,
                'html_content': html_content,
                'js_data': js_data,
                'timestamp': datetime.now(),
                'status': 'success'
            }
            
        except Exception as e:
            # エラー時のログ出力と戻り値
            logger.error(f"Error scraping {url}: {e}")
            return {
                'url': url,
                'error': str(e),
                'timestamp': datetime.now(),
                'status': 'error'
            }
        finally:
            # 必ずページを閉じる(メモリリーク防止)
            await page.close()

実際の使用例:基本的なWebページスクレイピング

# 使用例の詳細解説
async def demo_basic_scraping():
    """
    基本的なスクレイピングのデモ
    
    この関数はasyncで定義されている理由:
    - Playwrightが非同期APIを使用
    - 複数のページを効率的に処理可能
    - ブロッキング処理を回避
    """
    
    # 設定オブジェクトの作成
    config = ScrapingConfig(
        headless=False,  # デバッグ時はブラウザを表示
        timeout=20000    # 20秒のタイムアウト
    )
    
    # 非同期コンテキストマネージャーの使用
    # with文により、自動的にリソースが解放される
    async with ModernWebScraper(config) as scraper:
        # テストサイトの配列
        # httpbin.orgは開発者向けHTTPテストサービス
        test_urls = [
            "https://httpbin.org/html",  # HTML形式のレスポンス
            "https://httpbin.org/json",  # JSON形式のレスポンス
            "https://httpbin.org/xml"    # XML形式のレスポンス
        ]
        
        results = []  # 結果を格納するリスト
        
        # 各URLを順次処理
        for url in test_urls:
            print(f"スクレイピング中: {url}")
            
            # ページをスクレイピング
            result = await scraper.scrape_page(url)
            
            # 結果の判定と処理
            if result['status'] == 'success':
                print(f"✅ 成功: {result['title']}")
                results.append(result)
            else:
                print(f"❌ エラー: {result['error']}")
            
            # 適切な間隔を空ける(サーバー負荷軽減)
            # asyncio.sleep()は非ブロッキング待機
            await asyncio.sleep(1)
        
        return results

# 実行方法の解説
# Jupyter Notebookの場合:
# results = await demo_basic_scraping()

# 通常のPythonスクリプトの場合:
# import asyncio
# results = asyncio.run(demo_basic_scraping())

🔧 基本的なデータ抽出テクニック

BeautifulSoupとの組み合わせ(詳細解説版)

class BasicDataExtractor:
    """
    基本的なデータ抽出クラス
    
    BeautifulSoupを使用してHTML要素を抽出する
    正規表現パターンも事前定義して効率化
    """
    
    def __init__(self):
        """
        初期化メソッド
        よく使用される正規表現パターンを事前定義
        """
        self.extraction_patterns = {
            # メールアドレス抽出用の正規表現
            'email': r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
            # 電話番号抽出用(日本・米国形式対応)
            'phone': r'(\+?\d{1,3}[-.]?)?\(?\d{3}\)?[-.]?\d{3}[-.]?\d{4}',
            # 価格抽出用(通貨記号対応)
            'price': r'[¥$€£]\s*[\d,]+\.?\d*|[\d,]+\.?\d*\s*[¥$€£]',
            # 日付抽出用(複数形式対応)
            'date': r'\d{4}[-/]\d{1,2}[-/]\d{1,2}|\d{1,2}[-/]\d{1,2}[-/]\d{4}',
            # URL抽出用
            'url': r'https?://(?:[-\w.])+(?:[:\d]+)?(?:/(?:[\w/_.])*(?:\?(?:[\w&=%.])*)?(?:#(?:[\w.])*)?)?'
        }
    
    def extract_basic_info(self, html_content: str) -> Dict:
        """
        基本情報の抽出(包括的な情報取得)
        
        Args:
            html_content: HTML文字列
            
        Returns:
            抽出された情報の辞書
        """
        # BeautifulSoupでHTMLを解析
        # 'html.parser'は標準ライブラリのパーサー(追加インストール不要)
        soup = BeautifulSoup(html_content, 'html.parser')
        
        return {
            'title': self.get_title(soup),           # ページタイトル
            'headings': self.get_headings(soup),     # 見出し一覧
            'links': self.get_links(soup),           # リンク一覧
            'images': self.get_images(soup),         # 画像一覧
            'meta_data': self.get_meta_data(soup)    # メタデータ
        }
    
    def get_title(self, soup: BeautifulSoup) -> str:
        """
        タイトル取得(フォールバック機能付き)
        
        Args:
            soup: BeautifulSoupオブジェクト
            
        Returns:
            ページタイトル
        """
        # まず<title>タグを探す
        title_tag = soup.find('title')
        if title_tag:
            return title_tag.get_text(strip=True)  # strip=Trueで前後の空白を除去
        
        # <title>がない場合は<h1>タグをフォールバック
        h1_tag = soup.find('h1')
        return h1_tag.get_text(strip=True) if h1_tag else None
    
    def get_headings(self, soup: BeautifulSoup) -> List[Dict]:
        """
        見出し取得(階層情報付き)
        
        Args:
            soup: BeautifulSoupオブジェクト
            
        Returns:
            見出し情報のリスト
        """
        headings = []
        
        # h1からh6まですべての見出しを取得
        for level in range(1, 7):  # h1-h6
            # find_all()で該当するすべての要素を取得
            for heading in soup.find_all(f'h{level}'):
                headings.append({
                    'level': level,                         # 見出しレベル
                    'text': heading.get_text(strip=True),   # テキスト内容
                    'id': heading.get('id'),                # id属性
                    'class': heading.get('class')           # class属性(リスト形式)
                })
        
        return headings
    
    def get_links(self, soup: BeautifulSoup) -> List[Dict]:
        """
        リンク取得(属性情報も含む)
        
        Args:
            soup: BeautifulSoupオブジェクト
            
        Returns:
            リンク情報のリスト
        """
        links = []
        
        # href属性を持つ<a>タグをすべて取得
        # href=Trueで「href属性が存在する」条件を指定
        for link in soup.find_all('a', href=True):
            links.append({
                'url': link['href'],                     # リンクURL
                'text': link.get_text(strip=True),       # リンクテキスト
                'title': link.get('title'),              # title属性
                'target': link.get('target')             # target属性(_blank等)
            })
        
        return links
    
    def get_images(self, soup: BeautifulSoup) -> List[Dict]:
        """
        画像取得(属性情報も含む)
        
        Args:
            soup: BeautifulSoupオブジェクト
            
        Returns:
            画像情報のリスト
        """
        images = []
        
        # src属性を持つ<img>タグをすべて取得
        for img in soup.find_all('img', src=True):
            images.append({
                'src': img['src'],              # 画像URL
                'alt': img.get('alt'),          # alt属性(代替テキスト)
                'title': img.get('title'),      # title属性
                'width': img.get('width'),      # width属性
                'height': img.get('height')     # height属性
            })
        
        return images
    
    def get_meta_data(self, soup: BeautifulSoup) -> Dict:
        """
        メタデータ取得(SEO情報等)
        
        Args:
            soup: BeautifulSoupオブジェクト
            
        Returns:
            メタデータの辞書
        """
        meta_data = {}
        
        # すべての<meta>タグを処理
        for meta in soup.find_all('meta'):
            # name属性またはproperty属性を取得
            # name: 一般的なメタタグ(description, keywords等)
            # property: Open Graphメタタグ(og:title等)
            name = meta.get('name') or meta.get('property')
            content = meta.get('content')
            
            # 両方の属性が存在する場合のみ辞書に追加
            if name and content:
                meta_data[name] = content
        
        return meta_data
    
    def extract_with_regex(self, text: str, pattern_name: str) -> List[str]:
        """
        正規表現による抽出
        
        Args:
            text: 検索対象のテキスト
            pattern_name: パターン名(self.extraction_patternsのキー)
            
        Returns:
            マッチした文字列のリスト
        """
        import re
        
        # 事前定義されたパターンが存在するかチェック
        if pattern_name in self.extraction_patterns:
            pattern = self.extraction_patterns[pattern_name]
            # re.findall()で全てのマッチを取得
            return re.findall(pattern, text)
        
        # パターンが存在しない場合は空のリストを返す
        return []

# 使用例の詳細解説
async def demo_data_extraction():
    """
    データ抽出のデモ
    実際のHTMLからの情報抽出を体験
    """
    
    # サンプルHTMLの作成
    # 実際のWebページの構造を模倣
    sample_html = """
    <html>
        <head>
            <!-- ページのメタ情報 -->
            <title>サンプルページ</title>
            <meta name="description" content="これはテストページです">
            <meta property="og:title" content="OGタイトル">
        </head>
        <body>
            <!-- 見出し階層 -->
            <h1>メインタイトル</h1>
            <h2>サブタイトル</h2>
            
            <!-- コンテンツ(抽出対象の情報を含む) -->
            <p>お問い合わせ: contact@example.com</p>
            <p>電話: 03-1234-5678</p>
            
            <!-- リンク -->
            <a href="https://example.com" title="外部リンク">リンク</a>
            
            <!-- 画像 -->
            <img src="image.jpg" alt="サンプル画像">
        </body>
    </html>
    """
    
    # データ抽出器のインスタンス作成
    extractor = BasicDataExtractor()
    
    # 基本情報の抽出実行
    basic_info = extractor.extract_basic_info(sample_html)
    
    # 結果の表示
    print("=== 抽出結果 ===")
    print(f"タイトル: {basic_info['title']}")
    print(f"見出し数: {len(basic_info['headings'])}")
    print(f"リンク数: {len(basic_info['links'])}")
    print(f"画像数: {len(basic_info['images'])}")
    print(f"メタデータ: {basic_info['meta_data']}")
    
    # 正規表現による詳細抽出
    all_text = sample_html
    emails = extractor.extract_with_regex(all_text, 'email')
    phones = extractor.extract_with_regex(all_text, 'phone')
    
    print(f"\n=== 正規表現抽出結果 ===")
    print(f"メールアドレス: {emails}")
    print(f"電話番号: {phones}")
    
    return basic_info

# 実行例
# extraction_result = await demo_data_extraction()

🛡️ 基本的なセキュリティ考慮事項

User-Agent管理とリクエスト制限(詳細解説版)

class ResponsibleScraper(ModernWebScraper):
    """
    責任あるスクレイピングクラス
    
    継承を使用してModernWebScraperを拡張
    マナーを守ったスクレイピングを実現
    """
    
    def __init__(self, config: ScrapingConfig = None):
        """
        初期化メソッド
        
        親クラスの初期化に加えて、
        リクエスト管理用の属性を追加
        """
        super().__init__(config)  # 親クラスの初期化を実行
        
        self.request_history = []        # リクエスト履歴を記録
        self.min_delay = 1.0            # 最小遅延時間(秒)
        self.last_request_time = {}     # ドメイン別の最終リクエスト時刻
    
    async def polite_scrape(self, url: str, custom_delay: float = None) -> Dict:
        """
        マナーを守ったスクレイピング
        
        ドメインごとに適切な間隔を空けてリクエストを送信
        サーバー負荷軽減とアクセス制限回避を両立
        
        Args:
            url: スクレイピング対象のURL
            custom_delay: カスタム遅延時間(指定がなければデフォルト使用)
            
        Returns:
            スクレイピング結果の辞書
        """
        from urllib.parse import urlparse
        
        # URLからドメイン名を抽出
        # 例: "https://example.com/page" → "example.com"
        domain = urlparse(url).netloc
        current_time = time.time()
        
        # ドメインごとの遅延管理
        if domain in self.last_request_time:
            # 前回のリクエストからの経過時間を計算
            elapsed = current_time - self.last_request_time[domain]
            
            # 使用する遅延時間を決定
            delay = custom_delay or self.min_delay
            
            # まだ十分な時間が経過していない場合は待機
            if elapsed < delay:
                wait_time = delay - elapsed
                logger.info(f"Waiting {wait_time:.1f}s for {domain}")
                
                # 非ブロッキング待機(他の処理を妨げない)
                await asyncio.sleep(wait_time)
        
        # 実際のリクエスト実行
        result = await self.scrape_page(url)
        
        # 履歴の更新
        self.last_request_time[domain] = time.time()  # 最終リクエスト時刻を更新
        self.request_history.append({
            'url': url,
            'timestamp': datetime.now(),
            'status': result['status']
        })
        
        return result
    
    def get_request_stats(self) -> Dict:
        """
        リクエスト統計取得
        
        スクレイピングの実行状況を分析
        成功率やドメイン分布を把握
        
        Returns:
            統計情報の辞書
        """
        if not self.request_history:
            return {}
        
        total_requests = len(self.request_history)
        
        # 成功・失敗の集計
        successful = sum(1 for req in self.request_history if req['status'] == 'success')
        failed = total_requests - successful
        
        # ドメイン別統計の計算
        domain_counts = {}
        for req in self.request_history:
            from urllib.parse import urlparse
            domain = urlparse(req['url']).netloc
            
            # 辞書のget()メソッドで安全にカウント
            domain_counts[domain] = domain_counts.get(domain, 0) + 1
        
        return {
            'total_requests': total_requests,
            'successful': successful,
            'failed': failed,
            'success_rate': successful / total_requests * 100,  # 成功率(%)
            'domain_distribution': domain_counts
        }

# 使用例の詳細解説
async def demo_responsible_scraping():
    """
    責任あるスクレイピングのデモ
    
    適切な間隔を空けながら複数のページを処理
    統計情報の取得方法も示す
    """
    
    # 設定作成(ヘッドレスモードで高速実行)
    config = ScrapingConfig(headless=True)
    
    # 責任あるスクレイパーを使用
    async with ResponsibleScraper(config) as scraper:
        # テスト用URL配列
        test_urls = [
            "https://httpbin.org/delay/1",  # 1秒の遅延付きレスポンス
            "https://httpbin.org/html",     # HTML形式のレスポンス
            "https://httpbin.org/json"      # JSON形式のレスポンス
        ]
        
        results = []
        
        # 各URLを適切な間隔で処理
        for url in test_urls:
            print(f"Polite scraping: {url}")
            
            # カスタム遅延(2秒)を指定してスクレイピング
            result = await scraper.polite_scrape(url, custom_delay=2.0)
            results.append(result)
        
        # 統計情報の取得と表示
        stats = scraper.get_request_stats()
        print(f"\n=== リクエスト統計 ===")
        print(f"総リクエスト数: {stats['total_requests']}")
        print(f"成功率: {stats['success_rate']:.1f}%")
        print(f"ドメイン分布: {stats['domain_distribution']}")
        
        return results, stats

# 実行例
# responsible_results = await demo_responsible_scraping()

📋 第1部のまとめ

学習した内容(コード理解を含む)

  1. 2025年のトレンド理解: Playwrightの重要性と従来手法からの進化

    • 非同期処理によるパフォーマンス向上
    • 動的サイト対応の重要性
  2. 環境構築: Poetry + pyenvによるモダンなPython環境

    • 依存関係管理の最適化
    • 型ヒントの活用
  3. Playwright基礎: 非同期コンテキストマネージャーと基本操作

    • async/await構文の実践的な使用法
    • リソース管理の重要性
  4. データ抽出基礎: BeautifulSoupとの組み合わせ

    • HTMLパースの効率的な方法
    • 正規表現との連携
  5. 責任あるスクレイピング: 適切な遅延とリクエスト管理

    • サーバー負荷軽減の実装
    • 統計情報による品質管理

重要なポイント(実装観点)

  • 非同期処理の活用async/awaitによる効率的な処理
  • エラーハンドリング:try-except-finallyによる堅牢な実装
  • リソース管理:コンテキストマネージャーによる確実な解放
  • 設定の分離:@dataclassによる保守性の向上

第2部では、以下の高度なテクニックについて解説します:


免責事項: 本記事の内容は教育目的のものです。実際のスクレイピング実行時は、対象サイトの利用規約を遵守し、適切な許可を得てから実施してください。

関連記事

Streamlit入門 第3部:ポートフォリオ管理とアラート機能で完全な投資ツールを構築
Python

Streamlit入門 第3部:ポートフォリオ管理とアラート機能で完全な投資ツールを構築

これまでの記事で価格表示とチャート分析ができるようになりました。今回は最終回として、自分の保有している仮想通貨を管理するポートフォリオ機能と、価格変動を知らせるアラート機能を追加します。これで本格的な投資管理ツールの完成です! ポートフォリオ管理とは?なぜ重要なのか ...

Streamlit入門 第2部:美しいチャートと可視化で仮想通貨を分析しよう
Python

Streamlit入門 第2部:美しいチャートと可視化で仮想通貨を分析しよう

前回の記事で基本的な価格表示ができるようになりました。今回は、プロのトレーダーが使うような美しいチャートを追加して、本格的な分析ツールに仕上げていきます。難しそうに見えますが、実は数行のコードで驚くほど高機能なチャートが作れるんです! Plotlyとは?なぜグラフライブラリの中で最強なのか ...

Python Webスクレイピング 2025 第3部:実践プロジェクトとデータ管理
Python

Python Webスクレイピング 2025 第3部:実践プロジェクトとデータ管理

はじめに シリーズ最終回となる第3部では、実際のプロジェクトで使える実践的なスクレイピングシステムの構築について解説します。検出回避技術、データの永続化、監視システムの構築など、プロダクション環境で必要となる高度な技術を学びます。 また、法的・倫理的配慮についても詳しく説明し、責任あるスクレイピング...

コメント

0/2000