Search for Landsat-8 products using the “eop:track” as a queryable

import lxml.etree as etree
import requests
import cioppy
ciop = cioppy.Cioppy()
def get_params(osd):

    oss_ns = {'a':'',

    oss_content = etree.fromstring(requests.get(osd).content)

    url_template_element = oss_content.xpath('/j:OpenSearchDescription/j:Url[@type="application/atom+xml"]',

    parameters = dict()

    for index, parameter in enumerate(url_template_element.xpath('.//f:Parameter', namespaces=oss_ns)):

        parameters[parameter.attrib['name']] = {'title' : parameter.attrib['title'],
                                                'value' : parameter.attrib['value']}

        options = []
        for option in parameter.xpath('.//f:Option', namespaces=oss_ns):


        parameters[parameter.attrib['name']] = {'title' : parameter.attrib['title'],
                                                'value' : parameter.attrib['value'],
                                                'options' : options}
    return parameters
def get_param_value(osd, os_parameter):

    params = get_params(osd)

    res = None

    for index, param in enumerate(params):

        if params[param]['value'] == os_parameter:

            res = params[param]
            res['name'] = param

    return res

Define the Landsat-8 endpoint

osd_url = ''

Get the Landsat-8 search parameters

ls8_parameters = get_params(osd_url)

Print all the OpenSearch parameters

for key, value in ls8_parameters.iteritems():

    print '%24s' % ls8_parameters[key]['value'],  ls8_parameters[key]['title']
              {geo:uid?} The identifier of the resource within the search engine context (local reference)
    {t2:downloadOrigin?} a string that identifies the download origin (keyword, hostname...) to adapt the enclosure. If the parameter is enclosed between [] (e.g. [terradue]), enclosure will be returned only if there is a enclosure found for this source.
       {eop:cloudCover?} A number, set or interval requesting the cloud coverage
            {eop:frame?} A number, set or interval requesting the range of orbit frames
            {startIndex} index of the first search result desired
   {t2:vendorSpecifics?} A number, set or interval filtering vendor specific name:value
             {startPage} page number of the set of search results desired
       {eop:sensorType?} A string identifying the sensor type
     {eop:accessedFrom?} A string identifying the location from which the resource will be accessed. The catalogue shall return the download location in the enclosure atom link according to the parameter value.
         {t2:landCover?} A number, set or interval requesting the land coverage
      {eop:productType?} A string identifying the product type
           {time:start?} start of the temporal interval (RFC-3339)
 {eop:sensorResolution?} A string identifying the sensor spectral range
           {sct:source?} The URI of a source link (rel=via in ATOM).
         {geo:geometry?} Geometry in WKT
         {geo:relation?} Spatial relation (possible values are “intersects”, “contains”, “disjoint”). The default is intersects.
 {eop:parentIdentifier?} A string identifying the collection of the entry in a hierarchy of dataset
  {eop:processingLevel?} A string identifying the processing level applied to the dataset
              {language} desired language of the results
         {eop:platform?} A string with the platform short name
            {eop:track?} A number, set or interval requesting the range of orbit tracks
{t2:doubleCheckGeomtry?} Set to apply a finer geometry filtering
             {time:end?} stop of the temporal interval (RFC-3339)
         {dct:modified?} date after which dataset are updated (RFC-3339)
              {geo:box?} Rectangular bounding box
                 {count} number of search results per page desired
        {time:relation?} Temporal relation (possible values are “intersects”, “contains”, “during”, “disjoint”, “equals”)
   {eop:orbitDirection?} A string identifying the orbit direction
          {dct:subject?} The identifier of a category. Recommended best practice is to use a controlled vocabulary.
           {searchTerms} EO Free Text Search
         {t2:extension?} The value:name of a extension.
       {eop:instrument?} A string identifying the instrument
            {eop:title?} A name given to the resource
        {eop:orbitType?} A string identifying the orbit type

Find the parameter associated to ‘{eop:wrsLongitudeGrid?}’ and its options

product_type_parameter = get_param_value(osd_url, '{eop:track?}')
download_origin_parameter = get_param_value(osd_url, '{t2:downloadOrigin?}')

Now search for Landsat-8 products creating a dictionary with the search parameters

search_params = dict([(product_type_parameter['name'],
                       '160'), (download_origin_parameter['name'], 'terradue')])
{'do': 'terradue', 'track': '160'}
search =,

Show the first result returned

{'enclosure': '',
 'identifier': 'LC08_L1TP_160248_20190430_20190430_01_RT',
 'productType': 'L1TP',
 'self': '',
 'startdate': '2019-04-30T08:07:29.6130000Z',
 'track': '160',
 'wkt': 'POLYGON((93.72898 81.78061,98.27937 80.20367,108.4065 80.72712,105.58942 82.40608,93.72898 81.78061))'}

You can of course write the search parameters directly with:

search =,
                     params={'track': '160'},
{'enclosure': '',
 'identifier': 'LC08_L1TP_160248_20190430_20190430_01_RT',
 'productType': 'L1TP',
 'self': '',
 'startdate': '2019-04-30T08:07:29.6130000Z',
 'track': '160',
 'wkt': 'POLYGON((93.72898 81.78061,98.27937 80.20367,108.4065 80.72712,105.58942 82.40608,93.72898 81.78061))'}