0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pythonからのインターネットアクセスの問題解決

Last updated at Posted at 2025-04-02

対象とする問題

pythonで書いたプログラムでスクレイピングする際に、以下の3つの問題があることが判明したので、ChatGPTに症状などを伝えて相談し、解決方法を見つけた。

  • 使用環境のProxyサーバーがWindowsのユーザーアカウントを用いたWindows統合認証(NTLM)によるユーザー認証を要求するが、requestsモジュールなど通常のpythonのライブラリーがこれに対応していない
  • pythonの標準ライブラリーでは、PAC(Proxy Auto-Config)ファイルに対応していない
  • httpsで始まるURLにアクセスした場合に証明書に関するエラーが出る場合がある

NTLM認証とPACファイルの問題の解決方法

pythonのモジュールpx-proxyによるproxyサーバーを用い、元々のProxyサーバーの手前に入れたいわゆる多段串にすることで解決した。
px-proxyはNTLM認証に対応している。また、私の使用環境では下記の設定ファイルpx.iniの様に、ユーザー名やパスワードを指定しないでも、px-proxyが認証情報を取得してくれた。この辺は環境によるらしい。

[proxy]
server = 
pac = http://hogehoge.com/proxy.pac
pac_encoding = utf-8
port = 3128
listen = 127.0.0.1
gateway = 0
hostonly = 0
allow = 127.0.0.1
noproxy = 
useragent = 
username = 
auth = 

[client]

[settings]
workers = 2
threads = 32
idle = 30
socktimeout = 20.0
proxyreload = 60
foreground = 0
log = 0

私の使用環境では、proxyサーバーを自動設定する様になっていたので、pac =の行に設定している。proxyサーバーのアドレスを指定する場合には、server = の行に書けば良いと思われる。

px-proxyのインストール

単純に以下で良い。

pip install px-proxy

px-proxyによるproxyサーバーの起動

設定ファイルpx.iniを適当なディレクトリーに起き、以下を実行する

python -m px -c hogehogedir/px.ini

python製プログラムでの対応

環境変数HTTP_PROXYHTTPS_PROXYpx.inilistenに指定したIPアドレスとportに指定したポート番号を設定すれば良い。
px-proxyによるProxyサーバーが起動しているかも確認するならば、以下の様な関数を用意すると良い。

import socket
def set_proxy(port=3128, force_set_env = True):
    try:
        with socket.create_connection(("127.0.0.1", port), timeout=2) as sock:
            print(f"[OK] px proxy はポート {port} で起動しています。")
    except (socket.timeout, ConnectionRefusedError):
        raise RuntimeError(
            f"px proxy が 127.0.0.1:{port} で起動していません。\n"
            f"px を起動してください(例: python -m px または px.exe)"
        )
    except Exception as e:
        raise RuntimeError(f"px proxy チェック中に予期しないエラーが発生しました: {e}")

    for x in ["HTTP_PROXY", "HTTPS_PROXY"]:
        if force_set_env or (x not in os.environ):
            os.environ[x] = f'http://127.0.0.1:{port}'
    if True:
        for x in ["HTTP_PROXY", "HTTPS_PROXY"]:
            print(x, os.environ[x])

証明書に関する問題の解決方法

原因

httpsで始まるURLにブラウザからはアクセス出来るのに、python製プログラムからではアクセス時にエラーや警告が出るのは、使用している「信頼済みCAのリスト(証明書ストア)」が異なるからだそうです。
Windows上ではブラウザは、Windowsの証明書ストアを使うのに対し、pythonの標準的なライブラリー(requests, ssl, urllib3 など)は、certifi というPython向けの独立したCA証明書バンドルを使用するそうです。
certifiはMozillaベースですが、更新タイミングが異なるため、最新CAが含まれていない場合があるそうで、この場合に問題が発生します。

解決方法

要はpython製プログラムにおいてもWindowsの証明書ストアを用いれば良いです。その方法はいくつかありますが、一番簡単なのはpythonのpip-system-certsを使う方法です。

注意点

このモジュールをインストールしただけで、pipコマンドが使う証明書ストアもWindowsの証明書ストアを使う様に変更されます。

pip-system-certsのインストール

単純に以下

pip install pip-system-certs

python製プログラムでの対応

下記例の様にrequestsモジュールなどより前にimportするだけです。

import pip_system_certs
import requests
0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?