├── api ├── api │ ├── __init__.py │ ├── wsgi.py │ ├── urls.py │ └── settings.py ├── daily │ ├── __init__.py │ ├── apps.py │ ├── admin.py │ ├── serializers.py │ ├── urls.py │ ├── apiviews.py │ └── models.py ├── states │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── serializers.py │ ├── urls.py │ ├── tests.py │ ├── apiviews.py │ └── models.py ├── confirmed │ ├── __init__.py │ ├── apps.py │ ├── admin.py │ ├── serializers.py │ ├── urls.py │ ├── apiviews.py │ └── models.py ├── runtime.txt ├── Procfile ├── callmigrate.py ├── .idea │ ├── vcs.xml │ ├── inspectionProfiles │ │ └── profiles_settings.xml │ ├── modules.xml │ ├── misc.xml │ ├── api.iml │ └── workspace.xml ├── migrateupdate.py ├── manage.py ├── .circle │ └── config.yml └── requirements.txt ├── .idea ├── .gitignore ├── vcs.xml ├── inspectionProfiles │ └── profiles_settings.xml ├── modules.xml ├── misc.xml └── ncovid-19-api.iml ├── ss ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png └── flutterLogo1.png ├── ncovid.dump ├── data_getter ├── updater.py ├── daily_report.py ├── ncovid.csv ├── daily_report.csv ├── getData.py ├── newscraper.py ├── scraper.py └── ua_file.txt ├── LICENSE └── README.md /api/api/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/daily/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/states/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/confirmed/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.6.10 -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /api/Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn api.wsgi --log-file - 2 | clock: python clock.py -------------------------------------------------------------------------------- /ss/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastersam07/ncovid-19-api/HEAD/ss/1.png -------------------------------------------------------------------------------- /ss/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastersam07/ncovid-19-api/HEAD/ss/2.png -------------------------------------------------------------------------------- /ss/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastersam07/ncovid-19-api/HEAD/ss/3.png -------------------------------------------------------------------------------- /ss/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastersam07/ncovid-19-api/HEAD/ss/4.png -------------------------------------------------------------------------------- /ss/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastersam07/ncovid-19-api/HEAD/ss/5.png -------------------------------------------------------------------------------- /ncovid.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastersam07/ncovid-19-api/HEAD/ncovid.dump -------------------------------------------------------------------------------- /ss/flutterLogo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastersam07/ncovid-19-api/HEAD/ss/flutterLogo1.png -------------------------------------------------------------------------------- /api/callmigrate.py: -------------------------------------------------------------------------------- 1 | def callmigrate(): 2 | import os 3 | os.system("python manage.py migrate") 4 | -------------------------------------------------------------------------------- /api/daily/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DailyConfig(AppConfig): 5 | name = 'daily' 6 | -------------------------------------------------------------------------------- /api/daily/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Daily 4 | 5 | admin.site.register(Daily) 6 | -------------------------------------------------------------------------------- /api/states/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Data 4 | 5 | admin.site.register(Data) 6 | -------------------------------------------------------------------------------- /api/confirmed/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ConfirmedConfig(AppConfig): 5 | name = 'confirmed' 6 | -------------------------------------------------------------------------------- /api/confirmed/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | 5 | from .models import Confirmed 6 | 7 | admin.site.register(Confirmed) 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /api/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /api/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /api/confirmed/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from .models import Confirmed 4 | 5 | 6 | class CategorySerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = Confirmed 9 | fields = ('categories', 'values') 10 | -------------------------------------------------------------------------------- /data_getter/updater.py: -------------------------------------------------------------------------------- 1 | from apscheduler.schedulers.background import BackgroundScheduler 2 | from data_getter import getData 3 | 4 | 5 | def start(): 6 | scheduler = BackgroundScheduler() 7 | scheduler.add_job(getData.update_database, 'interval', hours=6) 8 | scheduler.start() 9 | -------------------------------------------------------------------------------- /api/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /api/states/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | from api import migrateupdate 4 | from data_getter import updater 5 | 6 | 7 | class StatesConfig(AppConfig): 8 | name = 'states' 9 | 10 | def ready(self): 11 | updater.start() 12 | migrateupdate.start() 13 | -------------------------------------------------------------------------------- /api/daily/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from .models import Daily 4 | 5 | 6 | class DailySerializer(serializers.ModelSerializer): 7 | 8 | class Meta: 9 | model = Daily 10 | fields = ('id', 'Date', 'No_of_cases', 'No_of_recovered', 'No_of_deaths') 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /api/migrateupdate.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from apscheduler.schedulers.background import BackgroundScheduler 3 | from api import callmigrate 4 | 5 | 6 | def start(): 7 | scheduler = BackgroundScheduler() 8 | scheduler.add_job(callmigrate.update_database, 'interval', hours=6) 9 | scheduler.start() 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /api/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /api/confirmed/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from rest_framework.routers import DefaultRouter 3 | 4 | from .apiviews import CategoryList 5 | 6 | router = DefaultRouter() 7 | router.register('api/confirmed', CategoryList, base_name='states') 8 | 9 | urlpatterns = [ 10 | path("api/confirmed/", CategoryList.as_view(), name="confirmed"), 11 | ] 12 | 13 | # urlpatterns += router.urls 14 | -------------------------------------------------------------------------------- /api/states/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from .models import Data 4 | 5 | 6 | # class CaseSerializer(serializers.ModelSerializer): 7 | # class Meta: 8 | # model = Cases 9 | # fields = '__all__' 10 | # 11 | # 12 | class StateSerializer(serializers.ModelSerializer): 13 | 14 | class Meta: 15 | model = Data 16 | fields = '__all__' 17 | -------------------------------------------------------------------------------- /api/daily/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from rest_framework.routers import DefaultRouter 3 | 4 | from .apiviews import DailyList, DailyDetail 5 | 6 | router = DefaultRouter() 7 | router.register('api/daily', DailyList, base_name='daily') 8 | 9 | urlpatterns = [ 10 | path("api/daily/", DailyList.as_view(), name="daily_list"), 11 | path("api/daily//", DailyDetail.as_view(), name="daily_detail"), 12 | ] 13 | 14 | -------------------------------------------------------------------------------- /api/confirmed/apiviews.py: -------------------------------------------------------------------------------- 1 | from rest_framework.views import APIView 2 | from rest_framework.response import Response 3 | 4 | from .models import Confirmed 5 | from .serializers import CategorySerializer 6 | 7 | 8 | class CategoryList(APIView): 9 | @staticmethod 10 | def get(request): 11 | categories = Confirmed.objects.all() 12 | data = CategorySerializer(categories, many=True).data 13 | return Response(data) 14 | 15 | 16 | -------------------------------------------------------------------------------- /api/api/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for api project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /api/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /api/states/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from rest_framework.routers import DefaultRouter 3 | from .apiviews import StateViewSet 4 | 5 | from .apiviews import StateList, StateDetail # CasesList 6 | 7 | router = DefaultRouter() 8 | router.register('api/states', StateList, base_name='states') 9 | 10 | urlpatterns = [ 11 | path("api/states/", StateList.as_view(), name="states_list"), 12 | path("api/states//", StateDetail.as_view(), name="states_detail"), 13 | # path("api/states//cases/", CasesList.as_view(), name="cases_list"), 14 | ] 15 | 16 | # urlpatterns += router.urls 17 | -------------------------------------------------------------------------------- /api/confirmed/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Confirmed(models.Model): 5 | id = models.IntegerField(primary_key=True) 6 | categories = models.CharField(db_column='Categories', max_length=50, blank=True, 7 | null=True) # Field name made lowercase. 8 | values = models.CharField(db_column='Values', max_length=50, blank=True, null=True) # Field name made lowercase. 9 | 10 | def __str__(self): 11 | return self.categories 12 | 13 | class Meta: 14 | unique_together = ("categories", "values") 15 | managed = False 16 | db_table = 'confirmed' 17 | -------------------------------------------------------------------------------- /api/daily/apiviews.py: -------------------------------------------------------------------------------- 1 | from rest_framework.generics import get_object_or_404 2 | from rest_framework.views import APIView 3 | from rest_framework.response import Response 4 | 5 | from .models import Daily 6 | from .serializers import DailySerializer 7 | 8 | 9 | class DailyList(APIView): 10 | @staticmethod 11 | def get(request): 12 | daily = Daily.objects.all() 13 | data = DailySerializer(daily, many=True).data 14 | return Response(data) 15 | 16 | 17 | class DailyDetail(APIView): 18 | @staticmethod 19 | def get(request, id): 20 | daily = get_object_or_404(Daily, pk=id) 21 | data = DailySerializer(daily).data 22 | return Response(data) 23 | -------------------------------------------------------------------------------- /api/states/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from rest_framework.test import APIRequestFactory, APITestCase 3 | 4 | from states import apiviews 5 | 6 | 7 | class TestState(APITestCase): 8 | def setUp(self): 9 | self.factory = APIRequestFactory() 10 | self.view = apiviews.StateViewSet.as_view({'get': 'list'}) 11 | self.uri = '/api/states/' 12 | 13 | def test_list(self): 14 | request = self.factory.get(self.uri) 15 | response = self.view(request) 16 | self.assertEqual(response.status_code, 200, 17 | 'Expected Response Code 200, received {0} instead.' 18 | .format(response.status_code)) 19 | -------------------------------------------------------------------------------- /.idea/ncovid-19-api.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /data_getter/daily_report.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import psycopg2 3 | from sqlalchemy import create_engine 4 | 5 | df = pd.read_csv("daily_report.csv") 6 | 7 | # add postgres db engine 8 | engine = create_engine('postgresql+psycopg2://postgres:mastersam@localhost/ncovid') 9 | # 10 | # adding df to tables 11 | df.to_sql(con=engine, name='daily', if_exists='replace', index=True, index_label='id') 12 | # 13 | print('Data transferred from df to postgresql successfully!!!') 14 | 15 | # checking the data 16 | print('checking the data...') 17 | conn = psycopg2.connect(host="localhost", database="ncovid", user="postgres", password="mastersam") 18 | cur = conn.cursor() 19 | cur.execute("SELECT * FROM daily") 20 | 21 | rows = cur.fetchall() 22 | 23 | for row in rows: 24 | print(row) 25 | print('Done checking!!!') 26 | 27 | conn.close() 28 | -------------------------------------------------------------------------------- /api/states/apiviews.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics, viewsets 2 | from rest_framework.generics import get_object_or_404 3 | from rest_framework.views import APIView 4 | from rest_framework.response import Response 5 | 6 | from .models import Data 7 | from .serializers import StateSerializer # CaseSerializer 8 | 9 | 10 | class StateList(APIView): 11 | @staticmethod 12 | def get(request): 13 | states = Data.objects.all() 14 | data = StateSerializer(states, many=True).data 15 | return Response(data) 16 | 17 | 18 | class StateDetail(APIView): 19 | @staticmethod 20 | def get(request, id): 21 | state = get_object_or_404(Data, pk=id) 22 | data = StateSerializer(state).data 23 | return Response(data) 24 | 25 | 26 | class StateViewSet(viewsets.ModelViewSet): 27 | queryset = Data.objects.all() 28 | serializer_class = StateSerializer 29 | -------------------------------------------------------------------------------- /data_getter/ncovid.csv: -------------------------------------------------------------------------------- 1 | id,States,No_of_cases,No_on_admission,No_discharged,No_of_deaths 2 | 0,Lagos,"2,041","1,480",528,33 3 | 1,Kano,707,595,79,33 4 | 2,FCT,370,291,72,7 5 | 3,Katsina,224,187,25,12 6 | 4, Bauchi,206,178,25,3 7 | 5,Borno,188,148,20,20 8 | 6,Jigawa,141,134,4,3 9 | 7,Ogun,127,76,46,5 10 | 8,Gombe,119,53,65,1 11 | 9,Kaduna,116,96,17,3 12 | 10,Sokoto,112,59,40,13 13 | 11,Edo,89,59,26,4 14 | 12,Zamfara,73,67,1,5 15 | 13,Oyo,73,55,16,2 16 | 14,Kwara,53,43,9,1 17 | 15,Osun,42,8,30,4 18 | 16,Rivers,33,25,5,3 19 | 17,Kebbi,31,23,5,3 20 | 18,Nasarawa,28,27,0,1 21 | 19,Delta,22,13,6,3 22 | 20,Adamawa,21,17,4,0 23 | 21,Yobe,20,19,0,1 24 | 22,Plateau,20,16,4,0 25 | 23,Ondo,18,6,11,1 26 | 24,Taraba,17,16,1,0 27 | 25,Akwa Ibom,17,3,12,2 28 | 26,Ekiti,15,5,9,1 29 | 27,Enugu,12,10,2,0 30 | 28,Niger,10,8,2,0 31 | 29,Ebonyi,9,9,0,0 32 | 30,Bayelsa,6,3,3,0 33 | 31,Benue,4,4,0,0 34 | 32,Imo,3,2,1,0 35 | 33,Anambra,2,1,1,0 36 | 34,Abia,2,1,1,0 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Abada Samuel Oghenero. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /api/daily/models.py: -------------------------------------------------------------------------------- 1 | # This is an auto-generated Django model module. 2 | # You'll have to do the following manually to clean this up: 3 | # * Rearrange models' order 4 | # * Make sure each model has one field with primary_key=True 5 | # * Make sure each ForeignKey has `on_delete` set to the desired behavior. 6 | # * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table 7 | # Feel free to rename the models, but don't rename db_table values or field names. 8 | from django.db import models 9 | 10 | 11 | class Daily(models.Model): 12 | id = models.IntegerField(primary_key=True) 13 | Date = models.CharField(db_column='Date', max_length=50, blank=True, null=False) # Field name 14 | # made lowercase. 15 | No_of_cases = models.CharField(db_column='Confirmed_Cases', max_length=50, blank=True, null=True) # Field name made 16 | # lowercase. 17 | No_of_recovered = models.CharField(db_column='Recovered', max_length=50, blank=True, null=True) # Field 18 | # name made lowercase . 19 | No_of_deaths = models.CharField(db_column='Deaths', max_length=50, blank=True, null=True) # Field name made 20 | # lowercase. 21 | 22 | def __str__(self): 23 | return self.Date 24 | 25 | class Meta: 26 | managed = False 27 | db_table = 'daily' 28 | -------------------------------------------------------------------------------- /api/.idea/api.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /api/.circle/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | # specify the version you desire here 6 | - image: circleci/python:3.6.1 7 | 8 | 9 | working_directory: ~/repo 10 | 11 | steps: 12 | - checkout 13 | 14 | # Download and cache dependencies 15 | - restore_cache: 16 | keys: 17 | - v1-dependencies-{{ checksum "api/requirements.txt" }} 18 | # fallback to using the latest cache if no exact match is found 19 | - v1-dependencies- 20 | 21 | - run: 22 | name: install dependencies 23 | command: | 24 | python3 -m venv venv 25 | . venv/bin/activate 26 | pip install -r api/requirements.txt 27 | 28 | - save_cache: 29 | paths: 30 | - ./venv 31 | key: v1-dependencies-{{ checksum "requirements.txt" }} 32 | 33 | # run tests! 34 | # this example uses Django's built-in test-runner 35 | # other common Python testing frameworks include pytest and nose 36 | # https://pytest.org 37 | # https://nose.readthedocs.io 38 | - run: 39 | name: run tests 40 | command: | 41 | . venv/bin/activate 42 | cd api 43 | python manage.py test 44 | 45 | - store_artifacts: 46 | path: test-reports 47 | destination: test-reports 48 | 49 | -------------------------------------------------------------------------------- /data_getter/daily_report.csv: -------------------------------------------------------------------------------- 1 | Date,Confirmed_Cases,Recovered,Deaths 2 | 2/27/2020,1,0,0 3 | 2/28/2020,1,0,0 4 | 2/29/2020,1,0,0 5 | 3/1/2020,1,0,0 6 | 3/2/2020,1,0,0 7 | 3/3/2020,1,0,0 8 | 3/4/2020,1,0,0 9 | 3/5/2020,1,0,0 10 | 3/6/2020,1,0,0 11 | 3/7/2020,1,0,0 12 | 3/8/2020,1,0,0 13 | 3/9/2020,2,0,0 14 | 3/10/2020,2,0,0 15 | 3/11/2020,2,0,0 16 | 3/12/2020,2,0,0 17 | 3/13/2020,2,0,0 18 | 3/14/2020,2,1,0 19 | 3/15/2020,2,1,0 20 | 3/16/2020,3,1,0 21 | 3/17/2020,3,1,0 22 | 3/18/2020,8,1,0 23 | 3/19/2020,12,1,0 24 | 3/20/2020,22,0,0 25 | 3/21/2020,25,2,0 26 | 3/22/2020,30,2,0 27 | 3/23/2020,40,2,1 28 | 3/24/2020,44,2,1 29 | 3/25/2020,51,2,1 30 | 3/26/2020,65,3,1 31 | 3/27/2020,81,3,1 32 | 3/28/2020,97,3,1 33 | 3/29/2020,111,3,1 34 | 3/30/2020,131,8,2 35 | 3/31/2020,139,9,2 36 | 4/1/2020,174,9,2 37 | 4/2/2020,184,20,2 38 | 4/3/2020,209,25,4 39 | 4/4/2020,214,25,4 40 | 4/5/2020,232,33,5 41 | 4/6/2020,238,35,5 42 | 4/7/2020,254,44,6 43 | 4/8/2020,276,44,6 44 | 4/9/2020,288,51,7 45 | 4/10/2020,305,58,7 46 | 4/11/2020,318,70,10 47 | 4/12/2020,323,85,10 48 | 4/13/2020,343,91,10 49 | 4/14/2020,373,99,11 50 | 4/15/2020,407,128,12 51 | 4/16/2020,442,152,13 52 | 4/17/2020,493,159,17 53 | 4/18/2020,542,166,19 54 | 4/19/2020,627,170,21 55 | 4/20/2020,665,188,22 56 | 4/21/2020,782,197,25 57 | 4/22/2020,873,197,28 58 | 4/23/2020,981,197,31 59 | 4/24/2020,1095,208,32 60 | 4/25/2020,1182,222,35 61 | 4/26/2020,1273,239,40 62 | 4/27/2020,1337,251,40 63 | 4/28/2020,1532,255,44 64 | 4/29/2020,1728,307,51 65 | 4/30/2020,1932,319,58 66 | 5/1/2020,2170,351,68 67 | 5/2/2020,2388,385,85 68 | 5/3/2020,2558,393,87 69 | 5/4/2020,2950,481,98 70 | 5/5/2020,2802,417,93 71 | 5/6/2020,3145,534,103 72 | 5/7/2020,3526,601,107 73 | 5/8/2020,3912,679,117 74 | 5/9/2020,4151,745,128 75 | 5/10/2020,4399,778,143 76 | 5/11/2020,4641,902,150 77 | 5/12/2020,4787,959,158 78 | 5/13/2020,4971,1070,164 -------------------------------------------------------------------------------- /api/api/urls.py: -------------------------------------------------------------------------------- 1 | """api URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, re_path, include 18 | from rest_framework_swagger.views import get_swagger_view 19 | from rest_framework.documentation import include_docs_urls 20 | from django_otp.admin import OTPAdminSite 21 | 22 | 23 | admin.site.__class__ = OTPAdminSite 24 | 25 | 26 | class OTPAdmin(OTPAdminSite): 27 | pass 28 | 29 | 30 | from django.contrib.auth.models import User 31 | from django_otp.plugins.otp_totp.models import TOTPDevice 32 | 33 | admin_site = OTPAdmin(name='OTPAdmin') 34 | admin_site.register(User) 35 | admin_site.register(TOTPDevice) 36 | 37 | schema_view = get_swagger_view(title='Nigeria Covid-19 API') 38 | api_doc = include_docs_urls(title='Nigeria Covid-19 API') 39 | 40 | urlpatterns = [ 41 | path('somenewurl/', admin_site.urls), 42 | path('some/', admin.site.urls), 43 | path(r'api/docs/', schema_view), 44 | path('admin/', include('admin_honeypot.urls', namespace='admin_honeypot')), 45 | re_path(r'^', include('states.urls')), 46 | re_path(r'^', include('confirmed.urls')), 47 | re_path(r'^', include('daily.urls')), 48 | path(r'', api_doc), 49 | ] 50 | -------------------------------------------------------------------------------- /data_getter/getData.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | import pandas as pd 4 | from sqlalchemy import create_engine 5 | 6 | 7 | def update_database(): 8 | headers = { 9 | # # 'user-agent': user_agent, 10 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) ' 11 | 'Chrome/56.0.2924.87 Safari/537.36', 12 | } 13 | url = 'https://covid19.ncdc.gov.ng' 14 | 15 | # make a request with headers 16 | r = requests.get(url, headers=headers, timeout=5) 17 | 18 | print(r.status_code) # 200 for success 19 | 20 | content = BeautifulSoup(r.text, 'lxml') # parsing content 21 | 22 | My_table = content.find('table', {'id': 'custom3'}) # table to be scrapped having id as custom3 23 | 24 | links = My_table.findAll('b') # all cases data seems to be in b tags 25 | stately = My_table.findAll('td') # all state name seems to be in td tags 26 | 27 | # save cases data to list 28 | cases = [] 29 | for link in links: 30 | cases.append(link.text) 31 | 32 | # save states data to list 33 | states = [] 34 | for state in stately: 35 | states.append(state.text) 36 | 37 | # escape string appears in list in odd indexes 38 | # get states with even indexes 39 | somes = [] 40 | for i in range(0, len(states), 2): 41 | somes.append(states[i]) 42 | 43 | # set length to be 37 due to irregularities 44 | 45 | # take data to pandas dataframe 46 | df = pd.DataFrame() 47 | df['States'] = somes[0:37] 48 | df['Cases'] = cases[0:37] 49 | 50 | print('Dataframe\n', df) 51 | 52 | # save data to csv 53 | df.to_csv(r'ncovid.csv', index=True, index_label='id') 54 | print("SUCCESS!!!") 55 | 56 | # create sqlite engine 57 | # engine = create_engine(r'db.sqlite3') 58 | 59 | # add postgres db engine 60 | engine = create_engine('postgresql+psycopg2://postgres:mastersam@localhost/ncovid') 61 | 62 | # adding df to tables 63 | df.to_sql(con=engine, name='data', if_exists='replace', index=True, index_label='id') 64 | 65 | print('Data transferred from df to postgres successfully!!!') 66 | -------------------------------------------------------------------------------- /api/states/models.py: -------------------------------------------------------------------------------- 1 | # from django.db import models 2 | # 3 | # 4 | # # from django.db import models 5 | # # from django.contrib.auth.models import User 6 | # # 7 | # # 8 | # # class State(models.Model): 9 | # # name = models.CharField(max_length=100) 10 | # # 11 | # # def __str__(self): 12 | # # return self.name 13 | # # 14 | # # 15 | # # class Cases(models.Model): 16 | # # states = models.ForeignKey(State, related_name='numbers', on_delete=models.CASCADE) 17 | # # cases = models.CharField(max_length=100) 18 | # # 19 | # # def __str__(self): 20 | # # return self.cases 21 | # # 22 | # 23 | # class StatesCases(models.Model): 24 | # id = models.IntegerField(primary_key=True) 25 | # cases = models.CharField(max_length=100) 26 | # states_id = models.IntegerField() 27 | # 28 | # class Meta: 29 | # managed = False 30 | # db_table = 'states_cases' 31 | # 32 | # 33 | # class StatesState(models.Model): 34 | # name = models.CharField(max_length=100) 35 | # 36 | # class Meta: 37 | # managed = False 38 | # db_table = 'states_state' 39 | 40 | # This is an auto-generated Django model module. 41 | # You'll have to do the following manually to clean this up: 42 | # * Rearrange models' order 43 | # * Make sure each model has one field with primary_key=True 44 | # * Make sure each ForeignKey has `on_delete` set to the desired behavior. 45 | # * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table 46 | # Feel free to rename the models, but don't rename db_table values or field names. 47 | from django.db import models 48 | 49 | 50 | class Data(models.Model): 51 | id = models.IntegerField(primary_key=True) 52 | States = models.CharField(db_column='States', max_length=50, blank=True, null=True) # Field name made lowercase. 53 | No_of_cases = models.CharField(db_column='No_of_cases', max_length=50, blank=True, null=True) # Field name made 54 | # lowercase. 55 | No_on_admission = models.CharField(db_column='No_on_admission', max_length=50, blank=True, null=True) # Field 56 | # name made 57 | # lowercase. 58 | No_discharged = models.CharField(db_column='No_discharged', max_length=50, blank=True, null=True) # Field name made 59 | # lowercase. 60 | No_of_deaths = models.CharField(db_column='No_of_deaths', max_length=50, blank=True,null=True) # Field name made 61 | # lowercase. 62 | 63 | def __str__(self): 64 | return self.States 65 | 66 | class Meta: 67 | managed = False 68 | db_table = 'data' 69 | -------------------------------------------------------------------------------- /data_getter/newscraper.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | import psycopg2 4 | from bs4 import BeautifulSoup 5 | import requests 6 | from sqlalchemy import create_engine # db engine 7 | import pandas as pd 8 | 9 | headers = { 10 | # # 'user-agent': user_agent, 11 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) ' 12 | 'Chrome/56.0.2924.87 Safari/537.36', 13 | } 14 | 15 | # make a request with headers 16 | r = requests.get('https://covid19.ncdc.gov.ng', headers=headers, timeout=15) 17 | 18 | # print(r.status_code) # 200 for success 19 | 20 | content = BeautifulSoup(r.text, 'lxml') # parsing content 21 | 22 | My_table = content.findAll('div', {'class': 'col-xs-3 col-md-3 col-xl-3'}) # div for all data 23 | Samples = content.find('div', {'class': 'col-md-12 col-xl-3'}) # div for total tested sapmles 24 | 25 | # print(Samples.find('span').text) 26 | # assign each div 27 | confirmed_cases = My_table[0] 28 | active_cases = My_table[1] 29 | discharged_cases = My_table[2] 30 | death = My_table[3] 31 | 32 | # get the category data 33 | sample_cat = Samples.find('h6').text 34 | confirmed_cat = confirmed_cases.find('h6').text 35 | active_cat = active_cases.find('h6').text 36 | discharged_cat = discharged_cases.find('h6').text 37 | death_cat = death.find('h6').text 38 | 39 | # get the figures data 40 | sample_data = Samples.find('span').text 41 | confirmed_data = confirmed_cases.find('h2').text 42 | active_data = active_cases.find('h2').text 43 | discharged_data = discharged_cases.find('h2').text 44 | death_data = death.find('h2').text 45 | 46 | # check data 47 | print(sample_cat, sample_data) 48 | print(confirmed_cat, confirmed_data) 49 | print(active_cat, active_data) 50 | print(discharged_cat, discharged_data) 51 | print(death_cat, death_data) 52 | 53 | # pass all outputs to list 54 | somes = [sample_cat, confirmed_cat, discharged_cat, death_cat] 55 | cases = [sample_data, confirmed_data, discharged_data, death_data] 56 | 57 | # print(cases) 58 | # print(somes) 59 | 60 | # take data to pandas dataframe 61 | df = pd.DataFrame() 62 | df['Categories'] = somes 63 | df['Values'] = cases 64 | 65 | print('Dataframe\n', df) 66 | 67 | # save data to csv 68 | # df.to_csv(r'ncovid.csv', index=True, index_label='id') 69 | # print("SUCCESS!!!") 70 | 71 | # add postgres db engine 72 | engine = create_engine('postgresql+psycopg2://postgres:mastersam@localhost/ncovid') 73 | # 74 | # adding df to tables 75 | df.to_sql(con=engine, name='confirmed', if_exists='replace', index=True, index_label='id') 76 | # 77 | print('Data transferred from df to postgresql successfully!!!') 78 | # 79 | # checking the data 80 | print('checking the data...') 81 | conn = psycopg2.connect(host="localhost", database="ncovid", user="postgres", password="mastersam") 82 | cur = conn.cursor() 83 | cur.execute("SELECT * FROM confirmed") 84 | 85 | rows = cur.fetchall() 86 | 87 | for row in rows: 88 | print(row) 89 | print('Done checking!!!') 90 | 91 | conn.close() 92 | -------------------------------------------------------------------------------- /api/requirements.txt: -------------------------------------------------------------------------------- 1 | altgraph==0.17 2 | aniso8601==8.0.0 3 | APScheduler==3.6.3 4 | astroid==2.3.3 5 | atomicwrites==1.3.0 6 | attrs==19.3.0 7 | Automat==20.2.0 8 | backcall==0.1.0 9 | beautifulsoup4==4.8.2 10 | bleach==3.1.4 11 | bs4==0.0.1 12 | certifi==2019.9.11 13 | cffi==1.14.0 14 | chardet==3.0.4 15 | click==7.1.1 16 | codeclimate-test-reporter==0.2.3 17 | colorama==0.4.1 18 | constantly==15.1.0 19 | coreapi==2.3.3 20 | coreschema==0.0.4 21 | coverage==4.5.4 22 | coveralls==1.8.2 23 | cryptography==2.9 24 | cssselect==1.1.0 25 | cycler==0.10.0 26 | decorator==4.4.1 27 | defusedxml==0.6.0 28 | dj-database-url==0.5.0 29 | django>=2.2.13 30 | django-admin-honeypot==1.1.0 31 | django-background-tasks==1.2.5 32 | django-compat==1.0.15 33 | django-defender==0.7.0 34 | django-heroku==0.3.1 35 | django-otp==0.9.0 36 | django-rest-swagger==2.2.0 37 | django-secure==1.0.2 38 | djangorestframework==3.10.3 39 | docopt==0.6.2 40 | entrypoints==0.3 41 | flake8==3.7.9 42 | Flask==1.1.1 43 | Flask-RESTful==0.3.8 44 | get-retries==0.1.1 45 | get-wayback-machine==0.1.2 46 | gunicorn==19.9.0 47 | hyperlink==19.0.0 48 | idna==2.8 49 | importlib-metadata==0.23 50 | incremental==17.5.0 51 | ipykernel==5.1.3 52 | ipython==7.9.0 53 | ipython-genutils==0.2.0 54 | ipywidgets==7.5.1 55 | isort==4.3.21 56 | itsdangerous==1.1.0 57 | itypes==1.1.0 58 | jedi==0.15.1 59 | Jinja2==2.10.3 60 | joblib==0.14.0 61 | jsonschema==3.2.0 62 | jupyter==1.0.0 63 | jupyter-client==5.3.4 64 | jupyter-console==6.0.0 65 | jupyter-core==4.6.1 66 | kiwisolver==1.1.0 67 | lazy-object-proxy==1.4.3 68 | lxml==4.5.0 69 | macholib==1.14 70 | MarkupSafe==1.1.1 71 | matplotlib==3.1.2 72 | mccabe==0.6.1 73 | mistune==0.8.4 74 | modulegraph==0.18 75 | more-itertools==7.2.0 76 | mysql==0.0.2 77 | mysql-connector==2.2.9 78 | mysqlclient==1.4.6 79 | nbconvert==5.6.1 80 | nbformat==4.4.0 81 | notebook==6.0.2 82 | numpy==1.17.4 83 | openapi-codec==1.3.2 84 | packaging==19.2 85 | pandas==0.25.3 86 | pandocfilters==1.4.2 87 | parsel==1.5.2 88 | parso==0.5.1 89 | pickleshare==0.7.5 90 | Pillow>=6.2.2 91 | pluggy==0.13.1 92 | prometheus-client==0.7.1 93 | prompt-toolkit==2.0.10 94 | Protego==0.1.16 95 | psycopg2==2.8.3 96 | py==1.8.0 97 | py2app==0.21 98 | pyasn1==0.4.8 99 | pyasn1-modules==0.2.8 100 | pycodestyle==2.5.0 101 | pycparser==2.20 102 | PyDispatcher==2.0.5 103 | pyflakes==2.1.1 104 | Pygments==2.4.2 105 | PyHamcrest==2.0.2 106 | pylint==2.4.4 107 | PyMySQL==0.9.3 108 | pyOpenSSL==19.1.0 109 | pyowm==2.3.2 110 | pyparsing==2.4.5 111 | pyrsistent==0.15.6 112 | pytest==5.3.0 113 | pytest-cov==2.8.1 114 | python-coveralls==2.9.3 115 | python-dateutil==2.8.1 116 | pytz==2019.3 117 | pywin32==227 118 | pywinpty==0.5.5 119 | PyYAML==5.1.2 120 | pyzmq==18.1.1 121 | qrcode==6.1 122 | qtconsole==4.6.0 123 | queuelib==1.5.0 124 | redis==3.4.1 125 | requests==2.22.0 126 | scikit-learn==0.21.3 127 | scipy==1.3.3 128 | Scrapy==2.0.1 129 | scrapy-wayback-machine==1.0.0 130 | seaborn==0.9.0 131 | Send2Trash==1.5.0 132 | service-identity==18.1.0 133 | simplejson==3.17.0 134 | six==1.13.0 135 | sklearn==0.0 136 | soupsieve==2.0 137 | SQLAlchemy==1.3.15 138 | sqlparse==0.3.0 139 | terminado==0.8.3 140 | testpath==0.4.4 141 | tornado==6.0.3 142 | traitlets==4.3.3 143 | Twisted==20.3.0 144 | typed-ast==1.4.0 145 | tzlocal==2.0.0 146 | uritemplate==3.0.0 147 | urllib3==1.25.7 148 | virtualenv==16.7.8 149 | w3lib==1.21.0 150 | wayback-machine-scraper==1.0.7 151 | waybackpack==0.3.5 152 | wcwidth==0.1.7 153 | webencodings==0.5.1 154 | Werkzeug==1.0.0 155 | whitenoise==4.1.3 156 | widgetsnbextension==3.5.1 157 | wrapt==1.11.2 158 | zipp==0.6.0 159 | zope.interface==5.1.0 160 | -------------------------------------------------------------------------------- /api/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 43 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 1585762082678 72 | 77 | 78 | 79 | 80 | 82 | 83 | 92 | 93 | -------------------------------------------------------------------------------- /data_getter/scraper.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | import psycopg2 4 | from bs4 import BeautifulSoup 5 | import requests 6 | from sqlalchemy import create_engine # db engine 7 | import pandas as pd 8 | 9 | """ 10 | delays = [12, 3, 9, 21, 5, 6, 19, 7, 33, 11, 2, 17, 4] 11 | 12 | 13 | def get_random_ua(): 14 | random_ua = '' 15 | ua_file = 'ua_file.txt' 16 | try: 17 | with open(ua_file) as f: 18 | lines = f.readlines() 19 | if len(lines) > 0: 20 | while not random_ua.strip(): 21 | prng = np.random.RandomState() 22 | index = prng.permutation(len(lines) - 1) 23 | idx = np.asarray(index, dtype=np.integer)[0] 24 | random_proxy = lines[int(idx)] 25 | except Exception as ex: 26 | print('Exception in random_ua') 27 | print(str(ex)) 28 | finally: 29 | return random_ua 30 | 31 | 32 | url = "https://futa.edu.ng/" 33 | user_agent = get_random_ua() 34 | 35 | """ 36 | headers = { 37 | # # 'user-agent': user_agent, 38 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) ' 39 | 'Chrome/56.0.2924.87 Safari/537.36', 40 | # 'referer': 'https://google.ng/', 41 | # # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 42 | # # 'Accept-Encoding': 'gzip, deflate, br', 43 | # # 'Accept-Language': 'en-US,en;q=0.9', 44 | # # 'Pragma': 'no-cache', 45 | } 46 | 47 | # make a request with headers 48 | r = requests.get('https://covid19.ncdc.gov.ng', headers=headers, timeout=15) 49 | 50 | # print(r.status_code) # 200 for success 51 | 52 | content = BeautifulSoup(r.text, 'lxml') # parsing content 53 | 54 | My_table = content.find('table', {'id': 'custom1'}) # table to be scrapped having id as custom1 55 | 56 | # links = My_table.findAll('b') # all cases data seems to be in b tags 57 | stately = My_table.findAll('td') # all state name seems to be in td tags 58 | 59 | # print(links) 60 | 61 | # save states data to list 62 | states = [] 63 | for state in stately: 64 | states.append(state.text.strip("\n")) 65 | 66 | # print(states) 67 | 68 | # get states with even indexes 69 | somes = [] 70 | for i in range(0, len(states), 5): 71 | somes.append(states[i]) 72 | # print("states") 73 | # print(somes) 74 | # print("Total number of affected states:", len(somes)+1) 75 | 76 | # save cases data to list 77 | all_cases = [] 78 | for i in range(0, len(states)): 79 | # checking condition 80 | if i % 5 != 0: 81 | all_cases.append(states[i]) 82 | # print("all cases") 83 | # print(all_cases) 84 | 85 | # save confirmed cases data to list 86 | confirmed_cases = [] 87 | for i in range(0, len(all_cases), 4): 88 | confirmed_cases.append(all_cases[i]) 89 | # print("confirmed") 90 | # print(confirmed_cases) 91 | 92 | # save cases data to list 93 | admitted_cases = [] 94 | for i in range(1, len(all_cases), 4): 95 | admitted_cases.append(all_cases[i]) 96 | # print("admitted") 97 | # print(admitted_cases) 98 | 99 | # save discharged cases data to list 100 | discharged_cases = [] 101 | for i in range(2, len(all_cases), 4): 102 | discharged_cases.append(all_cases[i]) 103 | # print("recovered") 104 | # print(discharged_cases) 105 | 106 | # save deaths data to list 107 | deaths = [] 108 | for i in range(3, len(all_cases), 4): 109 | deaths.append(all_cases[i]) 110 | # print("deaths") 111 | # print(deaths) 112 | 113 | # take data to pandas dataframe 114 | df = pd.DataFrame() 115 | df['States'] = somes 116 | df['No_of_cases'] = confirmed_cases 117 | df['No_on_admission'] = admitted_cases 118 | df['No_discharged'] = discharged_cases 119 | df['No_of_deaths'] = deaths 120 | 121 | print('Dataframe\n', df) 122 | # # 123 | # save data to csv 124 | df.to_csv(r'ncovid.csv', index=True, index_label='id') 125 | print("SUCCESS!!!") 126 | # 127 | # from sqlalchemy import create_engine 128 | 129 | # mysql engine 130 | # engine = create_engine('mysql+pymysql://root:@localhost/ncovid') 131 | 132 | # sqlite engine 133 | # engine = sqlite3.connect(r"C:\Users\USER\Desktop\ncovid-19-api\api\db.sqlite3") 134 | 135 | # connections for mysql 136 | # con = MySQLdb.connect(host="localhost", user="root", 137 | # passwd="", db="ncovid") 138 | 139 | # add postgres db engine 140 | engine = create_engine('postgresql+psycopg2://postgres:mastersam@localhost/ncovid') 141 | # 142 | # adding df to tables 143 | df.to_sql(con=engine, name='data', if_exists='replace', index=True, index_label='id') 144 | # 145 | print('Data transferred from df to postgresql successfully!!!') 146 | 147 | # checking the data 148 | # print('checking the data...') 149 | # conn = psycopg2.connect(host="localhost", database="ncovid", user="postgres", password="mastersam") 150 | # cur = conn.cursor() 151 | # cur.execute("SELECT * FROM confirmed") 152 | # 153 | # rows = cur.fetchall() 154 | # 155 | # for row in rows: 156 | # print(row) 157 | # print('Done checking confirmed\nNow checking data!!!') 158 | # 159 | # cur.execute("SELECT * FROM data") 160 | # 161 | # rows = cur.fetchall() 162 | # 163 | # for row in rows: 164 | # print(row) 165 | # print('Done checking data!!!') 166 | # 167 | # conn.close() 168 | -------------------------------------------------------------------------------- /api/api/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for api project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.0. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = 'hbzuywojk43$vn(w=!)q3lwmiqlixz6a8w#dvo+yq3n7eby^(j' 23 | 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = False 27 | 28 | ALLOWED_HOSTS = ['0.0.0.0', 'localhost', '127.0.0.1', 'covid9ja.herokuapp.com'] 29 | 30 | # Application definition 31 | 32 | INSTALLED_APPS = [ 33 | 'django.contrib.admin', 34 | 'django.contrib.auth', 35 | 'django.contrib.contenttypes', 36 | 'django.contrib.sessions', 37 | 'django.contrib.messages', 38 | 'django.contrib.staticfiles', 39 | 'rest_framework', 40 | 'states', 41 | 'confirmed', 42 | 'daily', 43 | 'rest_framework_swagger', 44 | 'admin_honeypot', 45 | 'django_otp', 46 | 'django_otp.plugins.otp_totp', 47 | # 'defender', 48 | ] 49 | 50 | REST_FRAMEWORK = {'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema'} 51 | 52 | MIDDLEWARE = [ 53 | 'django.middleware.security.SecurityMiddleware', 54 | 'django.contrib.sessions.middleware.SessionMiddleware', 55 | 'django.middleware.common.CommonMiddleware', 56 | 'django.middleware.csrf.CsrfViewMiddleware', 57 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 58 | 'django.contrib.messages.middleware.MessageMiddleware', 59 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 60 | 'django_otp.middleware.OTPMiddleware', 61 | # 'defender.middleware.FailedLoginMiddleware', 62 | ] 63 | 64 | OTP_TOTP_ISSUER = 'Awesome Inc.' 65 | 66 | ROOT_URLCONF = 'api.urls' 67 | 68 | TEMPLATES = [ 69 | { 70 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 71 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 72 | 'APP_DIRS': True, 73 | 'OPTIONS': { 74 | 'context_processors': [ 75 | 'django.template.context_processors.debug', 76 | 'django.template.context_processors.request', 77 | 'django.contrib.auth.context_processors.auth', 78 | 'django.contrib.messages.context_processors.messages', 79 | ], 80 | }, 81 | }, 82 | ] 83 | 84 | WSGI_APPLICATION = 'api.wsgi.application' 85 | 86 | # Database 87 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 88 | 89 | DATABASES = { 90 | 'default': { 91 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 92 | 'NAME': 'ncovid', 93 | 'USER': "postgres", 94 | 'PASSWORD': "mastersam", 95 | 'HOST': 'localhost', # Or an IP Address that your DB is hosted on 96 | 'PORT': '', # port number 97 | } 98 | } 99 | 100 | # DATABASES = { 101 | # 'default': { 102 | # 'ENGINE': 'django.db.backends.sqlite3', 103 | # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 104 | # } 105 | # } 106 | 107 | # DATABASES = { 108 | # 'default': { 109 | # 'ENGINE': 'django.db.backends.mysql', 110 | # 'NAME': 'ncovid', 111 | # 'USER': 'root', 112 | # 'PASSWORD': '', 113 | # 'HOST': 'localhost', # Or an IP Address that your DB is hosted on 114 | # 'PORT': '3306', 115 | # } 116 | # } 117 | 118 | # Password validation 119 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 120 | 121 | AUTH_PASSWORD_VALIDATORS = [ 122 | { 123 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 124 | }, 125 | { 126 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 127 | }, 128 | { 129 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 130 | }, 131 | { 132 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 133 | }, 134 | ] 135 | 136 | # Internationalization 137 | # https://docs.djangoproject.com/en/2.0/topics/i18n/ 138 | 139 | LANGUAGE_CODE = 'en-us' 140 | 141 | TIME_ZONE = 'UTC' 142 | 143 | USE_I18N = True 144 | 145 | USE_L10N = True 146 | 147 | USE_TZ = True 148 | 149 | # Static files (CSS, JavaScript, Images) 150 | # https://docs.djangoproject.com/en/2.0/howto/static-files/ 151 | 152 | STATIC_URL = '/static/' 153 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 154 | # Extra places for collectstatic to find static files. 155 | STATICFILES_DIRS = ( 156 | os.path.join(BASE_DIR, 'static'), 157 | ) 158 | 159 | # X_FRAME_OPTIONS = 'DENY' 160 | # SECURE_HSTS_PRELOAD = True 161 | # SECURE_HSTS_SECONDS = 30 162 | # SECURE_HSTS_INCLUDE_SUBDOMAINS = True 163 | # # SECURE_SSL_REDIRECT = True 164 | # SECURE_FRAME_DENY = True 165 | # SECURE_CONTENT_TYPE_NOSNIFF = True 166 | # SECURE_BROWSER_XSS_FILTER = True 167 | # SESSION_COOKIE_SECURE = True 168 | # SESSION_COOKIE_HTTPONLY = True 169 | # 170 | # SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') 171 | # CSRF_COOKIE_SECURE = True 172 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # covid9ja api 2 | 3 | Get Nigeria Covid-19 states by states 4 | 5 | [![Programming Language](https://img.shields.io/badge/Language-Python-success?style=flat-square)](https://python.org) 6 | [![Framework](https://img.shields.io/badge/Framework-Django%20Rest-success?style=flat-square)](https://www.djangoproject.com/) 7 | [![GitHub contributors](https://img.shields.io/github/contributors/mastersam07/ncovid-19-api?color=success&style=flat-square)](https://github.com/Mastersam07/ncovid-19-api/graphs/contributors) 8 | ![GitHub last commit](https://img.shields.io/github/last-commit/mastersam07/ncovid-19-api?style=flat-square) 9 | [![License](https://img.shields.io/badge/license-MIT-success.svg?style=flat-square)](https://github.com/Mastersam07/ncovid-19-api/blob/master/LICENSE) 10 | 11 | > This project is discontinued and service shutdown 12 | >> Serving data from NCDC(Nigeria Center For Disease Control) as a JSON API 13 | 14 | 15 | ## 💻 Requirements 16 | * Any Operating System (ie. MacOS X, Linux, Windows) 17 | * Any IDE with python installed on your system(ie. Pycharm, VSCode etc) 18 | * A little knowledge of Python, Django and Web scrapping 19 | * Hands to code 🤓 20 | * A brain to think 🤓 21 | 22 | ## ✨ Features 23 | - [x] Nigeria states and cases 24 | - [x] Nigeria total cases 25 | - [x] Nigeria daily cases 26 | 27 | 28 | ## Dependencies 29 | * [Django](https://flutter.dev/) 30 | * [Django Rest Framework](https://www.django-rest-framework.org/) 31 | * [PostgreSql](https://www.postgresql.org/) 32 | 33 | ## Routes 34 | - #### /: contains coreapi documentation 35 | - #### /api/docs: contains swagger documentation 36 | - #### /api/confirmed: generate a summary of all cases in Nigeria 37 | - #### /api/daily: generate a summary of all cases from apex day to current day 38 | - #### /api/daily/{id}: generate a summary of cases on a particular day id 39 | - #### /api/states: generate a summary of all infected states cases 40 | - #### /api/states/{id}: generate a summary of cases in a particular state given its id 41 | 42 | ## Getting started 43 | 44 | #### 1. [Setting up PostgreSql](https://www.postgresql.org/) 45 | 46 | #### 2. Clone the repo 47 | 48 | ```sh 49 | $ git clone https://github.com/Mastersam07/ncovid-19-api.git 50 | $ cd ncovid-19-api 51 | ``` 52 | 53 | #### 3. [Setup a virtual environment](https://programwithus.com/learn-to-code/Pip-and-virtualenv-on-Windows/) 54 | 55 | #### 4. Get requirements 56 | 57 | ```sh 58 | $ pip install requirements.txt 59 | ``` 60 | 61 | #### 5. Get the data 62 | 63 | ```sh 64 | $ cd data_getter 65 | $ python scraper.py 66 | ``` 67 | 68 | #### 6. Migrate database 69 | 70 | ```sh 71 | $ cd ..\api 72 | $ python manage.py migrate 73 | ``` 74 | 75 | #### 7. Run the application 76 | 77 | ```sh 78 | $ python manage.py runserver 79 | ``` 80 | 81 | #### 8. Run the application in deployment(debug: false) 82 | 83 | * ##### Create the folder "static" in the project root directory 84 | * ##### Add the below bit of code to settings.py 85 | 86 | ```sh 87 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 88 | # Extra places for collectstatic to find static files. 89 | STATICFILES_DIRS = ( 90 | os.path.join(BASE_DIR, 'static'), 91 | ) 92 | ``` 93 | * ##### Run the below command in your terminal 94 | ```sh 95 | $ python manage.py collectstatic 96 | ``` 97 | * ##### Your project is now production ready 98 | 99 | ## 📸 ScreenShots 100 | 101 | ||| 102 | ||| 103 | || 104 | 105 | ## 📊📈📉 106 | #### For the complete data in csv format, check the below: 107 | - #### [Total Data](https://github.com/Mastersam07/ncovid-19-api/blob/master/data_getter/ncovid.csv) 108 | - #### [Daily Reports](https://github.com/Mastersam07/ncovid-19-api/blob/master/data_getter/daily_report.csv) 109 | 110 | 111 | ## :heart: Found this project useful? 112 | #### If you found this project useful or you like what you see, then please consider giving it a :star: on Github and sharing it with your friends via social media. 113 | 114 | ## 🐛 Bugs/Request 115 | #### Encounter any problem(s)? feel free to open an issue. If you feel you could make something better, please raise a ticket on Github and I'll look into it. Pull request are also welcome. 116 | 117 | ## Showcase 118 | - #### ![flutter](ss/flutterLogo1.png "flutter logo") [https://github.com/Mastersam07/ncovid](https://github.com/Mastersam07/ncovid), (Flutter) by [@mastersam07](https://github.com/mastersam07) 119 | 120 | ## ⭐️ License 121 | #### MIT LICENSE 122 | ##### Transitively from NCDC Site, the data may not be used for commercial purposes. 123 | 124 | ## 🤓 Developer(s) 125 | #### **Abada Samuel Oghenero** 126 | 127 | 128 | 129 | 130 | 131 | ## Donate 132 | 133 | > #### If you found this project or the data helpful or you learned something from the source code and want to thank me, consider buying me a cup of :coffee: 134 | > 135 | > #### - [Paystack NG](https://paystack.com/pay/mastersam) 136 | -------------------------------------------------------------------------------- /data_getter/ua_file.txt: -------------------------------------------------------------------------------- 1 | Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19 2 | 3 | Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.36 Safari/525.19 4 | 5 | Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.540.0 Safari/534.10 6 | 7 | Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.4 (KHTML, like Gecko) Chrome/6.0.481.0 Safari/534.4 8 | 9 | Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4 10 | 11 | Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.3 Safari/532.2 12 | 13 | Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.201.1 Safari/532.0 14 | 15 | Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 16 | 17 | Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.173.1 Safari/530.5 18 | 19 | Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.558.0 Safari/534.10 20 | 21 | Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/540.0 (KHTML,like Gecko) Chrome/9.1.0.0 Safari/540.0 22 | 23 | Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.600.0 Safari/534.14 24 | 25 | Mozilla/5.0 (X11; U; Windows NT 6; en-US) AppleWebKit/534.12 (KHTML, like Gecko) Chrome/9.0.587.0 Safari/534.12 26 | 27 | Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13 28 | 29 | Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.11 Safari/534.16 30 | 31 | Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20 32 | 33 | Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.792.0 Safari/535.1 34 | 35 | Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.872.0 Safari/535.2 36 | 37 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7 38 | 39 | Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 40 | 41 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19 42 | 43 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24 44 | 45 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6 46 | 47 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1 48 | 49 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.15 (KHTML, like Gecko) Chrome/24.0.1295.0 Safari/537.15 50 | 51 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 52 | 53 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1467.0 Safari/537.36 54 | 55 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 56 | 57 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1623.0 Safari/537.36 58 | 59 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36 60 | 61 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.103 Safari/537.36 62 | 63 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.38 Safari/537.36 64 | 65 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36 66 | 67 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36 68 | 69 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36 70 | 71 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36 72 | 73 | Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 GTB5 74 | 75 | Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ko; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 76 | 77 | Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 78 | 79 | Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080214 Firefox/2.0.0.12 80 | 81 | Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 82 | 83 | Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.5) Gecko/20060819 Firefox/1.5.0.5 84 | 85 | Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 86 | 87 | Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 88 | 89 | Mozilla/5.0 (Windows; Windows NT 6.1; rv:2.0b2) Gecko/20100720 Firefox/4.0b2 90 | 91 | Mozilla/5.0 (X11; Linux x86_64; rv:2.0b4) Gecko/20100818 Firefox/4.0b4 92 | 93 | Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100308 Ubuntu/10.04 (lucid) Firefox/3.6 GTB7.1 94 | 95 | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b7) Gecko/20101111 Firefox/4.0b7 96 | 97 | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b8pre) Gecko/20101114 Firefox/4.0b8pre 98 | 99 | Mozilla/5.0 (X11; Linux x86_64; rv:2.0b9pre) Gecko/20110111 Firefox/4.0b9pre 100 | 101 | Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b9pre) Gecko/20101228 Firefox/4.0b9pre 102 | 103 | Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.2a1pre) Gecko/20110324 Firefox/4.2a1pre 104 | 105 | Mozilla/5.0 (X11; U; Linux amd64; rv:5.0) Gecko/20100101 Firefox/5.0 (Debian) 106 | 107 | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0a2) Gecko/20110613 Firefox/6.0a2 108 | 109 | Mozilla/5.0 (X11; Linux i686 on x86_64; rv:12.0) Gecko/20100101 Firefox/12.0 110 | 111 | Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2 112 | 113 | Mozilla/5.0 (X11; Ubuntu; Linux armv7l; rv:17.0) Gecko/20100101 Firefox/17.0 114 | 115 | Mozilla/5.0 (Windows NT 6.1; rv:21.0) Gecko/20130328 Firefox/21.0 116 | 117 | Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:22.0) Gecko/20130328 Firefox/22.0 118 | 119 | Mozilla/5.0 (Windows NT 5.1; rv:25.0) Gecko/20100101 Firefox/25.0 120 | 121 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:25.0) Gecko/20100101 Firefox/25.0 122 | 123 | Mozilla/5.0 (Windows NT 6.1; rv:28.0) Gecko/20100101 Firefox/28.0 124 | 125 | Mozilla/5.0 (X11; Linux i686; rv:30.0) Gecko/20100101 Firefox/30.0 126 | 127 | Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0 128 | 129 | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 130 | 131 | Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0 132 | 133 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0 134 | 135 | Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36 Edge/12.0 136 | 137 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.9600 138 | 139 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240 140 | 141 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10547 142 | 143 | Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586 144 | 145 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 Safari/537.36 Edge/14.14359 146 | 147 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3739.0 Safari/537.36 Edg/75.0.109.0 148 | 149 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.16 Safari/537.36 Edg/79.0.309.11 150 | 151 | Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fi-fi) AppleWebKit/420+ (KHTML, like Gecko) Safari/419.3 152 | 153 | Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7 154 | 155 | Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.6 156 | 157 | Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 158 | 159 | Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 160 | 161 | Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_6; it-it) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 162 | 163 | Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-HK) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 164 | 165 | Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 166 | 167 | Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 168 | 169 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10 170 | 171 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/536.26.17 (KHTML, like Gecko) Version/6.0.2 Safari/536.26.17 172 | 173 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/6.1.3 Safari/537.75.14 174 | 175 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/600.3.10 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.10 176 | 177 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11) AppleWebKit/601.1.39 (KHTML, like Gecko) Version/9.0 Safari/601.1.39 178 | 179 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13) AppleWebKit/603.1.13 (KHTML, like Gecko) Version/10.1 Safari/603.1.13 180 | 181 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15 --------------------------------------------------------------------------------