Returning nested attributes from XML using Beautiful Soup

Viewed 61

I have the following code which gets me close to where I want to be, but I want to access certain nested data within the period I have printed. The code:

import requests
from bs4 import BeautifulSoup
import datetime
today = str(datetime.date.today() + datetime.timedelta(days=1))

url = 'https://www.yr.no/place/Norway/Oslo/Oslo/Oslo/forecast.xml'

document = requests.get(url)

soup= BeautifulSoup(document.content, features='html.parser')

period = soup.find(attrs={'from':today + 'T12:00:00'})

print(period)

This gives me the following output (or similar to this basically as the days change):

<time from="2021-04-19T12:00:00" period="2" to="2021-04-19T18:00:00">
<!-- Valid from 2021-04-19T12:00:00 to 2021-04-19T18:00:00 -->
<symbol name="Clear sky" number="1" numberex="1" var="01d"></symbol>
<precipitation value="0"></precipitation>
<!-- Valid at 2021-04-19T12:00:00 -->
<winddirection code="WSW" deg="245.9" name="West-southwest"></winddirection>
<windspeed mps="1.8" name="Light breeze"></windspeed>
<temperature unit="celsius" value="14"></temperature>
<pressure unit="hPa" value="1028.4"></pressure>
</time>

I now want to drill down further to access the following:

  • temperature value (eg. 14)
  • temperature unit (eg. celsius)
  • precipitation value (eg. 0)

I don't know how to drill down further (the reason for initially getting a particular date/period is that there are multiple on the XML, so need to first get the proper period, then drill down to the details of that period).

2 Answers

Use period.precipitation and period.temperature to access your tags:

import requests
from bs4 import BeautifulSoup
import datetime

today = str(datetime.date.today() + datetime.timedelta(days=1))

url = "https://www.yr.no/place/Norway/Oslo/Oslo/Oslo/forecast.xml"

document = requests.get(url)

soup = BeautifulSoup(document.content, features="html.parser")
city = soup.find("name")

period = soup.find(attrs={"from": today + "T12:00:00"})

print("Temperature:", period.temperature["value"])
print("Temperature Unit:", period.temperature["unit"])
print("Precipitation Value:", period.precipitation["value"])

Prints:

Temperature: 14
Temperature Unit: celsius
Precipitation Value: 0

Okay I figured this out on my own in the end - and just in case anyone is googling and comes across this page... here's my solution:

from bs4 import BeautifulSoup
import datetime
today = str(datetime.date.today() + datetime.timedelta(days=1))

url = 'https://www.yr.no/place/Norway/Oslo/Oslo/Oslo/forecast.xml'

document = requests.get(url)

soup= BeautifulSoup(document.content, features='html.parser')
city = soup.find("name")

period = soup.find(attrs={'from':today + 'T12:00:00'})

precip = period.find('precipitation')['value']
temp_unit = period.find('temperature')['unit']
temp_value = period.find('temperature')['value']
city = soup.find("name").get_text()

print(city,'has the following forecast for',today+':\nPrecipitation:',precip+'mm\nTemperature:',temp_value,temp_unit)
Related