LoginSignup
0
0

More than 1 year has passed since last update.

Python Win32 APIでHTTP通信

Last updated at Posted at 2021-06-13

Python Win32 APIでウインドウを前面に出す
Python Win32 APIでウインドウメッセージ

Win32 APIを使ってHTTP通信をやってみます。WinINetというライブラリを使います。

from ctypes import *

InternetOpen = windll.wininet.InternetOpenW
InternetConnect = windll.wininet.InternetConnectW
HttpOpenRequest = windll.wininet.HttpOpenRequestW
HttpSendRequest = windll.wininet.HttpSendRequestW
InternetReadFile = windll.wininet.InternetReadFile
InternetCloseHandle = windll.wininet.InternetCloseHandle
GetLastError = windll.kernel32.GetLastError

ドキュメント(InternetOpenW)を見ると、下の方にDLL Wininet.dllと書かれています。
library.png

これより、モジュールのパスは(user32ではなく)windll.wininetになります。

INTERNET_OPEN_TYPE_PRECONFIG = 0

lpszAgent = "test" # ユーザーエージェント(適当)
hInet = InternetOpen(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, None, None, 0)
if hInet == 0:
    raise Exception

INTERNET_OPEN_TYPE_PRECONFIG - レジストリから何か設定を読み込むみたいです。

詳しい意味や他のパラメータなど、ドキュメントにすべて書かれています。ただ、どれにすればいいかは試行錯誤です。また、InternetOpenAなど~Aでは通らなかったので、すべて~Wにしています。
(C言語では~Aでも通るのに)

InternetOpenとInternetConnectで初期化、これは最初に一度だけやればよいです。
HttpOpenRequest,HttpSendRequestで送信して、InternetReadFileで応答を(バイト配列で)受信します。

import sys
from ctypes import *

InternetOpen = windll.wininet.InternetOpenW
InternetConnect = windll.wininet.InternetConnectW
InternetCloseHandle = windll.wininet.InternetCloseHandle
HttpOpenRequest = windll.wininet.HttpOpenRequestW
HttpSendRequest = windll.wininet.HttpSendRequestW
InternetReadFile = windll.wininet.InternetReadFile
GetLastError = windll.kernel32.GetLastError

INTERNET_OPEN_TYPE_PRECONFIG = 0
INTERNET_SERVICE_HTTP = 3
INTERNET_DEFAULT_HTTP_PORT = 80

try:
    lpszAgent = "test"
    hInet = InternetOpen(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, None, None, 0)
    if hInet == 0:
        raise Exception

    lpszServerName = "docs.microsoft.com"
    hConnect = InternetConnect(hInet, lpszServerName, INTERNET_DEFAULT_HTTP_PORT, None, None, INTERNET_SERVICE_HTTP, 0, None)
    if hConnect == 0:
        raise Exception

    lpszObjectName = "en-us/windows/win32/api/wininet/nf-wininet-internetopenw"
    hRequest = HttpOpenRequest(hConnect, "GET", lpszObjectName, None, None, None, 0, None)
    if hRequest == 0:
        raise Exception

    lpszHeaders = "Content-Type: application/x-www-form-urlencoded"
    ret = HttpSendRequest(hRequest, lpszHeaders, -1, None, 0)
    if ret == 0:
        raise Exception

    dwRead = c_long(1)
    while dwRead.value > 0:
        lpBuffer = create_string_buffer(1024)
        ret = InternetReadFile(hRequest, lpBuffer, 1024, pointer(dwRead))
        if ret == 0:
            raise Exception
        sys.stdout.buffer.write(lpBuffer.value) # 応答を出力

except Exception as e:
    print(GetLastError())
    raise e

finally:
    if hRequest != 0:
        InternetCloseHandle(hRequest)
    if hConnect != 0:
        InternetCloseHandle(hConnect)
    if hInet != 0:
        InternetCloseHandle(hInet)

実行結果

<!DOCTYPE html>
...(略)...
    <div id="action-panel" role="region" aria-label="Action Panel" class="action-panel has-default-focus" tabindex="-1"></div>
</body>
</html>

参考までに、対応するC言語のソース
gcc .\wininet_test.c -lWininet
(Mingw-w64で確認)

wininet_test.c
#include <windows.h>
#include <wininet.h>
#include <stdio.h>

int main(void)
{
    char *lpszAgent = "test";
    HINTERNET hInet = InternetOpenA(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (hInet == NULL)
    {
        printf("InternetOpenA error %d\n", GetLastError());
        goto finally;
    }

    char *lpszServerName = "docs.microsoft.com";
    HINTERNET hConnect = InternetConnectA(hInet, lpszServerName, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)NULL);
    if (hConnect == NULL)
    {
        printf("InternetConnectA error %d\n", GetLastError());
        goto finally;
    }

    char *lpszObjectName = "en-us/windows/win32/api/wininet/nf-wininet-internetopenw";
    HINTERNET hRequest = HttpOpenRequestA(hConnect, "GET", lpszObjectName, NULL, NULL, NULL, 0, (DWORD_PTR)NULL);
    if (hRequest == NULL)
    {
        printf("HttpOpenRequestA error %d\n", GetLastError());
        goto finally;
    }

    char *lpszHeaders = "Content-Type: application/x-www-form-urlencoded";
    BOOL bRet = HttpSendRequestA(hRequest, lpszHeaders, -1, NULL, 0);
    if (bRet == FALSE)
    {
        printf("HttpSendRequestA error %d\n", GetLastError());
        goto finally;
    }

    char buf[1024] = {0};
    DWORD dwRead = 0;
    do
    {
        bRet = InternetReadFile(hRequest, buf, 1023, &dwRead);
        if (bRet == FALSE)
        {
            printf("InternetReadFile error %d\n", GetLastError());
            goto finally;
        }

        buf[dwRead] = 0; // ヌル終端
        printf(buf);
    } while (dwRead > 0);

finally:
    if (hRequest != NULL) InternetCloseHandle(hRequest);
    if (hConnect != NULL) InternetCloseHandle(hConnect);
    if (hInet != NULL) InternetCloseHandle(hInet);

    return 0;
}
0
0
2

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
0