CAR¶
O Serviço Florestal Brasileiro mantem um GeoServer sob um certificado TLS 1.2 (ultrapassado) e isso dificulta o acesso usando a biblioteca OWSLib, como faço usualmente.
Cheguei a abri a issue Cipher / SSL Error #1008, buscando auxílio e os caminhos indicados me fizeram fazer o acesso diretamente por meio de requisição web, abstraindo o GeoServer.
import json
import pprint
import tempfile
import ee
import geemap
import geopandas as gpd
import pandas as pd
import open_geodata as geo
import requests
from urllib3.util import create_urllib3_context
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
Vetores
# Obtem, seleciona
gdf = geo.load_dataset(db='sp', name='geo.sp_250k_wgs84')
# Seleciona
mask = (
(gdf['municipio_nome'] == 'Piracicaba')
| (gdf['municipio_nome'] == 'Americana')
| (gdf['municipio_nome'] == 'Limeira')
)
gdf = gdf[mask]
# Passa para a mesma coordenada do raster
# gdf['geometry'] = gdf['geometry'].to_crs(4326)
gdf['geometry'] = gdf['geometry'].to_crs(4674)
# Reseta Index
gdf = gdf.reset_index(drop=True)
gdf.info()
gdf.head()
Criamos uma pasta temporária, onde os arquivos serão baixados.
# Crio pasta temporária
temp_path = Path(tempfile.gettempdir()) / 'open_geodata' / 'sfb'
temp_path.mkdir(exist_ok=True, parents=True)
temp_path
Definimos qual o estado que desejamos baixar e instanciamos a classe.
É possível também ver o atributo url para entender qual a url que será utilizada para baixar o arquivo.
estado = 'AC'
car = geo.providers.br.sfb.sicar.CAR(uf=estado)
car.url
Only return the NumberOfFeatures in a WFS query indica que o WFS na versão 1.0.0 não retorna.
url = 'https://geoserver.car.gov.br/geoserver/sicar/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=sicar%3Asicar_imoveis_sp&outputFormat=application%2Fjson'
url = 'https://geoserver.car.gov.br/geoserver/sicar/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=sicar%3Asicar_imoveis_sp&resultType=hits'
url = 'https://geoserver.car.gov.br/geoserver/sicar/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=sicar%3Asicar_imoveis_sp&outputFormat=application%2Fjson&startIndex=1000'
url
car.create_session()
# r = car.session.get(url=url)
# print(r.status_code)
xmin, ymin, xmax, ymax = map(float, gdf.total_bounds)
f'{xmin},{ymin},{xmax},{ymax}:{gdf.crs}'
O GeoServer versão 1.0.0, utiulizado pelo SFB, tem diversas limitações por ser desatualizado.
- Não aceita o parâmetro
resultType=hitspara contar o número de feições existentes - O
maxFeaturesserá, sempre, no máximo, de 10.000, mesmo que se defina mais que isso.
base_url = "https://geoserver.car.gov.br/geoserver/sicar/ows"
params = {
"service": "WFS",
"version": "1.0.0",
"request": "GetFeature",
"typeName": "sicar:sicar_imoveis_ac",
"outputFormat": "application/json",
"maxFeatures": 10_000,
#'BBOX': f'{xmin},{ymin},{xmax},{ymax}:{gdf.crs}',
#'bbox': f'{xmin},{ymin},{xmax},{ymax}',
"startIndex": 0,
#'srsName': 'EPSG:4326',
'srsName': 'EPSG:4674',
}
r = car.session.get(base_url, params=params)
print(len(r.json().get("features", [])))
split_url = urlsplit(url=base_url)
encode_params = urlencode(query=params, doseq=True)
urlunsplit(
(
split_url.scheme, # https
split_url.netloc, # servidor.com
split_url.path, # /wfs
encode_params, # Parâmetros modificados (a nova query)
split_url.fragment, # fragmento (#anchor)
)
)
Na real
params = {
"service": "WFS",
"version": "1.0.0",
"request": "GetFeature",
"typeName": "sicar:sicar_imoveis_sp",
"outputFormat": "application/json",
"maxFeatures": 10_000,
#'BBOX': f'{xmin},{ymin},{xmax},{ymax}',
#'srsName': 'EPSG:4326',
'srsName': 'EPSG:4674',
}
total = 0
start = 0
all_features = []
while True:
params["startIndex"] = start # Pode não ser suportado, mas tente
r = car.session.get(url=base_url, params=params, stream=True)
r.raise_for_status()
data = r.json()
# Obtem os features
features = data.get("features", [])
count = len(features)
print(f"Chunk com {count} feições")
total += count
#
all_features.extend(features)
print(params["maxFeatures"])
if count < params["maxFeatures"]:
break
start += count
print(f"Total de feições: {total}")
temp_path
output_file = temp_path / f'car_{estado}4674.geojson'
geojson = {"type": "FeatureCollection", "features": all_features}
with open(output_file, "w", encoding="utf-8") as f:
json.dump(geojson, f)
gdf = gpd.read_file(output_file)
gdf.to_file(temp_path / f'car_{estado}4674.gpkg', driver='GPKG')
Fazemos o download do arquivo.
output_file = temp_path / f'car_{estado}.geojson'
car.download_file(filepath=output_file, url=url)
Por fim lemos o arquivo.
gdf = gpd.read_file(filename=output_file)
gdf.info()
gdf.head(3)