PythonでWebページのHTMLを取得する最初の一歩として、requestsは最有力候補です。
インストールが簡単で、短いコードでGETリクエストを送り、ステータスコードやエンコーディングを確認しながら安全に扱えます。
本記事では、初心者でも迷わないように、最短コードからエラー対策までを丁寧に解説します。
requestsの準備
pipでrequestsをインストール
requestsは標準ライブラリではありません。
まずはpipでインストールします。
プロジェクトごとに仮想環境を作るのが理想ですが、ここではシンプルにインストール手順を示します。
可能であればpython -m pip
形式での実行をおすすめします。
Pythonの実体に紐づいたpipが使えるため、バージョンの取り違いを防ぎやすいからです。
# Windowsの場合
py -m venv .venv # 任意(仮想環境を作る場合)
.venv\Scripts\activate # 任意(仮想環境を有効化)
py -m pip install -U requests # requestsをインストール/更新
# macOS / Linuxの場合
python3 -m venv .venv # 任意(仮想環境を作る場合)
source .venv/bin/activate # 任意(仮想環境を有効化)
python3 -m pip install -U requests
インストール時には多くのログが表示されます。
以下は一例です。
Collecting requests
Downloading requests-2.32.3-py3-none-any.whl ...
Collecting charset-normalizer<4,>=2 (from requests)
...
Successfully installed certifi-2024.x.x charset-normalizer-3.x.x idna-3.x requests-2.32.3 urllib3-2.x
importで動作確認
インストール後に必ずimportできるかを確認します。
バージョンも一緒に表示しておくと、環境メモとして便利です。
# importできるか確認し、バージョンと簡単なメッセージを出力します
import requests
print(requests.__version__) # requestsのバージョン確認
print("requests is ready!") # シンプルな動作確認
2.32.3
requests is ready!
requestsでHTMLを取得する方法
最短のGETコード例
まずは最短コードでHTMLを取得してみます。
学習用に安定して応答するhttps://example.com
を使います。
# 最短でHTMLを取得して先頭だけ表示する例
import requests
url = "https://example.com" # 学習用のサンプルサイト
res = requests.get(url) # GETリクエストを送信
# 取得したHTMLの先頭200文字だけ表示(全文は長いので一部に限定)
print(res.text[:200])
<!doctype html>
<html>
<head>
<title>Example Domain</title>
...
ここまでのコードは「成功した場合」を想定しています。
実戦では、後述のステータスコード確認とエラー処理を合わせて書くのが基本です。
ステータスコードを確認
HTTPはステータスコードで成功/失敗や追加の指示を表します。
200番台が成功、300番台はリダイレクト、400番台と500番台はエラーの目安です。
まずは成功の確認を習慣にしましょう。
# ステータスコードと簡易なOK判定を確認します
import requests
url = "https://example.com"
res = requests.get(url)
print("status_code:", res.status_code) # 例: 200
print("ok:", res.ok) # Trueなら成功(200〜399あたりが目安)
print("reason:", res.reason) # 例: OK
status_code: 200
ok: True
reason: OK
参考として、よく見るコードの意味を表にまとめます。
範囲 | 意味の目安 | 例 |
---|---|---|
200–299 | 成功 | 200(OK), 204(No Content) |
300–399 | リダイレクト | 301(Moved Permanently), 302(Found) |
400–499 | クライアントエラー | 400(Bad Request), 404(Not Found) |
500–599 | サーバーエラー | 500(Internal Server Error), 503(Service Unavailable) |
文字化け対策
日本語ページなどでは文字化けが起きることがあります。
requestsはレスポンスヘッダーや内容からエンコーディングを推測しますが、うまくいかない場合はapparent_encoding
を使った補正が有効です。
# エンコーディングを確認・補正してからテキスト化する例
import requests
url = "https://www.example.com" # 実際には日本語サイトで試すと違いが分かりやすいです
res = requests.get(url)
print("encoding(before):", res.encoding) # サーバーから推定されたエンコーディング
# 必要に応じて補正(誤検出の可能性もあるため、条件付きで設定するのがおすすめ)
if not res.encoding or res.encoding.lower() in ("iso-8859-1", "ascii"):
res.encoding = res.apparent_encoding
print("encoding(after):", res.encoding)
print(res.text[:200]) # 補正後のテキストの先頭を確認
encoding(before): ISO-8859-1
encoding(after): utf-8
<!doctype html>...
補足
常にapparent_encoding
が正しいとは限りません。
まずはサーバーが返すContent-Type
ヘッダーのcharset
を尊重し、怪しい場合だけ補正する方針が実務的です。
よく使うオプションと使い方
timeoutを設定する
timeoutは必ず設定しましょう。
未指定だと待ち続ける可能性があります。
接続と読み取りで別々に指定できます。
# 接続(3.05秒)・読み取り(10秒)のタイムアウトを設定する例
import requests
url = "https://httpbin.org/delay/2" # 2秒遅延して返答するテストAPI
try:
res = requests.get(url, timeout=(3.05, 10)) # (connect, read)
print("OK:", res.status_code)
except requests.exceptions.Timeout:
print("Timeout!")
OK: 200
使い分けの目安
- 1つの数値
timeout=10
は接続と読み取りの両方に適用されます。 - タプル
(connect, read)
で分けると、ネットワーク事情に合わせた調整が可能です。
ヘッダー(User-Agent)を付ける
一部サイトはデフォルトのUser-Agentだとブロックすることがあります。
適切なUser-Agentを明示しましょう。
# 一般的なブラウザ風のUser-Agentを付ける例
import requests
url = "https://httpbin.org/headers"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/122.0.0.0 Safari/537.36"
}
res = requests.get(url, headers=headers, timeout=10)
# サーバーが受け取ったヘッダーを確認(学習用API)
print(res.json()["headers"]["User-Agent"])
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
注意
身元を偽る意図でのUser-Agent偽装は避け、アクセス先のポリシーに従ってください。
クエリパラメータ(params)を付ける
検索条件などをURLのクエリとして付与するにはparams
引数が便利です。
辞書を渡すだけでURLに自動で付与されます。
# ?key=value形式のパラメータを付ける例
import requests
url = "https://httpbin.org/get"
params = {
"q": "python requests",
"page": 1
}
res = requests.get(url, params=params, timeout=10)
print("Final URL:", res.url) # エンコード後の最終URLを確認
print("args:", res.json()["args"]) # サーバー側で受け取られたクエリ
Final URL: https://httpbin.org/get?q=python+requests&page=1
args: {'page': '1', 'q': 'python requests'}
リダイレクトを制御
requestsはデフォルトでリダイレクトを自動追従します。
挙動を変えたい場合はallow_redirects
やhistory
を活用します。
# リダイレクトを追う/追わないを比較する例
import requests
url = "https://httpbin.org/redirect/1"
# 追従する(デフォルト)
res1 = requests.get(url, timeout=10)
print("follow: status", res1.status_code)
print("follow: history length", len(res1.history)) # どれだけリダイレクトしたか
# 追従しない
res2 = requests.get(url, allow_redirects=False, timeout=10)
print("no follow: status", res2.status_code)
print("no follow: Location", res2.headers.get("Location")) # 次のURLが分かる
follow: status 200
follow: history length 1
no follow: status 302
no follow: Location https://httpbin.org/get
エラー対策と注意点
HTTPエラーを検出
HTTPエラーはraise_for_status()
で検出するのが定番です。
成功時は何も起きず、4xx/5xx時に例外が送出されます。
# HTTPステータスがエラーのときに例外を起こす例
import requests
url = "https://httpbin.org/status/404" # 404を返すテストURL
res = requests.get(url, timeout=10)
try:
res.raise_for_status() # 4xx/5xxの場合にHTTPErrorを投げる
print("Success:", res.status_code)
except requests.exceptions.HTTPError as e:
print("HTTPError:", e)
HTTPError: 404 Client Error: NOT FOUND for url: https://httpbin.org/status/404
例外をキャッチ
ネットワーク通信ではさまざまな例外が起こり得ます。
基本はRequestException
で包括しつつ、よくあるものは個別に捕捉すると原因切り分けがしやすくなります。
# 例外を適切に捕捉して原因をログに出すテンプレート
import requests
url = "https://httpbin.org/delay/5" # 5秒遅延
try:
res = requests.get(url, timeout=(2, 2)) # あえて短いtimeoutでエラーに
res.raise_for_status() # HTTPエラー検出
print("OK:", res.status_code)
except requests.exceptions.Timeout:
print("Timeout(接続または読み取りが時間切れ)")
except requests.exceptions.ConnectionError:
print("ConnectionError(名前解決/接続が失敗)")
except requests.exceptions.HTTPError as e:
print("HTTPError:", e)
except requests.exceptions.TooManyRedirects:
print("TooManyRedirects(リダイレクトが多すぎ)")
except requests.exceptions.RequestException as e:
# 上記以外のrequests系例外の最終受け皿
print("RequestException:", e)
Timeout(接続または読み取りが時間切れ)
参考として、代表的な例外の概要をまとめます。
例外名 | 起こりやすい状況 |
---|---|
Timeout | サーバーの応答が遅い、timeoutが短すぎる |
ConnectionError | DNS失敗、サーバーダウン、ネットワーク断 |
HTTPError | 4xx/5xxステータスが返ってきた |
TooManyRedirects | 無限リダイレクトや回数制限超過 |
RequestException | requests全般の基底例外(最後に捕捉) |
レスポンス内容を確認
HTMLを扱う前に本当にHTMLなのかを確認すると安全です。
ヘッダーのContent-Type
を見たり、サイズや先頭文字列を確認します。
必要に応じてファイル保存も行います。
# レスポンスの内容タイプとサイズ、先頭を確認し、HTMLなら保存する例
import requests
from pathlib import Path
url = "https://example.com"
res = requests.get(url, timeout=10)
content_type = res.headers.get("Content-Type", "")
print("Content-Type:", content_type)
print("Length(bytes):", len(res.content))
print("Head(100):", res.text[:100].replace("\n", " "))
# HTMLらしければ保存
if "text/html" in content_type.lower():
# エンコーディングを必要に応じて補正
if not res.encoding or res.encoding.lower() in ("iso-8859-1", "ascii"):
res.encoding = res.apparent_encoding
out = Path("page.html")
out.write_text(res.text, encoding=res.encoding or "utf-8")
print(f"Saved to {out.resolve()}")
else:
print("HTMLではない可能性があります。処理を見直してください。")
Content-Type: text/html; charset=UTF-8
Length(bytes): 1256
Head(100): <!doctype html> <html> <head> <title>Example Domain</title> ...
Saved to /your/project/path/page.html
実務での小さなコツ
文字数やサイズが極端に小さいときはエラーページの可能性があります。HTML内のキーワードから異常検知することもあります。
アクセス先の利用規約やrobots.txt、アクセス間隔などのマナーを順守してください。本記事では詳細を扱いませんが、実運用前に必ず確認しましょう。
まとめ
本記事では、requestsでWebページのHTMLを取得する基本を、インストールから最短コード、ステータス確認、文字化け対策、よく使うオプション、そしてエラー処理まで順を追って解説しました。
実務ではtimeoutの設定とraise_for_statusによるエラー検出、そしてエンコーディングの確認が特に重要です。
まずは学習用の安定したURLで動作を確かめ、徐々にヘッダーやパラメータ、リダイレクト制御などを組み合わせて、自身の目的に合う堅牢な取得処理へと育てていきましょう。
次のステップとしては、取得したHTMLから情報を抽出するためのライブラリ(Beautiful Soup)も学ぶと、Webスクレイピングの幅が大きく広がります。