or1ko's diary

日々を書きます

HTTPSのURLから本文を取得する方法

事前に、Wifiを使えるようにしておく。
Raspberry Pi Pico WとMicroPythonでWifiに接続する方法 - or1ko's diary

まず、httpfetch.pyというファイル名で下記を作成。
長くなったので別ファイルとして保存。

import usocket
import ssl

def fetch(url):
    try:
        proto, dummy, host, path = url.split("/", 3)
    except ValueError:
        proto, dummy, host = url.split("/", 2)
        path = ""

    port = 443
    if ":" in host:
        host, port = host.split(":", 1)
        port = int(port)

    ai = usocket.getaddrinfo(host, port, 0, usocket.SOCK_STREAM)
    ai = ai[0]

    s = usocket.socket(ai[0], ai[1], ai[2])
    try:
        s.connect(ai[-1])
        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
        s = ctx.wrap_socket(s, server_hostname=host)

        s.write('GET')
        s.write(b" /")
        s.write(path)
        s.write(b" HTTP/1.0\r\nHost: ")
        s.write(host)
        s.write(b"\r\n")
        s.write(b"\r\n")

        l = s.readline()
        l = l.split(None, 2)
        status = int(l[1])
        while True:
            l = s.readline()
            if not l or l == b"\r\n":
                break
            if l.startswith(b"Transfer-Encoding:"):
                if b"chunked" in l:
                    raise ValueError("Unsupported " + l)
            elif l.startswith(b"Location:"):
                raise NotImplementedError("Redirects not yet supported")
        
        body = s.read()
        
    except OSError:
        raise
    finally:
        s.close()

    return body

本体側で下記のようにして利用する。

import httpfetch

body = httpfetch.fetch('https://www.example.com')
print(body)

本文が大きいとメモリ不足で失敗する。
その場合は、すべて取得せず一定のbyteごとに読み取るようにする。

下記の2つのページを参考に作成。
pycopy-lib/cpython-ussl/ussl.py at master · pfalcon/pycopy-lib · GitHub
pycopy-lib/urllib.urequest/urllib/urequest.py at master · pfalcon/pycopy-lib · GitHub