Getting current weather data using OpenWeatherMap API











up vote
7
down vote

favorite












I would really appreciate if someone could take a look at this code. I am not very advanced, so ANY kind of feedback and critique would be precious to me.



What this program is supposed to do is to go to a given URL, download the list of cities, for which it will download the data, based on a https://openweathermap.org/api . It should be run on a regular basis and write all of the results to the CSV file.



It is divided into two parts. The first one consists only of the scheduler, final function which is being run by it and the list of columns I want to get as the final result.



Code is written for Python 3.6.



from API.helpers import get_weather_data, json_to_df, create_dict
import schedule, time

URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'
columns = ["name","sys.country","main.temp",
"main.humidity","main.pressure",
"visibility", "wind.speed"]
#Writing results to CSV
def weather_api(URL):
dict = create_dict(URL)
for city, code in dict.items():
data = get_weather_data(city, code)
json_to_df(data, columns)
schedule.every().day.at("10:30").do(weather_api, URL)
while True:
schedule.run_pending()
time.sleep(1)


Here is the second part, which is my "helper" file.



import json
import requests
from pandas.io.json import json_normalize
import pandas as pd
import os
import requests
import csv
api_key = "xxxxxxxxxxxxxxxxxxxxxxx"

#function to build api requests
def build_request(city, code):
base_url = "http://api.openweathermap.org/data/2.5/weather?"
complete_url = base_url + "appid=" + api_key + "&q=" + city +"," + code
return complete_url

#function to get weather data
def get_weather_data(city, code):
url = build_request(city, code)
try:
response = requests.get(url)
response.status_code
except requests.exceptions.HTTPError:
print('Error occured while downloading data')
except requests.exceptions.URLError:
print('Error occured while downloading data')
citydataJSON = response.text
citydata = json.loads(citydataJSON)
return citydata

def json_to_df(data, columns):
df = pd.DataFrame.from_dict(json_normalize(data), orient='columns')
new_df = df[columns]
new_df.insert(0, 'TimeStamp', pd.datetime.now().replace(microsecond=0))
if not os.path.isfile('weather.csv'):
return new_df.to_csv('weather.csv', header='column_names', index=False)
else:
return new_df.to_csv('weather.csv', mode='a', header=False, index=False)
#creating a dictionary of cities and city codes(based on the CSV file downloaded from a given URL
def create_dict(URL):
with requests.Session() as s:
dict = {}
download = s.get(URL)
decoded_content = download.content.decode('utf-8')
cs = csv.reader(decoded_content.splitlines(), delimiter=',')
next(cs, None)
my_list = list(cs)
for row in my_list:
dict[row[0]] = row[1]
return dict









share|improve this question
























  • What Python version did you write this for?
    – Mast
    Sep 28 at 11:45






  • 1




    @Graipher Oops, my misunderstanding.
    – 200_success
    Sep 28 at 15:13















up vote
7
down vote

favorite












I would really appreciate if someone could take a look at this code. I am not very advanced, so ANY kind of feedback and critique would be precious to me.



What this program is supposed to do is to go to a given URL, download the list of cities, for which it will download the data, based on a https://openweathermap.org/api . It should be run on a regular basis and write all of the results to the CSV file.



It is divided into two parts. The first one consists only of the scheduler, final function which is being run by it and the list of columns I want to get as the final result.



Code is written for Python 3.6.



from API.helpers import get_weather_data, json_to_df, create_dict
import schedule, time

URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'
columns = ["name","sys.country","main.temp",
"main.humidity","main.pressure",
"visibility", "wind.speed"]
#Writing results to CSV
def weather_api(URL):
dict = create_dict(URL)
for city, code in dict.items():
data = get_weather_data(city, code)
json_to_df(data, columns)
schedule.every().day.at("10:30").do(weather_api, URL)
while True:
schedule.run_pending()
time.sleep(1)


Here is the second part, which is my "helper" file.



import json
import requests
from pandas.io.json import json_normalize
import pandas as pd
import os
import requests
import csv
api_key = "xxxxxxxxxxxxxxxxxxxxxxx"

#function to build api requests
def build_request(city, code):
base_url = "http://api.openweathermap.org/data/2.5/weather?"
complete_url = base_url + "appid=" + api_key + "&q=" + city +"," + code
return complete_url

#function to get weather data
def get_weather_data(city, code):
url = build_request(city, code)
try:
response = requests.get(url)
response.status_code
except requests.exceptions.HTTPError:
print('Error occured while downloading data')
except requests.exceptions.URLError:
print('Error occured while downloading data')
citydataJSON = response.text
citydata = json.loads(citydataJSON)
return citydata

def json_to_df(data, columns):
df = pd.DataFrame.from_dict(json_normalize(data), orient='columns')
new_df = df[columns]
new_df.insert(0, 'TimeStamp', pd.datetime.now().replace(microsecond=0))
if not os.path.isfile('weather.csv'):
return new_df.to_csv('weather.csv', header='column_names', index=False)
else:
return new_df.to_csv('weather.csv', mode='a', header=False, index=False)
#creating a dictionary of cities and city codes(based on the CSV file downloaded from a given URL
def create_dict(URL):
with requests.Session() as s:
dict = {}
download = s.get(URL)
decoded_content = download.content.decode('utf-8')
cs = csv.reader(decoded_content.splitlines(), delimiter=',')
next(cs, None)
my_list = list(cs)
for row in my_list:
dict[row[0]] = row[1]
return dict









share|improve this question
























  • What Python version did you write this for?
    – Mast
    Sep 28 at 11:45






  • 1




    @Graipher Oops, my misunderstanding.
    – 200_success
    Sep 28 at 15:13













up vote
7
down vote

favorite









up vote
7
down vote

favorite











I would really appreciate if someone could take a look at this code. I am not very advanced, so ANY kind of feedback and critique would be precious to me.



What this program is supposed to do is to go to a given URL, download the list of cities, for which it will download the data, based on a https://openweathermap.org/api . It should be run on a regular basis and write all of the results to the CSV file.



It is divided into two parts. The first one consists only of the scheduler, final function which is being run by it and the list of columns I want to get as the final result.



Code is written for Python 3.6.



from API.helpers import get_weather_data, json_to_df, create_dict
import schedule, time

URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'
columns = ["name","sys.country","main.temp",
"main.humidity","main.pressure",
"visibility", "wind.speed"]
#Writing results to CSV
def weather_api(URL):
dict = create_dict(URL)
for city, code in dict.items():
data = get_weather_data(city, code)
json_to_df(data, columns)
schedule.every().day.at("10:30").do(weather_api, URL)
while True:
schedule.run_pending()
time.sleep(1)


Here is the second part, which is my "helper" file.



import json
import requests
from pandas.io.json import json_normalize
import pandas as pd
import os
import requests
import csv
api_key = "xxxxxxxxxxxxxxxxxxxxxxx"

#function to build api requests
def build_request(city, code):
base_url = "http://api.openweathermap.org/data/2.5/weather?"
complete_url = base_url + "appid=" + api_key + "&q=" + city +"," + code
return complete_url

#function to get weather data
def get_weather_data(city, code):
url = build_request(city, code)
try:
response = requests.get(url)
response.status_code
except requests.exceptions.HTTPError:
print('Error occured while downloading data')
except requests.exceptions.URLError:
print('Error occured while downloading data')
citydataJSON = response.text
citydata = json.loads(citydataJSON)
return citydata

def json_to_df(data, columns):
df = pd.DataFrame.from_dict(json_normalize(data), orient='columns')
new_df = df[columns]
new_df.insert(0, 'TimeStamp', pd.datetime.now().replace(microsecond=0))
if not os.path.isfile('weather.csv'):
return new_df.to_csv('weather.csv', header='column_names', index=False)
else:
return new_df.to_csv('weather.csv', mode='a', header=False, index=False)
#creating a dictionary of cities and city codes(based on the CSV file downloaded from a given URL
def create_dict(URL):
with requests.Session() as s:
dict = {}
download = s.get(URL)
decoded_content = download.content.decode('utf-8')
cs = csv.reader(decoded_content.splitlines(), delimiter=',')
next(cs, None)
my_list = list(cs)
for row in my_list:
dict[row[0]] = row[1]
return dict









share|improve this question















I would really appreciate if someone could take a look at this code. I am not very advanced, so ANY kind of feedback and critique would be precious to me.



What this program is supposed to do is to go to a given URL, download the list of cities, for which it will download the data, based on a https://openweathermap.org/api . It should be run on a regular basis and write all of the results to the CSV file.



It is divided into two parts. The first one consists only of the scheduler, final function which is being run by it and the list of columns I want to get as the final result.



Code is written for Python 3.6.



from API.helpers import get_weather_data, json_to_df, create_dict
import schedule, time

URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'
columns = ["name","sys.country","main.temp",
"main.humidity","main.pressure",
"visibility", "wind.speed"]
#Writing results to CSV
def weather_api(URL):
dict = create_dict(URL)
for city, code in dict.items():
data = get_weather_data(city, code)
json_to_df(data, columns)
schedule.every().day.at("10:30").do(weather_api, URL)
while True:
schedule.run_pending()
time.sleep(1)


Here is the second part, which is my "helper" file.



import json
import requests
from pandas.io.json import json_normalize
import pandas as pd
import os
import requests
import csv
api_key = "xxxxxxxxxxxxxxxxxxxxxxx"

#function to build api requests
def build_request(city, code):
base_url = "http://api.openweathermap.org/data/2.5/weather?"
complete_url = base_url + "appid=" + api_key + "&q=" + city +"," + code
return complete_url

#function to get weather data
def get_weather_data(city, code):
url = build_request(city, code)
try:
response = requests.get(url)
response.status_code
except requests.exceptions.HTTPError:
print('Error occured while downloading data')
except requests.exceptions.URLError:
print('Error occured while downloading data')
citydataJSON = response.text
citydata = json.loads(citydataJSON)
return citydata

def json_to_df(data, columns):
df = pd.DataFrame.from_dict(json_normalize(data), orient='columns')
new_df = df[columns]
new_df.insert(0, 'TimeStamp', pd.datetime.now().replace(microsecond=0))
if not os.path.isfile('weather.csv'):
return new_df.to_csv('weather.csv', header='column_names', index=False)
else:
return new_df.to_csv('weather.csv', mode='a', header=False, index=False)
#creating a dictionary of cities and city codes(based on the CSV file downloaded from a given URL
def create_dict(URL):
with requests.Session() as s:
dict = {}
download = s.get(URL)
decoded_content = download.content.decode('utf-8')
cs = csv.reader(decoded_content.splitlines(), delimiter=',')
next(cs, None)
my_list = list(cs)
for row in my_list:
dict[row[0]] = row[1]
return dict






python python-3.x api






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Sep 28 at 15:24









Mast

7,43863686




7,43863686










asked Sep 28 at 11:00









Grevioos

362




362












  • What Python version did you write this for?
    – Mast
    Sep 28 at 11:45






  • 1




    @Graipher Oops, my misunderstanding.
    – 200_success
    Sep 28 at 15:13


















  • What Python version did you write this for?
    – Mast
    Sep 28 at 11:45






  • 1




    @Graipher Oops, my misunderstanding.
    – 200_success
    Sep 28 at 15:13
















What Python version did you write this for?
– Mast
Sep 28 at 11:45




What Python version did you write this for?
– Mast
Sep 28 at 11:45




1




1




@Graipher Oops, my misunderstanding.
– 200_success
Sep 28 at 15:13




@Graipher Oops, my misunderstanding.
– 200_success
Sep 28 at 15:13










2 Answers
2






active

oldest

votes

















up vote
2
down vote













Your code is very nicely split into functions. As a next step I would split it to classes. What you want to do is




  1. Collect the data for a given city

  2. Convert it into a schema that fits your purposes and write it to a file


In my opinion, the scheduling of this job should be done elsewhere, e.g. cron



Although the +-sign concatenates strings correctly it is not the most readable way to do it. There are many ways to format strings in Python3 and I tend to use f-strings.



Pandas is a great library for data analysis and data "wrangling" but to use it to write csv files is simply an overkill. Usually, you want to keep your virtual environmets as small as possible and use the standard library as much as possible. In this case the csv library is all you need.



I think you got somehow lost when modifying the API response. There is absolutely no need to convert it from dictionary to json and then back to tabular form. Simply use the dictionary that requests gives you, get the data you need and write it to a file.



Here's my code:



from os.path import isfile
from io import StringIO
from datetime import datetime
from csv import DictWriter
import requests


URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'

class CityWeatherCollector(object):
"""Class to collect weather information for a given city from openweathermap.org
"""

base_url = "http://api.openweathermap.org/data/2.5/weather?"
apikey = 'xxxxxxxxxxxxxxxxxxxxxxx'

def __init__(self, city, code):
self.city = city
self.code = code

@property
def full_url(self):
return self.base_url + f"appid={self.apikey}&q={self.city},{self.code}"

def fetch_data(self):
response = requests.get(self.full_url)
if response.status_code == 200:
#returns a dictionary
return response.json()
else:
raise WeatherCollectionError(f"Response from API was: {response.status_code}")


class WeatherCollectionError(Exception):
pass


class WeatherDataWriter(object):

def __init__(self, full_filepath):
self.full_filepath = full_filepath

class WeatherData(object):
"""Class for a representation of the data"""

def __init__(self, name, country, temp, humidity, pressure, visibility, wind_speed, timestamp=datetime.now()):
self.name = name
self.country = country
self.temp = temp
self.humidity = humidity
self.pressure = pressure
self.visibility = visibility
self.wind_speed = wind_speed
self.timestamp = timestamp

@staticmethod
def create_from_json(json_dict, timestamp=datetime.now()):
return WeatherData(
name=json_dict['name'],
country=json_dict['sys']['country'],
temp=json_dict['main']['temp'],
humidity=json_dict['main']['humidity'],
pressure=json_dict['main']['pressure'],
visibility=json_dict['visibility'],
wind_speed=json_dict['wind']['speed'],
timestamp=timestamp
)

def write_one(self, outfile):
weather_data = self.__dict__
# if file exists, append
csv_writer = DictWriter(
out_file,
fieldnames=list(weather_data.keys()),
delimiter=',',
lineterminator='n'
)
#if the file is empty write header
if outfile.tell() == 0:
csv_writer.writeheader()
csv_writer.writerow(weather_data)


def get_cities(url=URL):
response = requests.get(url)
if response.status_code == 200:
decoded_response = StringIO(response.content.decode('utf8'))
# pop the headings
next(decoded_response)
for line in decoded_response:
city, code = tuple(line.strip().split(','))
yield CityWeatherCollector(city, code)


if __name__ == '__main__':
timestamp = datetime.now()
with open('data.csv', 'a') as out_file:
for collector in get_cities(URL):
# add error handling
full_data = collector.fetch_data()
data = WeatherData.create_from_json(json_dict=full_data, timestamp=timestamp)
data.write_one(out_file)





share|improve this answer








New contributor




kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    up vote
    1
    down vote













    Nice project! I would bring another point not touched by kaidokuupa:



    You should follow PEP8 which is the official style guide for writing Python. It's a set of guideline to write code readable by others, which is very important when you will be working on open source project and/or in an enterprise environment.



    To help you conform to this standard, you can use what is called "Linter" which is a software telling you if you follow the standard (or you can configure it to implement your own standard most of the time). Example of linter for Python are flake8, Black (this one also rewrite your code), Pylint and many more I'm not aware of probably.



    Using a linter can be integrated with a Continuous Integration tool when you use your favorite CVS (Git, Mercurial, SVN ...)



    Another point is your comments should describe the 'Why' not 'What'.
    For example



    #function to get weather data
    def get_weather_data(city, code):
    ...


    This comment is not very helpful. And to comment function/method you should probably use docstring instead.
    A good article on writing code comment here by one of the founders of StackOverflow.com.






    share|improve this answer





















      Your Answer





      StackExchange.ifUsing("editor", function () {
      return StackExchange.using("mathjaxEditing", function () {
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      });
      });
      }, "mathjax-editing");

      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "196"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














       

      draft saved


      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f204524%2fgetting-current-weather-data-using-openweathermap-api%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      2
      down vote













      Your code is very nicely split into functions. As a next step I would split it to classes. What you want to do is




      1. Collect the data for a given city

      2. Convert it into a schema that fits your purposes and write it to a file


      In my opinion, the scheduling of this job should be done elsewhere, e.g. cron



      Although the +-sign concatenates strings correctly it is not the most readable way to do it. There are many ways to format strings in Python3 and I tend to use f-strings.



      Pandas is a great library for data analysis and data "wrangling" but to use it to write csv files is simply an overkill. Usually, you want to keep your virtual environmets as small as possible and use the standard library as much as possible. In this case the csv library is all you need.



      I think you got somehow lost when modifying the API response. There is absolutely no need to convert it from dictionary to json and then back to tabular form. Simply use the dictionary that requests gives you, get the data you need and write it to a file.



      Here's my code:



      from os.path import isfile
      from io import StringIO
      from datetime import datetime
      from csv import DictWriter
      import requests


      URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'

      class CityWeatherCollector(object):
      """Class to collect weather information for a given city from openweathermap.org
      """

      base_url = "http://api.openweathermap.org/data/2.5/weather?"
      apikey = 'xxxxxxxxxxxxxxxxxxxxxxx'

      def __init__(self, city, code):
      self.city = city
      self.code = code

      @property
      def full_url(self):
      return self.base_url + f"appid={self.apikey}&q={self.city},{self.code}"

      def fetch_data(self):
      response = requests.get(self.full_url)
      if response.status_code == 200:
      #returns a dictionary
      return response.json()
      else:
      raise WeatherCollectionError(f"Response from API was: {response.status_code}")


      class WeatherCollectionError(Exception):
      pass


      class WeatherDataWriter(object):

      def __init__(self, full_filepath):
      self.full_filepath = full_filepath

      class WeatherData(object):
      """Class for a representation of the data"""

      def __init__(self, name, country, temp, humidity, pressure, visibility, wind_speed, timestamp=datetime.now()):
      self.name = name
      self.country = country
      self.temp = temp
      self.humidity = humidity
      self.pressure = pressure
      self.visibility = visibility
      self.wind_speed = wind_speed
      self.timestamp = timestamp

      @staticmethod
      def create_from_json(json_dict, timestamp=datetime.now()):
      return WeatherData(
      name=json_dict['name'],
      country=json_dict['sys']['country'],
      temp=json_dict['main']['temp'],
      humidity=json_dict['main']['humidity'],
      pressure=json_dict['main']['pressure'],
      visibility=json_dict['visibility'],
      wind_speed=json_dict['wind']['speed'],
      timestamp=timestamp
      )

      def write_one(self, outfile):
      weather_data = self.__dict__
      # if file exists, append
      csv_writer = DictWriter(
      out_file,
      fieldnames=list(weather_data.keys()),
      delimiter=',',
      lineterminator='n'
      )
      #if the file is empty write header
      if outfile.tell() == 0:
      csv_writer.writeheader()
      csv_writer.writerow(weather_data)


      def get_cities(url=URL):
      response = requests.get(url)
      if response.status_code == 200:
      decoded_response = StringIO(response.content.decode('utf8'))
      # pop the headings
      next(decoded_response)
      for line in decoded_response:
      city, code = tuple(line.strip().split(','))
      yield CityWeatherCollector(city, code)


      if __name__ == '__main__':
      timestamp = datetime.now()
      with open('data.csv', 'a') as out_file:
      for collector in get_cities(URL):
      # add error handling
      full_data = collector.fetch_data()
      data = WeatherData.create_from_json(json_dict=full_data, timestamp=timestamp)
      data.write_one(out_file)





      share|improve this answer








      New contributor




      kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















        up vote
        2
        down vote













        Your code is very nicely split into functions. As a next step I would split it to classes. What you want to do is




        1. Collect the data for a given city

        2. Convert it into a schema that fits your purposes and write it to a file


        In my opinion, the scheduling of this job should be done elsewhere, e.g. cron



        Although the +-sign concatenates strings correctly it is not the most readable way to do it. There are many ways to format strings in Python3 and I tend to use f-strings.



        Pandas is a great library for data analysis and data "wrangling" but to use it to write csv files is simply an overkill. Usually, you want to keep your virtual environmets as small as possible and use the standard library as much as possible. In this case the csv library is all you need.



        I think you got somehow lost when modifying the API response. There is absolutely no need to convert it from dictionary to json and then back to tabular form. Simply use the dictionary that requests gives you, get the data you need and write it to a file.



        Here's my code:



        from os.path import isfile
        from io import StringIO
        from datetime import datetime
        from csv import DictWriter
        import requests


        URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'

        class CityWeatherCollector(object):
        """Class to collect weather information for a given city from openweathermap.org
        """

        base_url = "http://api.openweathermap.org/data/2.5/weather?"
        apikey = 'xxxxxxxxxxxxxxxxxxxxxxx'

        def __init__(self, city, code):
        self.city = city
        self.code = code

        @property
        def full_url(self):
        return self.base_url + f"appid={self.apikey}&q={self.city},{self.code}"

        def fetch_data(self):
        response = requests.get(self.full_url)
        if response.status_code == 200:
        #returns a dictionary
        return response.json()
        else:
        raise WeatherCollectionError(f"Response from API was: {response.status_code}")


        class WeatherCollectionError(Exception):
        pass


        class WeatherDataWriter(object):

        def __init__(self, full_filepath):
        self.full_filepath = full_filepath

        class WeatherData(object):
        """Class for a representation of the data"""

        def __init__(self, name, country, temp, humidity, pressure, visibility, wind_speed, timestamp=datetime.now()):
        self.name = name
        self.country = country
        self.temp = temp
        self.humidity = humidity
        self.pressure = pressure
        self.visibility = visibility
        self.wind_speed = wind_speed
        self.timestamp = timestamp

        @staticmethod
        def create_from_json(json_dict, timestamp=datetime.now()):
        return WeatherData(
        name=json_dict['name'],
        country=json_dict['sys']['country'],
        temp=json_dict['main']['temp'],
        humidity=json_dict['main']['humidity'],
        pressure=json_dict['main']['pressure'],
        visibility=json_dict['visibility'],
        wind_speed=json_dict['wind']['speed'],
        timestamp=timestamp
        )

        def write_one(self, outfile):
        weather_data = self.__dict__
        # if file exists, append
        csv_writer = DictWriter(
        out_file,
        fieldnames=list(weather_data.keys()),
        delimiter=',',
        lineterminator='n'
        )
        #if the file is empty write header
        if outfile.tell() == 0:
        csv_writer.writeheader()
        csv_writer.writerow(weather_data)


        def get_cities(url=URL):
        response = requests.get(url)
        if response.status_code == 200:
        decoded_response = StringIO(response.content.decode('utf8'))
        # pop the headings
        next(decoded_response)
        for line in decoded_response:
        city, code = tuple(line.strip().split(','))
        yield CityWeatherCollector(city, code)


        if __name__ == '__main__':
        timestamp = datetime.now()
        with open('data.csv', 'a') as out_file:
        for collector in get_cities(URL):
        # add error handling
        full_data = collector.fetch_data()
        data = WeatherData.create_from_json(json_dict=full_data, timestamp=timestamp)
        data.write_one(out_file)





        share|improve this answer








        New contributor




        kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.




















          up vote
          2
          down vote










          up vote
          2
          down vote









          Your code is very nicely split into functions. As a next step I would split it to classes. What you want to do is




          1. Collect the data for a given city

          2. Convert it into a schema that fits your purposes and write it to a file


          In my opinion, the scheduling of this job should be done elsewhere, e.g. cron



          Although the +-sign concatenates strings correctly it is not the most readable way to do it. There are many ways to format strings in Python3 and I tend to use f-strings.



          Pandas is a great library for data analysis and data "wrangling" but to use it to write csv files is simply an overkill. Usually, you want to keep your virtual environmets as small as possible and use the standard library as much as possible. In this case the csv library is all you need.



          I think you got somehow lost when modifying the API response. There is absolutely no need to convert it from dictionary to json and then back to tabular form. Simply use the dictionary that requests gives you, get the data you need and write it to a file.



          Here's my code:



          from os.path import isfile
          from io import StringIO
          from datetime import datetime
          from csv import DictWriter
          import requests


          URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'

          class CityWeatherCollector(object):
          """Class to collect weather information for a given city from openweathermap.org
          """

          base_url = "http://api.openweathermap.org/data/2.5/weather?"
          apikey = 'xxxxxxxxxxxxxxxxxxxxxxx'

          def __init__(self, city, code):
          self.city = city
          self.code = code

          @property
          def full_url(self):
          return self.base_url + f"appid={self.apikey}&q={self.city},{self.code}"

          def fetch_data(self):
          response = requests.get(self.full_url)
          if response.status_code == 200:
          #returns a dictionary
          return response.json()
          else:
          raise WeatherCollectionError(f"Response from API was: {response.status_code}")


          class WeatherCollectionError(Exception):
          pass


          class WeatherDataWriter(object):

          def __init__(self, full_filepath):
          self.full_filepath = full_filepath

          class WeatherData(object):
          """Class for a representation of the data"""

          def __init__(self, name, country, temp, humidity, pressure, visibility, wind_speed, timestamp=datetime.now()):
          self.name = name
          self.country = country
          self.temp = temp
          self.humidity = humidity
          self.pressure = pressure
          self.visibility = visibility
          self.wind_speed = wind_speed
          self.timestamp = timestamp

          @staticmethod
          def create_from_json(json_dict, timestamp=datetime.now()):
          return WeatherData(
          name=json_dict['name'],
          country=json_dict['sys']['country'],
          temp=json_dict['main']['temp'],
          humidity=json_dict['main']['humidity'],
          pressure=json_dict['main']['pressure'],
          visibility=json_dict['visibility'],
          wind_speed=json_dict['wind']['speed'],
          timestamp=timestamp
          )

          def write_one(self, outfile):
          weather_data = self.__dict__
          # if file exists, append
          csv_writer = DictWriter(
          out_file,
          fieldnames=list(weather_data.keys()),
          delimiter=',',
          lineterminator='n'
          )
          #if the file is empty write header
          if outfile.tell() == 0:
          csv_writer.writeheader()
          csv_writer.writerow(weather_data)


          def get_cities(url=URL):
          response = requests.get(url)
          if response.status_code == 200:
          decoded_response = StringIO(response.content.decode('utf8'))
          # pop the headings
          next(decoded_response)
          for line in decoded_response:
          city, code = tuple(line.strip().split(','))
          yield CityWeatherCollector(city, code)


          if __name__ == '__main__':
          timestamp = datetime.now()
          with open('data.csv', 'a') as out_file:
          for collector in get_cities(URL):
          # add error handling
          full_data = collector.fetch_data()
          data = WeatherData.create_from_json(json_dict=full_data, timestamp=timestamp)
          data.write_one(out_file)





          share|improve this answer








          New contributor




          kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          Your code is very nicely split into functions. As a next step I would split it to classes. What you want to do is




          1. Collect the data for a given city

          2. Convert it into a schema that fits your purposes and write it to a file


          In my opinion, the scheduling of this job should be done elsewhere, e.g. cron



          Although the +-sign concatenates strings correctly it is not the most readable way to do it. There are many ways to format strings in Python3 and I tend to use f-strings.



          Pandas is a great library for data analysis and data "wrangling" but to use it to write csv files is simply an overkill. Usually, you want to keep your virtual environmets as small as possible and use the standard library as much as possible. In this case the csv library is all you need.



          I think you got somehow lost when modifying the API response. There is absolutely no need to convert it from dictionary to json and then back to tabular form. Simply use the dictionary that requests gives you, get the data you need and write it to a file.



          Here's my code:



          from os.path import isfile
          from io import StringIO
          from datetime import datetime
          from csv import DictWriter
          import requests


          URL = 'https://pm1aapplicantsdata.blob.core.windows.net/databases/CitiesWeather/CitiesWeather.csv'

          class CityWeatherCollector(object):
          """Class to collect weather information for a given city from openweathermap.org
          """

          base_url = "http://api.openweathermap.org/data/2.5/weather?"
          apikey = 'xxxxxxxxxxxxxxxxxxxxxxx'

          def __init__(self, city, code):
          self.city = city
          self.code = code

          @property
          def full_url(self):
          return self.base_url + f"appid={self.apikey}&q={self.city},{self.code}"

          def fetch_data(self):
          response = requests.get(self.full_url)
          if response.status_code == 200:
          #returns a dictionary
          return response.json()
          else:
          raise WeatherCollectionError(f"Response from API was: {response.status_code}")


          class WeatherCollectionError(Exception):
          pass


          class WeatherDataWriter(object):

          def __init__(self, full_filepath):
          self.full_filepath = full_filepath

          class WeatherData(object):
          """Class for a representation of the data"""

          def __init__(self, name, country, temp, humidity, pressure, visibility, wind_speed, timestamp=datetime.now()):
          self.name = name
          self.country = country
          self.temp = temp
          self.humidity = humidity
          self.pressure = pressure
          self.visibility = visibility
          self.wind_speed = wind_speed
          self.timestamp = timestamp

          @staticmethod
          def create_from_json(json_dict, timestamp=datetime.now()):
          return WeatherData(
          name=json_dict['name'],
          country=json_dict['sys']['country'],
          temp=json_dict['main']['temp'],
          humidity=json_dict['main']['humidity'],
          pressure=json_dict['main']['pressure'],
          visibility=json_dict['visibility'],
          wind_speed=json_dict['wind']['speed'],
          timestamp=timestamp
          )

          def write_one(self, outfile):
          weather_data = self.__dict__
          # if file exists, append
          csv_writer = DictWriter(
          out_file,
          fieldnames=list(weather_data.keys()),
          delimiter=',',
          lineterminator='n'
          )
          #if the file is empty write header
          if outfile.tell() == 0:
          csv_writer.writeheader()
          csv_writer.writerow(weather_data)


          def get_cities(url=URL):
          response = requests.get(url)
          if response.status_code == 200:
          decoded_response = StringIO(response.content.decode('utf8'))
          # pop the headings
          next(decoded_response)
          for line in decoded_response:
          city, code = tuple(line.strip().split(','))
          yield CityWeatherCollector(city, code)


          if __name__ == '__main__':
          timestamp = datetime.now()
          with open('data.csv', 'a') as out_file:
          for collector in get_cities(URL):
          # add error handling
          full_data = collector.fetch_data()
          data = WeatherData.create_from_json(json_dict=full_data, timestamp=timestamp)
          data.write_one(out_file)






          share|improve this answer








          New contributor




          kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          share|improve this answer



          share|improve this answer






          New contributor




          kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          answered 2 days ago









          kaidokuuppa

          1214




          1214




          New contributor




          kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.





          New contributor





          kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.






          kaidokuuppa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.
























              up vote
              1
              down vote













              Nice project! I would bring another point not touched by kaidokuupa:



              You should follow PEP8 which is the official style guide for writing Python. It's a set of guideline to write code readable by others, which is very important when you will be working on open source project and/or in an enterprise environment.



              To help you conform to this standard, you can use what is called "Linter" which is a software telling you if you follow the standard (or you can configure it to implement your own standard most of the time). Example of linter for Python are flake8, Black (this one also rewrite your code), Pylint and many more I'm not aware of probably.



              Using a linter can be integrated with a Continuous Integration tool when you use your favorite CVS (Git, Mercurial, SVN ...)



              Another point is your comments should describe the 'Why' not 'What'.
              For example



              #function to get weather data
              def get_weather_data(city, code):
              ...


              This comment is not very helpful. And to comment function/method you should probably use docstring instead.
              A good article on writing code comment here by one of the founders of StackOverflow.com.






              share|improve this answer

























                up vote
                1
                down vote













                Nice project! I would bring another point not touched by kaidokuupa:



                You should follow PEP8 which is the official style guide for writing Python. It's a set of guideline to write code readable by others, which is very important when you will be working on open source project and/or in an enterprise environment.



                To help you conform to this standard, you can use what is called "Linter" which is a software telling you if you follow the standard (or you can configure it to implement your own standard most of the time). Example of linter for Python are flake8, Black (this one also rewrite your code), Pylint and many more I'm not aware of probably.



                Using a linter can be integrated with a Continuous Integration tool when you use your favorite CVS (Git, Mercurial, SVN ...)



                Another point is your comments should describe the 'Why' not 'What'.
                For example



                #function to get weather data
                def get_weather_data(city, code):
                ...


                This comment is not very helpful. And to comment function/method you should probably use docstring instead.
                A good article on writing code comment here by one of the founders of StackOverflow.com.






                share|improve this answer























                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  Nice project! I would bring another point not touched by kaidokuupa:



                  You should follow PEP8 which is the official style guide for writing Python. It's a set of guideline to write code readable by others, which is very important when you will be working on open source project and/or in an enterprise environment.



                  To help you conform to this standard, you can use what is called "Linter" which is a software telling you if you follow the standard (or you can configure it to implement your own standard most of the time). Example of linter for Python are flake8, Black (this one also rewrite your code), Pylint and many more I'm not aware of probably.



                  Using a linter can be integrated with a Continuous Integration tool when you use your favorite CVS (Git, Mercurial, SVN ...)



                  Another point is your comments should describe the 'Why' not 'What'.
                  For example



                  #function to get weather data
                  def get_weather_data(city, code):
                  ...


                  This comment is not very helpful. And to comment function/method you should probably use docstring instead.
                  A good article on writing code comment here by one of the founders of StackOverflow.com.






                  share|improve this answer












                  Nice project! I would bring another point not touched by kaidokuupa:



                  You should follow PEP8 which is the official style guide for writing Python. It's a set of guideline to write code readable by others, which is very important when you will be working on open source project and/or in an enterprise environment.



                  To help you conform to this standard, you can use what is called "Linter" which is a software telling you if you follow the standard (or you can configure it to implement your own standard most of the time). Example of linter for Python are flake8, Black (this one also rewrite your code), Pylint and many more I'm not aware of probably.



                  Using a linter can be integrated with a Continuous Integration tool when you use your favorite CVS (Git, Mercurial, SVN ...)



                  Another point is your comments should describe the 'Why' not 'What'.
                  For example



                  #function to get weather data
                  def get_weather_data(city, code):
                  ...


                  This comment is not very helpful. And to comment function/method you should probably use docstring instead.
                  A good article on writing code comment here by one of the founders of StackOverflow.com.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 2 days ago









                  Julien Rousé

                  456416




                  456416






























                       

                      draft saved


                      draft discarded



















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f204524%2fgetting-current-weather-data-using-openweathermap-api%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Quarter-circle Tiles

                      build a pushdown automaton that recognizes the reverse language of a given pushdown automaton?

                      Mont Emei