Zeel commited on
Commit
e210de0
·
1 Parent(s): 0105922

Dynamically access Wayback imagery

Browse files
Files changed (2) hide show
  1. app.py +41 -1
  2. sandbox.ipynb +376 -2
app.py CHANGED
@@ -15,6 +15,7 @@ import plotly.express as px
15
  import branca.colormap as cm
16
 
17
  from functions import *
 
18
 
19
  st.set_page_config(layout="wide")
20
 
@@ -146,8 +147,47 @@ buffer_geometry_gdf = (
146
  ) # reset index forces GeoSeries to GeoDataFrame
147
  buffer_geometry_gdf["Name"] = "Buffer"
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  # visualize the geometry
150
- wayback_df = pd.read_parquet("./wayback.parquet").set_index("date")
151
  first_item = wayback_df.iloc[0]
152
  wayback_title = "Esri " + first_item["Title"]
153
  wayback_url = (
 
15
  import branca.colormap as cm
16
 
17
  from functions import *
18
+ import xml.etree.ElementTree as ET
19
 
20
  st.set_page_config(layout="wide")
21
 
 
147
  ) # reset index forces GeoSeries to GeoDataFrame
148
  buffer_geometry_gdf["Name"] = "Buffer"
149
 
150
+ # Get Wayback data
151
+ # <old code>
152
+ # wayback_df = pd.read_parquet("./wayback.parquet").set_index("date")
153
+ # </old code>
154
+ # <new code 2nd Feb 2025 by Zeel>
155
+ # Fetch XML data
156
+ url = "https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/WMTS/1.0.0/WMTSCapabilities.xml"
157
+ response = requests.get(url)
158
+ response.raise_for_status() # Ensure request was successful
159
+
160
+ # Parse XML
161
+ root = ET.fromstring(response.content)
162
+
163
+ ns = {
164
+ "wmts": "https://www.opengis.net/wmts/1.0",
165
+ "ows": "https://www.opengis.net/ows/1.1",
166
+ "xlink": "https://www.w3.org/1999/xlink",
167
+ }
168
+
169
+ layers = root.findall(".//wmts:Contents/wmts:Layer", ns)
170
+
171
+ layer_data = []
172
+ for layer in layers:
173
+ title = layer.find("ows:Title", ns)
174
+ identifier = layer.find("ows:Identifier", ns)
175
+ resource = layer.find("wmts:ResourceURL", ns) # Tile URL template
176
+
177
+ title_text = title.text if title is not None else "N/A"
178
+ identifier_text = identifier.text if identifier is not None else "N/A"
179
+ url_template = resource.get("template") if resource is not None else "N/A"
180
+
181
+ layer_data.append({"Title": title_text, "ResourceURL_Template": url_template})
182
+
183
+ wayback_df = pd.DataFrame(layer_data)
184
+ wayback_df["date"] = pd.to_datetime(wayback_df["Title"].str.extract(r"(\d{4}-\d{2}-\d{2})").squeeze(), errors="coerce")
185
+ wayback_df.set_index("date", inplace=True)
186
+ print(wayback_df)
187
+
188
+ # </new code 2nd Feb 2025 by Zeel>
189
+
190
  # visualize the geometry
 
191
  first_item = wayback_df.iloc[0]
192
  wayback_title = "Esri " + first_item["Title"]
193
  wayback_url = (
sandbox.ipynb CHANGED
@@ -2,7 +2,7 @@
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
- "execution_count": 13,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
@@ -10,8 +10,250 @@
10
  "import kml2geojson\n",
11
  "import requests\n",
12
  "import geopandas as gpd\n",
 
13
  "\n",
14
- "data = requests.get(\"https://drive.google.com/uc?id=1bN8lkSQkGZcSmZPLF8jm-AWTRA7FsEcr\")"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  ]
16
  },
17
  {
@@ -169,6 +411,138 @@
169
  "# kml2geojson.convert(BytesIO(data.content))[0]['features']"
170
  ]
171
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  {
173
  "cell_type": "code",
174
  "execution_count": 14,
 
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
+ "execution_count": 2,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
 
10
  "import kml2geojson\n",
11
  "import requests\n",
12
  "import geopandas as gpd\n",
13
+ "import pandas as pd\n",
14
  "\n",
15
+ "# data = requests.get(\"https://drive.google.com/uc?id=1bN8lkSQkGZcSmZPLF8jm-AWTRA7FsEcr\")"
16
+ ]
17
+ },
18
+ {
19
+ "cell_type": "code",
20
+ "execution_count": 3,
21
+ "metadata": {},
22
+ "outputs": [
23
+ {
24
+ "data": {
25
+ "text/html": [
26
+ "<div>\n",
27
+ "<style scoped>\n",
28
+ " .dataframe tbody tr th:only-of-type {\n",
29
+ " vertical-align: middle;\n",
30
+ " }\n",
31
+ "\n",
32
+ " .dataframe tbody tr th {\n",
33
+ " vertical-align: top;\n",
34
+ " }\n",
35
+ "\n",
36
+ " .dataframe thead th {\n",
37
+ " text-align: right;\n",
38
+ " }\n",
39
+ "</style>\n",
40
+ "<table border=\"1\" class=\"dataframe\">\n",
41
+ " <thead>\n",
42
+ " <tr style=\"text-align: right;\">\n",
43
+ " <th></th>\n",
44
+ " <th>Title</th>\n",
45
+ " <th>Identifier</th>\n",
46
+ " <th>LowerCorner</th>\n",
47
+ " <th>UpperCorner</th>\n",
48
+ " <th>Format</th>\n",
49
+ " <th>TileMatrixSetLinks</th>\n",
50
+ " <th>ResourceURL_Template</th>\n",
51
+ " <th>date</th>\n",
52
+ " </tr>\n",
53
+ " </thead>\n",
54
+ " <tbody>\n",
55
+ " <tr>\n",
56
+ " <th>0</th>\n",
57
+ " <td>World Imagery (Wayback 2024-10-10)</td>\n",
58
+ " <td>WB_2024_R11</td>\n",
59
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
60
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
61
+ " <td>NaN</td>\n",
62
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
63
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
64
+ " <td>2024-10-10</td>\n",
65
+ " </tr>\n",
66
+ " <tr>\n",
67
+ " <th>1</th>\n",
68
+ " <td>World Imagery (Wayback 2024-09-19)</td>\n",
69
+ " <td>WB_2024_R10</td>\n",
70
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
71
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
72
+ " <td>NaN</td>\n",
73
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
74
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
75
+ " <td>2024-09-19</td>\n",
76
+ " </tr>\n",
77
+ " <tr>\n",
78
+ " <th>2</th>\n",
79
+ " <td>World Imagery (Wayback 2024-08-15)</td>\n",
80
+ " <td>WB_2024_R08</td>\n",
81
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
82
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
83
+ " <td>NaN</td>\n",
84
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
85
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
86
+ " <td>2024-08-15</td>\n",
87
+ " </tr>\n",
88
+ " <tr>\n",
89
+ " <th>3</th>\n",
90
+ " <td>World Imagery (Wayback 2024-06-27)</td>\n",
91
+ " <td>WB_2024_R07</td>\n",
92
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
93
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
94
+ " <td>NaN</td>\n",
95
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
96
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
97
+ " <td>2024-06-27</td>\n",
98
+ " </tr>\n",
99
+ " <tr>\n",
100
+ " <th>4</th>\n",
101
+ " <td>World Imagery (Wayback 2024-06-06)</td>\n",
102
+ " <td>WB_2024_R06</td>\n",
103
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
104
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
105
+ " <td>NaN</td>\n",
106
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
107
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
108
+ " <td>2024-06-06</td>\n",
109
+ " </tr>\n",
110
+ " <tr>\n",
111
+ " <th>...</th>\n",
112
+ " <td>...</td>\n",
113
+ " <td>...</td>\n",
114
+ " <td>...</td>\n",
115
+ " <td>...</td>\n",
116
+ " <td>...</td>\n",
117
+ " <td>...</td>\n",
118
+ " <td>...</td>\n",
119
+ " <td>...</td>\n",
120
+ " </tr>\n",
121
+ " <tr>\n",
122
+ " <th>170</th>\n",
123
+ " <td>World Imagery (Wayback 2014-06-11)</td>\n",
124
+ " <td>WB_2014_R08</td>\n",
125
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
126
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
127
+ " <td>NaN</td>\n",
128
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
129
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
130
+ " <td>2014-06-11</td>\n",
131
+ " </tr>\n",
132
+ " <tr>\n",
133
+ " <th>171</th>\n",
134
+ " <td>World Imagery (Wayback 2014-05-14)</td>\n",
135
+ " <td>WB_2014_R06</td>\n",
136
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
137
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
138
+ " <td>NaN</td>\n",
139
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
140
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
141
+ " <td>2014-05-14</td>\n",
142
+ " </tr>\n",
143
+ " <tr>\n",
144
+ " <th>172</th>\n",
145
+ " <td>World Imagery (Wayback 2014-04-30)</td>\n",
146
+ " <td>WB_2014_R05</td>\n",
147
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
148
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
149
+ " <td>NaN</td>\n",
150
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
151
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
152
+ " <td>2014-04-30</td>\n",
153
+ " </tr>\n",
154
+ " <tr>\n",
155
+ " <th>173</th>\n",
156
+ " <td>World Imagery (Wayback 2014-03-26)</td>\n",
157
+ " <td>WB_2014_R03</td>\n",
158
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
159
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
160
+ " <td>NaN</td>\n",
161
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
162
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
163
+ " <td>2014-03-26</td>\n",
164
+ " </tr>\n",
165
+ " <tr>\n",
166
+ " <th>174</th>\n",
167
+ " <td>World Imagery (Wayback 2014-02-20)</td>\n",
168
+ " <td>WB_2014_R01</td>\n",
169
+ " <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
170
+ " <td>2.003750722959434E7 2.003750722959434E7</td>\n",
171
+ " <td>NaN</td>\n",
172
+ " <td>default028mm, GoogleMapsCompatible</td>\n",
173
+ " <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
174
+ " <td>2014-02-20</td>\n",
175
+ " </tr>\n",
176
+ " </tbody>\n",
177
+ "</table>\n",
178
+ "<p>175 rows × 8 columns</p>\n",
179
+ "</div>"
180
+ ],
181
+ "text/plain": [
182
+ " Title Identifier \\\n",
183
+ "0 World Imagery (Wayback 2024-10-10) WB_2024_R11 \n",
184
+ "1 World Imagery (Wayback 2024-09-19) WB_2024_R10 \n",
185
+ "2 World Imagery (Wayback 2024-08-15) WB_2024_R08 \n",
186
+ "3 World Imagery (Wayback 2024-06-27) WB_2024_R07 \n",
187
+ "4 World Imagery (Wayback 2024-06-06) WB_2024_R06 \n",
188
+ ".. ... ... \n",
189
+ "170 World Imagery (Wayback 2014-06-11) WB_2014_R08 \n",
190
+ "171 World Imagery (Wayback 2014-05-14) WB_2014_R06 \n",
191
+ "172 World Imagery (Wayback 2014-04-30) WB_2014_R05 \n",
192
+ "173 World Imagery (Wayback 2014-03-26) WB_2014_R03 \n",
193
+ "174 World Imagery (Wayback 2014-02-20) WB_2014_R01 \n",
194
+ "\n",
195
+ " LowerCorner \\\n",
196
+ "0 -2.003750722959434E7 -2.003750722959434E7 \n",
197
+ "1 -2.003750722959434E7 -2.003750722959434E7 \n",
198
+ "2 -2.003750722959434E7 -2.003750722959434E7 \n",
199
+ "3 -2.003750722959434E7 -2.003750722959434E7 \n",
200
+ "4 -2.003750722959434E7 -2.003750722959434E7 \n",
201
+ ".. ... \n",
202
+ "170 -2.003750722959434E7 -2.003750722959434E7 \n",
203
+ "171 -2.003750722959434E7 -2.003750722959434E7 \n",
204
+ "172 -2.003750722959434E7 -2.003750722959434E7 \n",
205
+ "173 -2.003750722959434E7 -2.003750722959434E7 \n",
206
+ "174 -2.003750722959434E7 -2.003750722959434E7 \n",
207
+ "\n",
208
+ " UpperCorner Format \\\n",
209
+ "0 2.003750722959434E7 2.003750722959434E7 NaN \n",
210
+ "1 2.003750722959434E7 2.003750722959434E7 NaN \n",
211
+ "2 2.003750722959434E7 2.003750722959434E7 NaN \n",
212
+ "3 2.003750722959434E7 2.003750722959434E7 NaN \n",
213
+ "4 2.003750722959434E7 2.003750722959434E7 NaN \n",
214
+ ".. ... ... \n",
215
+ "170 2.003750722959434E7 2.003750722959434E7 NaN \n",
216
+ "171 2.003750722959434E7 2.003750722959434E7 NaN \n",
217
+ "172 2.003750722959434E7 2.003750722959434E7 NaN \n",
218
+ "173 2.003750722959434E7 2.003750722959434E7 NaN \n",
219
+ "174 2.003750722959434E7 2.003750722959434E7 NaN \n",
220
+ "\n",
221
+ " TileMatrixSetLinks \\\n",
222
+ "0 default028mm, GoogleMapsCompatible \n",
223
+ "1 default028mm, GoogleMapsCompatible \n",
224
+ "2 default028mm, GoogleMapsCompatible \n",
225
+ "3 default028mm, GoogleMapsCompatible \n",
226
+ "4 default028mm, GoogleMapsCompatible \n",
227
+ ".. ... \n",
228
+ "170 default028mm, GoogleMapsCompatible \n",
229
+ "171 default028mm, GoogleMapsCompatible \n",
230
+ "172 default028mm, GoogleMapsCompatible \n",
231
+ "173 default028mm, GoogleMapsCompatible \n",
232
+ "174 default028mm, GoogleMapsCompatible \n",
233
+ "\n",
234
+ " ResourceURL_Template date \n",
235
+ "0 https://wayback.maptiles.arcgis.com/arcgis/res... 2024-10-10 \n",
236
+ "1 https://wayback.maptiles.arcgis.com/arcgis/res... 2024-09-19 \n",
237
+ "2 https://wayback.maptiles.arcgis.com/arcgis/res... 2024-08-15 \n",
238
+ "3 https://wayback.maptiles.arcgis.com/arcgis/res... 2024-06-27 \n",
239
+ "4 https://wayback.maptiles.arcgis.com/arcgis/res... 2024-06-06 \n",
240
+ ".. ... ... \n",
241
+ "170 https://wayback.maptiles.arcgis.com/arcgis/res... 2014-06-11 \n",
242
+ "171 https://wayback.maptiles.arcgis.com/arcgis/res... 2014-05-14 \n",
243
+ "172 https://wayback.maptiles.arcgis.com/arcgis/res... 2014-04-30 \n",
244
+ "173 https://wayback.maptiles.arcgis.com/arcgis/res... 2014-03-26 \n",
245
+ "174 https://wayback.maptiles.arcgis.com/arcgis/res... 2014-02-20 \n",
246
+ "\n",
247
+ "[175 rows x 8 columns]"
248
+ ]
249
+ },
250
+ "execution_count": 3,
251
+ "metadata": {},
252
+ "output_type": "execute_result"
253
+ }
254
+ ],
255
+ "source": [
256
+ "pd.read_parquet(\"wayback.parquet\")"
257
  ]
258
  },
259
  {
 
411
  "# kml2geojson.convert(BytesIO(data.content))[0]['features']"
412
  ]
413
  },
414
+ {
415
+ "cell_type": "code",
416
+ "execution_count": 24,
417
+ "metadata": {},
418
+ "outputs": [],
419
+ "source": [
420
+ "import requests\n",
421
+ "import pandas as pd\n",
422
+ "import xml.etree.ElementTree as ET\n",
423
+ "\n",
424
+ "# Fetch XML data\n",
425
+ "url = \"https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/WMTS/1.0.0/WMTSCapabilities.xml\"\n",
426
+ "response = requests.get(url)\n",
427
+ "response.raise_for_status() # Ensure request was successful\n",
428
+ "\n",
429
+ "# Parse XML\n",
430
+ "root = ET.fromstring(response.content)"
431
+ ]
432
+ },
433
+ {
434
+ "cell_type": "code",
435
+ "execution_count": 25,
436
+ "metadata": {},
437
+ "outputs": [
438
+ {
439
+ "name": "stdout",
440
+ "output_type": "stream",
441
+ "text": [
442
+ "Found 178 layers\n"
443
+ ]
444
+ }
445
+ ],
446
+ "source": [
447
+ "ns = {\"wmts\": \"https://www.opengis.net/wmts/1.0\"}\n",
448
+ "layers = root.findall(\".//wmts:Layer\", ns)\n",
449
+ "print(f\"Found {len(layers)} layers\")"
450
+ ]
451
+ },
452
+ {
453
+ "cell_type": "code",
454
+ "execution_count": 35,
455
+ "metadata": {},
456
+ "outputs": [
457
+ {
458
+ "name": "stdout",
459
+ "output_type": "stream",
460
+ "text": [
461
+ "Found 178 layers\n",
462
+ " Title \\\n",
463
+ "date \n",
464
+ "2025-01-30 World Imagery (Wayback 2025-01-30) \n",
465
+ "2024-12-12 World Imagery (Wayback 2024-12-12) \n",
466
+ "2024-11-18 World Imagery (Wayback 2024-11-18) \n",
467
+ "2024-10-10 World Imagery (Wayback 2024-10-10) \n",
468
+ "2024-09-19 World Imagery (Wayback 2024-09-19) \n",
469
+ "... ... \n",
470
+ "2014-06-11 World Imagery (Wayback 2014-06-11) \n",
471
+ "2014-05-14 World Imagery (Wayback 2014-05-14) \n",
472
+ "2014-04-30 World Imagery (Wayback 2014-04-30) \n",
473
+ "2014-03-26 World Imagery (Wayback 2014-03-26) \n",
474
+ "2014-02-20 World Imagery (Wayback 2014-02-20) \n",
475
+ "\n",
476
+ " ResourceURL_Template \n",
477
+ "date \n",
478
+ "2025-01-30 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
479
+ "2024-12-12 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
480
+ "2024-11-18 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
481
+ "2024-10-10 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
482
+ "2024-09-19 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
483
+ "... ... \n",
484
+ "2014-06-11 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
485
+ "2014-05-14 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
486
+ "2014-04-30 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
487
+ "2014-03-26 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
488
+ "2014-02-20 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
489
+ "\n",
490
+ "[178 rows x 2 columns]\n"
491
+ ]
492
+ }
493
+ ],
494
+ "source": [
495
+ "ns = {\n",
496
+ " \"wmts\": \"https://www.opengis.net/wmts/1.0\",\n",
497
+ " \"ows\": \"https://www.opengis.net/ows/1.1\",\n",
498
+ " \"xlink\": \"https://www.w3.org/1999/xlink\"\n",
499
+ "}\n",
500
+ "\n",
501
+ "layers = root.findall(\".//wmts:Contents/wmts:Layer\", ns)\n",
502
+ "print(f\"Found {len(layers)} layers\")\n",
503
+ "\n",
504
+ "layer_data = []\n",
505
+ "for layer in layers:\n",
506
+ " title = layer.find(\"ows:Title\", ns)\n",
507
+ " identifier = layer.find(\"ows:Identifier\", ns)\n",
508
+ " resource = layer.find(\"wmts:ResourceURL\", ns) # Tile URL template\n",
509
+ " \n",
510
+ " title_text = title.text if title is not None else \"N/A\"\n",
511
+ " identifier_text = identifier.text if identifier is not None else \"N/A\"\n",
512
+ " url_template = resource.get(\"template\") if resource is not None else \"N/A\"\n",
513
+ "\n",
514
+ " layer_data.append({\n",
515
+ " \"Title\": title_text,\n",
516
+ " \"ResourceURL_Template\": url_template\n",
517
+ " })\n",
518
+ "\n",
519
+ "import pandas as pd\n",
520
+ "df = pd.DataFrame(layer_data)\n",
521
+ "df['date'] = pd.to_datetime(df['Title'].str.extract(r\"(\\d{4}-\\d{2}-\\d{2})\").squeeze(), errors='coerce')\n",
522
+ "df.set_index('date', inplace=True)\n",
523
+ "print(df)"
524
+ ]
525
+ },
526
+ {
527
+ "cell_type": "code",
528
+ "execution_count": 32,
529
+ "metadata": {},
530
+ "outputs": [
531
+ {
532
+ "data": {
533
+ "text/plain": [
534
+ "'https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/36557/{TileMatrix}/{TileRow}/{TileCol}'"
535
+ ]
536
+ },
537
+ "execution_count": 32,
538
+ "metadata": {},
539
+ "output_type": "execute_result"
540
+ }
541
+ ],
542
+ "source": [
543
+ "df['Tile URL'].iloc[0]"
544
+ ]
545
+ },
546
  {
547
  "cell_type": "code",
548
  "execution_count": 14,