Pythonの標準ライブラリurllibを用いたGETリクエストのデータ取得方法

1. urllibモジュールの概要

urllibはPythonに標準搭載されているHTTPクライアントパッケージであり、スクリプトからWebサーバーに対してリクエストを送信し、レスポンスを処理する基盤機能を提供します。Python 3環境では、HTTP通信の制御を担うurllib.requestと、URLの解析やエンコードを処理するurllib.parseが主要なサブモジュールとして利用されます。

2. 基礎的なHTMLコンテンツの取得

指定したエンドポイントに対してGETリクエストを実行し、サーバーから返されたHTMLソースを取得する実装例を以下に示します。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from urllib.request import urlopen

def retrieve_web_content(request_url):
    # 指定URLへリクエストを送信し、レスポンスオブジェクトを取得
    server_res = urlopen(request_url)
    # レスポンスボディをバイト列として読み込み
    raw_payload = server_res.read()
    return raw_payload

if __name__ == '__main__':
    target_site = 'https://example.com'
    html_bytes = retrieve_web_content(target_site)
    # バイト列をUTF-8でデコードしてコンソールに出力
    print(html_bytes.decode('utf-8'))

urlopen関数はターゲットURLを受け取り、通信が成功するとレスポンスオブジェクトを返します。取得されたデータはデフォルトでbytes型であるため、文字列として扱う場合は適切なエンコーディングでデコードする処理が必須です。また、レスポンスオブジェクトからはステータスコードやヘッダー情報などのメタデータも参照可能です。

3. レスポンスデータのローカル保存

取得したHTMLデータをファイルとして永続化するには、標準のファイルI/O操作と組み合わせます。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from urllib.request import urlopen

if __name__ == '__main__':
    endpoint = 'https://example.com'
    http_res = urlopen(endpoint)
    
    # バイト列を文字列に変換
    text_content = http_res.read().decode('utf-8')
    
    # コンテキストマネージャを用いてテキストファイルに書き込み
    with open('local_archive.html', 'w', encoding='utf-8') as file_stream:
        file_stream.write(text_content)
        
    print('ローカルファイルへの書き込みが完了しました。')

open関数の書き込みモード('w')を使用し、エンコーディングを明示的に指定することで文字化れを防ぎながらデータをディスクに出力します。

4. バイナリデータ(画像)のダウンロード処理

画像やPDFなどの非テキストデータを取得する場合は、文字コード変換を行わず、そのままのバイト列をバイナリモードで保存します。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from urllib.request import urlopen
import ssl

# 環境によってはHTTPS検証でエラーが出るため、一時的に検証を無効化
ssl._create_default_https_context = ssl._create_unverified_context

if __name__ == '__main__':
    asset_url = 'https://via.placeholder.com/150'
    res_obj = urlopen(asset_url)
    img_bytes = res_obj.read()
    
    # バイナリ書き込みモード('wb')で直接保存
    with open('sample_image.jpg', 'wb') as binary_file:
        binary_file.write(img_bytes)
        
    print('メディアファイルの保存に成功しました。')

バイナリデータに対してdecode()を実行すると例外が発生するため、'wb'モードで直接書き込むことが正しいアプローチとなります。

5. 非ASCII文字列を含むURLのエンコード

URL仕様上、パスやクエリパラメータに日本語や特殊記号を直接含めることはできません。検索ワードなどのパラメータをURLに組み込む際は、パーセントエンコーディングを適用する必要があります。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from urllib.request import urlopen
from urllib.parse import urlencode

if __name__ == '__main__':
    base_endpoint = 'https://example.com/search'
    # 辞書形式でパラメータを定義
    query_data = {
        'keyword': '機械学習入門',
        'category': 'tech'
    }
    
    # パラメータをURLエンコードしてクエリ文字列を生成
    encoded_query = urlencode(query_data)
    complete_url = f'{base_endpoint}?{encoded_query}'
    
    print(f'生成されたリクエストURL: {complete_url}')
    
    api_res = urlopen(complete_url)
    result_data = api_res.read()
    
    with open('search_results.html', 'wb') as out_f:
        out_f.write(result_data)

urllib.parse.urlencodeを使用することで、辞書内のキーと値が自動的にkey=value形式に変換され、非ASCII文字が安全な形式にエンコードされます。

6. カスタムリクエストヘッダーによるアクセス制御回避

多くのWebサービスは、リクエストヘッダーのUser-Agentフィールドを監視し、ボットやスクリプトからのアクセスをフィルタリングします。標準のurlopenのみではヘッダーの変更が困難なため、urllib.request.Requestオブジェクトを明示的に生成してヘッダー情報を上書きします。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from urllib.request import Request, urlopen

if __name__ == '__main__':
    secured_url = 'https://example.com/api/data'
    # 一般的なデスクトップブラウザの識別情報を模倣
    mock_headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
        'Accept-Language': 'ja,en;q=0.9'
    }
    
    # ヘッダー情報を含めたリクエストオブジェクトを生成
    browser_req = Request(url=secured_url, headers=mock_headers)
    
    # カスタムリクエストを実行
    final_res = urlopen(browser_req)
    html_body = final_res.read().decode('utf-8')
    
    print(f'通信ステータス: {final_res.status}')
    # 取得したコンテンツを解析または保存

Requestクラスのインスタンス生成時にheaders引数を渡すことで、任意のHTTPヘッダーをリクエストに埋め込むことが可能です。これにより、サーバー側のUAチェックを通過し、正常なコンテンツの取得が期待できます。

タグ: urllib HTTPリクエスト URLエンコード User-Agent偽装 Webスクレイピング

10月8日 04:32 投稿