はじめに
この記事は、
「タイルのURL取得なんて余裕だと思ってたのに、なぜかできない。。。」
と謎にハマってしまった人(数日前の自分)に向けた記事です。
予想される検索ワード
以下、この記事を求めているであろう方が入力しそうな
(というか実際に私が必死で検索した)検索ワードです。
QGIS, PyQGIS, タイル, URL, 取得
実行環境
- Windows11
- QGIS 3.28
忙しい人向けの結論
QGISでタイルレイヤを選択している状態で、Pythonコンソールで以下を実行すれば取得できます。
# アクティブレイヤ
layer = iface.activeLayer()
# レイヤのソースを取得
src = layer.source()
# ソースを"&"で分けてリスト化
src_list = src.split("&")
# "url="で始まる要素を取得
url = [s for s in src_list if s.startswith('url=')][0]
# 先頭の"url="という文字は不要なので削除
url = url.lstrip("url=")
# URLデコード
url = url.replace("%7B", "{").replace("%7D", "}")
print(url)
タイルのURLを取得するために
取得方法自体は上述の通りなので、
ここからは「なんで上記のコードで取得できるの?」について書いていきます。
layer.source()とは
私が混乱した諸悪の根源です。
というか、そもそもPyQGISのドキュメントに"layer.source()"って載ってないですよね?
「アンタは一体何なんだ!」って感じです。
とりあえず、素直にQGISに質問(ただのhelp)してみると以下のように返してくれます。
>>> help(qgis._core.QgsRasterLayer.source)
Help on built-in function source:
source(...)
source(self) -> str
Returns the source for the layer. This source may contain usernames, passwords
and other sensitive information.
.. seealso:: :py:func:`publicSource`
ふむふむ。なんだかレイヤのソース(URL)を返してくれそうですね。
layer.source()を試してみる
さて、みんな大好き地理院タイルで確認してみましょう。
(きっとタイルのURLを返してくれるに違いない!)
$\huge{「...いや、欲しいのはそっちじゃないんや。」}$
世の中、そう甘くはないですね。
ちなみに、私はここから 「きっと、素直にURLを返す関数があるに違いない!」 と
関数探しの旅に出(て帰ってこれなくなり)ました。
layer.source()の戻り値
関数探しの旅に出ると帰って来れなくなる恐れがあるので
素直にlayer.source()の戻り値と向き合います。
指定レイヤがWebマップタイルだった場合の
layer.source()の戻り値は基本的に、
key1=value1&key2=value2&key3=value3&...
という構造のようです。
(指定レイヤがWebマップタイルでない場合は、この限りでは無いです)
今回返ってきた値を分解してみると
type=xyz # xyzタイル形式だよ
&
url=https://cyberjapandata.gsi.go.jp/xyz/pale/%7Bz%7D/%7Bx%7D/%7By%7D.png # urlはここだよ
&
zmax=18&zmin=0 # ズームレベル0~18だよ
&
http-header:referer= # HTTPリファラは無いよ
ということを示しています。
URLの取得
layer.source()の戻り値を見てみたところ、
"url="に割り当てられている値がそれっぽいので、取得してみましょう。
# アクティブレイヤ
layer = iface.activeLayer()
# レイヤのソースを取得
src = layer.source()
# ソースを"&"で分けてリスト化
src_list = src.split("&")
# "url="で始まる要素を取得
url = [s for s in src_list if s.startswith('url=')][0]
# 先頭の"url="という文字は不要なので削除
url = url.lstrip("url=")
print(url)
# => https://cyberjapandata.gsi.go.jp/xyz/pale/%7Bz%7D/%7Bx%7D/%7By%7D.png
それっぽい値が取得できましたね。
あとは"%7B"とか"%7D"をどうにかすれば良さそうです。
URLエンコード
"%7B"とか"%7D"は
URLエンコードによって "{" とか "}" が変換された値です。
URLエンコード、とは、URLとして使用できない文字を扱う際に、利用可能な文字に変換(エンコード)する事を言います。パーセントエンコーディング、とも言います。
そのため、"%7B"とか"%7D"をデコード(元に戻す)すれば良いです。
# URLデコード
url = url.replace("%7B", "{").replace("%7D", "}")
print(url)
# => https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png
上手く取得することができました。めでたしめでたし。
おわりに
「タイルのURL取得なんてQGISのプロパティでサクッと見られるんだから余裕でしょ」
と思っていたのですが、意外にも手間取ってしまいました。(主に関数探しのせい)
皆様も関数探しの旅は、ほどほどに。。。
...あ、urlを一発で取得できる関数を知っている方がいれば、教えてください。