Quick guide: query an ArcGIS Online feature service table with Python

Here’s a quick and easy guide to querying an ArcGIS Online feature service table with Python. No intro, straight into the how-to:

To get started, import the requests library:

import requests

The next step is to authenticate with ArcGIS Online and obtain a token. To do that, I will call the generateToken REST endpoint, passing in a username and password. The data payload will be application/x-www-form-urlencoded form data, and the appropriate header is included in the request:

def generateToken():
    userName = "username"
    password = "password"
    generateTokenUrl = "https://www.arcgis.com/sharing/rest/generateToken"
    refererUrl = "https://www.arcgis.com&client=referer"

    headers = {
        "Content-Type": "application/x-www-form-urlencoded"
    }
    requestBody = f"username={userName}&password={password}&referer={refererUrl}&f=json"

    response = requests.request("POST", generateTokenUrl, headers=headers, data=requestBody)

    return response.json()["token"]

Once a token is obtained, a layer’s table can be queried. For this example, I am using the Colleges and Universities layer from the ArcGIS Online Living Atlas of the World:

https://maps.arcgis.com/home/item.html?id=d257743c055e4206bd8a0f2d14af69fe

This layer displays colleges and universities in the U.S. and its territories. From the link above the feature service url can be obtained:


Navigate to the service url, and the “colleges_and_universities” layer is visible:


Navigate to the layer url, and various metadata including a description is visible; scrolling down will show the table’s columns and the supported query operations:


To query data in the layer, the query REST endpoint is used, passing in the token obtained above and the required query parameters. For example, to return all institutions in the layer that are in Phoenix, Arizona, I would want to query the “CITY” and “STABBR” fields where their values are equal to “Phoenix” and “AZ”, respectively. A query string can be built out to include a where clause that matches this. Also note the additional parameters of outFields=* to return all the table’s fields and their values, returnGeometry=true to include the lat and lon for the point, f=json to tell the server the response data type we want, and finally a token parameter with the previously obtained token value to authenticate with the server:

def queryTable(token):
    serviceUrl = "https://services2.arcgis.com/FiaPA4ga0iQKduv3/ArcGIS/rest/services/Colleges_and_Universities_View/FeatureServer/0/query"

    city = "Phoenix"
    state = "AZ"

    headers = {
        "Content-Type": "application/x-www-form-urlencoded"
    }

    requestBody = f"where=CITY='{city}' AND STABBR='{state}'&outFields=*&returnGeometry=true&f=json&token={token}"
    
    response = requests.request("POST", serviceUrl, headers=headers, data=requestBody)

    return response.json()

The response object is returned as JSON, and the features that match the where clause (28 in total) can be found in the features property:


Putting the code all together, the complete script looks like this (also available as a GitHub Gist here):

import requests

def generateToken():
    userName = "useraname"
    password = "password"
    generateTokenUrl = "https://www.arcgis.com/sharing/rest/generateToken"
    refererUrl = "https://www.arcgis.com&client=referer"

    headers = {
        "Content-Type": "application/x-www-form-urlencoded"
    }
    requestBody = f"username={userName}&password={password}&referer={refererUrl}&f=json"

    response = requests.request("POST", generateTokenUrl, headers=headers, data=requestBody)

    return response.json()["token"]


def queryTable(token):
    serviceUrl = "https://services2.arcgis.com/FiaPA4ga0iQKduv3/ArcGIS/rest/services/Colleges_and_Universities_View/FeatureServer/0/query"

    city = "Phoenix"
    state = "AZ"

    headers = {
        "Content-Type": "application/x-www-form-urlencoded"
    }
    requestBody = f"where=CITY='{city}' AND STABBR='{state}'&outFields=*&returnGeometry=true&f=json&token={token}"
    
    response = requests.request("POST", serviceUrl, headers=headers, data=requestBody)

    return response.json()


token = generateToken()
response = queryTable(token)

Leave a comment