埋め込みJSONからプロキシIPと16進ポートを抽出する
プロキシ一覧のスクリプト呼び出しから既知のJSONペイロードをデコードし、16進ポートはそのソース形式が明示している場合にのみ解釈します。
空のHTMLテーブルは、応答にプロキシのレコードがないことを必ずしも意味しません。一部の一覧はJSONオブジェクトをJavaScript呼び出しの中に置き、後から行を埋めます。
すでに取得済みのソースが特定のラッパー gp.insertPrx とそれに続くJSONオブジェクトを使っている場合:
import ipaddress
import json
import re
decoder = json.JSONDecoder()
endpoints = set()
for marker in re.finditer(r"gp[.]insertPrx\(\s*", html):
try:
row, end = decoder.raw_decode(html, marker.end())
if not isinstance(row, dict):
continue
address = ipaddress.ip_address(row["PROXY_IP"])
port = int(row["PROXY_PORT"], 16)
except (ValueError, KeyError, TypeError):
continue
if 1 <= port <= 65535 and html[end:].lstrip().startswith(");"):
endpoints.add((str(address), port))
htmlはブラウザのオブジェクトではなくソースのテキストです。正規表現は既知のラッパーを見つけ、JSONDecoderがJSON値の終わりを判定します。これにより、入れ子のJSONを正規表現だけで解析しようとする試みを避けられます。
例のポートフィールドは明示的に16進数です。C38は10進数の3128を意味します。どちらもポートと呼ばれるという理由だけで、無関係なプロバイダーの10進フィールドに基数16を適用してはいけません。
これは示された形式のためのパーサーであり、JavaScriptインタープリターではありません。単一引用符のオブジェクトリテラル、計算値、その他のJavaScript式には別の文書化されたデータインターフェースが必要です。エンドポイント一覧を得るために任意のページコードを実行しないでください。
ソースの契約を検証し、プロトコルフィールドは別に保持します。代わりにHTMLの行が埋まっているソースなら、このJavaScriptラッパーのパーサーではなく行単位のエンドポイント抽出を使ってください。アドレスとポートを抽出しても、そのエンドポイントが現在使えるプロキシサービスを提供していることにはなりません。