How to Get Data from an API & Process XML in Python
Tags: nlp, datascience, tutorial, beginners
Published: 2020-07-05 12:41:53

Thanks to the `requests` library it is quick and easy to get data from an API, even for beginners, and the `ElementTree` library makes it easy to process the XML that an API provides. This tutorial, aimed at beginners, will show you an end-to-end example using python to get information about **property listings** from the **Zoopla API**.

We start by going to the [Zoopla API](https://developer.zoopla.co.uk/) page and clicking 'Register':

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zxsvyzr1x95kxkf9dbhi.png)

Fill in the form:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/s11az8ko8br9e7r3cfzd.png)

You'll be given an **API key** (a string of text) that looks something like this:

`abc79x5kxxx8xxx6def4abc1`

You're then allowed to use their [interactive tool to search for property listings](https://developer.zoopla.co.uk/io-docs). I searched for a postcode by typing in 'WR10', with 'area' left blank, and clicked the 'Try it!' button.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/aty7n54ylkk5m1zg42u9.png)

This produced a **request URL** which will be needed if we want to do this search programmatically in our python code:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/93es74p7ei54xaaicn9v.png)

(Note: my API key has been cropped from the image but your API key will be shown after 'api_key=')

Notice how the URL contains the postcode that was used in the search, as well as the API key. 

The 'Try it' feature also produces the **XML output** containing the search results:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uqx3pxm2ef5yowr6qcyf.png)

It's a good idea to look through this to get an idea of the structure of the XML to make it easier to use the information later. Tip: if you copy-paste the XML into a tool like **Sublime Text**, you can collapse/expand the tags to make it easier to see the hierarchy of attributes.

Now let's start coding. We first need to import the following libraries (install them first if you need to):

```python
import requests  # for using API
import xml.etree.ElementTree as ET  # for parsing XML
import numpy as np  # for using pandas
import pandas as pd  # for using dataframes
```
Then save your api key as a variable. I've called mine `api_key`:

```python
api_key = 'abc79x5kxxx8xxx6def4abc1'
```

Copy-paste the request URL that was created by the 'Try it!' feature on the Zoopla API website and save it as a variable called `request_url`:

```python
request_url = 'http://api.zoopla.co.uk/api/v1/property_listings.xml?postcode=WR10&api_key=abc79x5kxxx8xxx6def4abc1'
```
(Note: the API key at the end of the request URL above is a dummy string. You should have your own API key shown there.)

We need to use this `request_url` to call the API from our python code, like this:

```python
r = requests.get(request_url)  # call API 
```

We can then use `ElementTree` to process the XML that the API sent back in its response:

```python
root = ET.fromstring(r.content)  # parse XML
```

Let's say that we're only interested in the `description` for each property listing. We can print each description by looping through the `description` tags and printing the text, like this:

```python
# loop through each "description" element in the XML 
for description in root.iter('description'):  
        print(description.text, # print the description
              '\n')  # leave space under the description
```

My output looks like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/k8t224ioxerp7njpqo96.png)

Let's modify the loop to put the descriptions into a dataframe instead of printing them:

```python
# create a list to store the descriptions
desc_list = []

# loop through each "description" element in the XML
for description in root.iter('description'):
        # add the description text to the list of descriptions   
        desc_list.append(description.text)  
        
# convert the list of descriptions to a dataframe
properties_df = pd.DataFrame({"description":desc_list})

# view the properties dataframe
# (with a wider column "description" so we can see the full text)
properties_df\
.style.set_properties(subset=['description'], **{'width': '800px'}) \
.hide_index() # don't show the index column
```

My output:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/isugo7h34vmhi93zgb0j.png)

Let's get the **property type** for each listing and add them to the dataframe:

```python
# create a list to store the property type for each property
prop_types_list = []

# loop through the property listings
for prop_type in root.iter('property_type'):
        # add the property type to the list
        prop_types_list.append(prop_type.text)
        
# add the property types to the dataframe as a new column
properties_df["property_type"] = prop_types_list

# view the updated dataframe
properties_df\
.style.set_properties(subset=['description'], **{'width': '800px'}) \
.hide_index() 

```

The output:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9ce1lzb7ymdstz8z8yjg.png)

What if we wanted to get the property listings for multiple postcodes? This is one way of doing it using a list of postcodes to dynamically build a request URL for each postcode:

```python
# create a list of the postcodes to get property listings for
postcodes = ['PE19','WR10', 'PO38'] 

# create a list to store the request URL for each postcode
request_urls = []

# loop through the postcodes
for postcode in postcodes:
    
    # create a request URL for the postcode
    request_url = "http://api.zoopla.co.uk/api/v1/property_listings.xml?postcode=" + postcode + "&api_key=" + api_key
    
    # add the request URL to the list
    request_urls.append(request_url)
    
# view the request URLs
request_urls

```

My output (cropped so you can't see my API key):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/44st64beusxlcciyp9c4.png)

Now lets loop through these request URLs and get the description and property type for each listing in each postcode, and store them in a dataframe:

```python
# create lists to store descriptions and property types
desc_list = []
prop_types_list = []

# loop through the request URLs to get
# the property descriptions and 
# property types
for request_url in request_urls:
    r = requests.get(request_url)
    root = ET.fromstring(r.content)
    
    for description in root.iter('description'):
        desc_list.append(description.text)
        
    for prop_type in root.iter('property_type'):
        prop_types_list.append(prop_type.text)
        

# create a dataframe of the descriptions and property types 
properties_df = pd.DataFrame({"description":desc_list, "property_type":prop_types_list})

# view the updated dataframe
properties_df\
.style.set_properties(subset=['description'], **{'width': '800px'}) \
.hide_index()       

```

My output:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sp9ioknfpjhvb80x5jn5.png)

You could make the data frame more useful by adding the postcodes and other information from the XML such as the street name, post town, county, number of bedrooms and much more. Then you could extend the fun and do some data analysis on it and create some data visualisations. If you want some help getting started with text analysis then [this tutorial](https://dev.to/nicfoxds/how-to-analyse-clean-text-data-in-python-2hb9) might help, and if you'd like some tips on how to create good-looking charts in python you may like [this tutorial](https://dev.to/nicfoxds/how-to-make-better-looking-charts-in-python-1h3h).