Reading geopackage geometries in Python

You can use the gdal/ogr, fiona (built on gdal/ogr) or geopandas (built on fiona) python libraries.

Below is a fiona example:

import fiona

# No need to pass "layer='etc'" if there's only one layer
with fiona.open('test.gpkg', layer='layer_of_interest') as layer:
    for feature in layer:
        print(feature['geometry'])

Partial output for one record in my data:

{'type': 'MultiPolygon', 'coordinates': [[[(147.01294051, -34.75046834699997), (147.01289292100003, -34.75075388199998), (147.01251220799998, -34.75068249799993), etc...

From the fiona docs:

A record you get from a collection is a Python dict structured exactly like a GeoJSON Feature. Fiona records are self-describing; the names of its fields are contained within the data structure and the values in the fields are typed properly for the type of record. Numeric field values are instances of type int and float, for example, not strings.


Geopandas is extremely useful and easy to use for this kind of thing: http://geopandas.org/

You can load vector data with attributes (e.g. from geopackages, shapefiles, etc.) into ?(geo)pandas dataframes which allow really easy analysis of the data without messing around with ogr/gdal.

import geopandas as gpd
data = gpd.read_file("path.mygeopackage.gpkg")
data.head()  # Prints the first 5 rows of the loaded data to see what it looks like.

GeoPackages are SQLite databases with a specific structure. You cannot just read geometries as "random" sequential bytes from a SQLite database, there might be fragmentation or similar.

If you want to do it low-level and without one of the fine libraries others suggested, the pure Python standard library way would be to use sqlite3 to open the file and then get the geometry bytes via SQL.

For example for http://www.geopackage.org/data/sample1_2.gpkg:

import sqlite3
conn = sqlite3.connect('sample1_2.gpkg')                                
cursor = conn.cursor()

# geometry column name is in gpkg_geometry_columns
# let'S pretend we already know it is 'Shape' for this dataset
cursor.execute("SELECT Shape FROM counties LIMIT 1;")
result = cursor.fetchone()[0]
# now you have the bytes of one geometry

It's not plain WKB though, you would still need to parse a binary header and then take the actual WKB bytes from the blob. I won't go into detail because it was obviously not what the questioner wanted, but if you want to do this the hard way, the specifications can be found at http://www.geopackage.org./spec/#gpb_format