User:TolBot/Task 5

From Meta, a Wikimedia project coordination wiki
TolBot: Task 5
Status  Approved
Wiki x
Summary Update COVID-19 pandemic data
Page(s) Pages:
Period daily
Language Python
Supervision automatic
Excl. compl.? No

Requests for approval[edit]

Source[edit]

Version 1.2.0, updated 15 Oct 2021.
run = True

languages = {
	'en': {
		'page': 'Template:COVID-19 data/data',
		'summary': '[[m:User:TolBot/Task 5|Task 5]]: update COVID-19 pandemic data'
	},
	'fr': {
		'page': 'Modèle:Données de la pandémie de Covid-19/données',
		'summary': '[[m:User:TolBot/Task 5|Tâche 5]]: mettre à jour les données de la pandémie de COVID-19'
	}
}

bot_username = ''
bot_password = ''
bot_credentials = (bot_username, bot_password)

import requests
import json
import subprocess
import re

api = 'https://{0}.wikipedia.org/w/api.php?format=json&formatversion=2'

owid_url = 'https://covid.ourworldindata.org/data/latest/owid-covid-latest.json'

urls = {
    'US': 'https://data.cdc.gov/resource/9mfq-cb36.json'
}

owid_translator = {
    'countries': {
        'OWID_WRL': 'XW',
        'OWID_EUN': 'EU',
        'OWID_CYN': 'XC',
        'OWID_KOS': 'XK',
				'ABW': 'AW',
				'AFG': 'AF',
				'AGO': 'AO',
				'AIA': 'AI',
				'ALA': 'AX',
				'ALB': 'AL',
				'AND': 'AD',
				'ARE': 'AE',
				'ARG': 'AR',
				'ARM': 'AM',
				'ASM': 'AS',
				'ATA': 'AQ',
				'ATF': 'TF',
				'ATG': 'AG',
				'AUS': 'AU',
				'AUT': 'AT',
				'AZE': 'AZ',
				'BDI': 'BI',
				'BEL': 'BE',
				'BEN': 'BJ',
				'BES': 'BQ',
				'BFA': 'BF',
				'BGD': 'BD',
				'BGR': 'BG',
				'BHR': 'BH',
				'BHS': 'BS',
				'BIH': 'BA',
				'BLM': 'BL',
				'BLR': 'BY',
				'BLZ': 'BZ',
				'BMU': 'BM',
				'BOL': 'BO',
				'BRA': 'BR',
				'BRB': 'BB',
				'BRN': 'BN',
				'BTN': 'BT',
				'BVT': 'BV',
				'BWA': 'BW',
				'CAF': 'CF',
				'CAN': 'CA',
				'CCK': 'CC',
				'CHE': 'CH',
				'CHL': 'CL',
				'CHN': 'CN',
				'CIV': 'CI',
				'CMR': 'CM',
				'COD': 'CD',
				'COG': 'CG',
				'COK': 'CK',
				'COL': 'CO',
				'COM': 'KM',
				'CPV': 'CV',
				'CRI': 'CR',
				'CUB': 'CU',
				'CUW': 'CW',
				'CXR': 'CX',
				'CYM': 'KY',
				'CYP': 'CY',
				'CZE': 'CZ',
				'DEU': 'DE',
				'DJI': 'DJ',
				'DMA': 'DM',
				'DNK': 'DK',
				'DOM': 'DO',
				'DZA': 'DZ',
				'ECU': 'EC',
				'EGY': 'EG',
				'ERI': 'ER',
				'ESH': 'EH',
				'ESP': 'ES',
				'EST': 'EE',
				'ETH': 'ET',
				'FIN': 'FI',
				'FJI': 'FJ',
				'FLK': 'FK',
				'FRA': 'FR',
				'FRO': 'FO',
				'FSM': 'FM',
				'GAB': 'GA',
				'GBR': 'GB',
				'GEO': 'GE',
				'GGY': 'GG',
				'GHA': 'GH',
				'GIB': 'GI',
				'GIN': 'GN',
				'GLP': 'GP',
				'GMB': 'GM',
				'GNB': 'GW',
				'GNQ': 'GQ',
				'GRC': 'GR',
				'GRD': 'GD',
				'GRL': 'GL',
				'GTM': 'GT',
				'GUF': 'GF',
				'GUM': 'GU',
				'GUY': 'GY',
				'HKG': 'HK',
				'HMD': 'HM',
				'HND': 'HN',
				'HRV': 'HR',
				'HTI': 'HT',
				'HUN': 'HU',
				'IDN': 'ID',
				'IMN': 'IM',
				'IND': 'IN',
				'IOT': 'IO',
				'IRL': 'IE',
				'IRN': 'IR',
				'IRQ': 'IQ',
				'ISL': 'IS',
				'ISR': 'IL',
				'ITA': 'IT',
				'JAM': 'JM',
				'JEY': 'JE',
				'JOR': 'JO',
				'JPN': 'JP',
				'KAZ': 'KZ',
				'KEN': 'KE',
				'KGZ': 'KG',
				'KHM': 'KH',
				'KIR': 'KI',
				'KNA': 'KN',
				'KOR': 'KR',
				'KWT': 'KW',
				'LAO': 'LA',
				'LBN': 'LB',
				'LBR': 'LR',
				'LBY': 'LY',
				'LCA': 'LC',
				'LIE': 'LI',
				'LKA': 'LK',
				'LSO': 'LS',
				'LTU': 'LT',
				'LUX': 'LU',
				'LVA': 'LV',
				'MAC': 'MO',
				'MAF': 'MF',
				'MAR': 'MA',
				'MCO': 'MC',
				'MDA': 'MD',
				'MDG': 'MG',
				'MDV': 'MV',
				'MEX': 'MX',
				'MHL': 'MH',
				'MKD': 'MK',
				'MLI': 'ML',
				'MLT': 'MT',
				'MMR': 'MM',
				'MNE': 'ME',
				'MNG': 'MN',
				'MNP': 'MP',
				'MOZ': 'MZ',
				'MRT': 'MR',
				'MSR': 'MS',
				'MTQ': 'MQ',
				'MUS': 'MU',
				'MWI': 'MW',
				'MYS': 'MY',
				'MYT': 'YT',
				'NAM': 'NA',
				'NCL': 'NC',
				'NER': 'NE',
				'NFK': 'NF',
				'NGA': 'NG',
				'NIC': 'NI',
				'NIU': 'NU',
				'NLD': 'NL',
				'NOR': 'NO',
				'NPL': 'NP',
				'NRU': 'NR',
				'NZL': 'NZ',
				'OMN': 'OM',
				'PAK': 'PK',
				'PAN': 'PA',
				'PCN': 'PN',
				'PER': 'PE',
				'PHL': 'PH',
				'PLW': 'PW',
				'PNG': 'PG',
				'POL': 'PL',
				'PRI': 'PR',
				'PRK': 'KP',
				'PRT': 'PT',
				'PRY': 'PY',
				'PSE': 'PS',
				'PYF': 'PF',
				'QAT': 'QA',
				'REU': 'RE',
				'ROU': 'RO',
				'RUS': 'RU',
				'RWA': 'RW',
				'SAU': 'SA',
				'SDN': 'SD',
				'SEN': 'SN',
				'SGP': 'SG',
				'SGS': 'GS',
				'SHN': 'SH',
				'SJM': 'SJ',
				'SLB': 'SB',
				'SLE': 'SL',
				'SLV': 'SV',
				'SMR': 'SM',
				'SOM': 'SO',
				'SPM': 'PM',
				'SRB': 'RS',
				'SSD': 'SS',
				'STP': 'ST',
				'SUR': 'SR',
				'SVK': 'SK',
				'SVN': 'SI',
				'SWE': 'SE',
				'SWZ': 'SZ',
				'SXM': 'SX',
				'SYC': 'SC',
				'SYR': 'SY',
				'TCA': 'TC',
				'TCD': 'TD',
				'TGO': 'TG',
				'THA': 'TH',
				'TJK': 'TJ',
				'TKL': 'TK',
				'TKM': 'TM',
				'TLS': 'TL',
				'TON': 'TO',
				'TTO': 'TT',
				'TUN': 'TN',
				'TUR': 'TR',
				'TUV': 'TV',
				'TWN': 'TW',
				'TZA': 'TZ',
				'UGA': 'UG',
				'UKR': 'UA',
				'UMI': 'UM',
				'URY': 'UY',
				'USA': 'US',
				'UZB': 'UZ',
				'VAT': 'VA',
				'VCT': 'VC',
				'VEN': 'VE',
				'VGB': 'VG',
				'VIR': 'VI',
				'VNM': 'VN',
				'VUT': 'VU',
				'WLF': 'WF',
				'WSM': 'WS',
				'YEM': 'YE',
				'ZAF': 'ZA',
				'ZMB': 'ZM',
				'ZWE': 'ZW'
    },
    'columns': {
      'people_vaccinated': 'total_vaccinated',
      'people_fully_vaccinated': 'fully_vaccinated',
      'total_vaccinations': 'vaccine_doses',
      'total_cases': 'cases',
      'total_deaths': 'deaths',
      'people_vaccinated_per_hundred': 'percent_vaccinated',
      'people_fully_vaccinated_per_hundred': 'percent_fully_vaccinated',
			'total_deaths_per_million': 'deaths_per_million'
    }
}

# Login
def login(api, session, credentials):
  token_params = {
      'action': 'query',
      'meta': 'tokens',
      'type': 'login'
  }
  token_q = session.post(api, data=token_params).json()
  token = token_q['query']['tokens']['logintoken']
  username, password = credentials
  login_params = {
      'action': 'login',
      'lgname': username,
      'lgpassword': password,
      'lgtoken': token
  }
  login_q = session.post(api, data=login_params).json()
  return session

# Get and parse current data on page
def parse_json(api, session, page):
  params = {
      'action': 'parse',
      'prop': 'wikitext',
      'page': page
  }
  q = session.post(api, data=params).json()
  wikitext = q['parse']['wikitext']
  data = json.loads(wikitext)
  return data

def get(url):
  return requests.get(url).json()

# Update with OWID data
def update_owid(session, owid_data, data, translator):
  for owid_code, location_data in owid_data.items():
    if owid_code in translator['countries']:
      for owid_col, col in translator['columns'].items():
        if owid_col in location_data:
          code = translator['countries'][owid_code]
          if not code in data:
            data[code] = {}
          if location_data[owid_col]:
            data[code][col] = location_data[owid_col]
  return data

# Edit page with updated data
def edit(api, session, page, data, summary):
  text = json.dumps(data, ensure_ascii=False, sort_keys=True)
  token_params = {
      'action': 'query',
      'meta': 'tokens'
  }
  token_q = session.post(api, data=token_params).json()
  token = token_q['query']['tokens']['csrftoken']
  edit_params = {
      'action': 'edit',
      'title': page,
      'text': text,
      'summary': summary,
      'token': token
  }
  edit_q = session.post(api, data=edit_params).json()
  return edit_q

session = requests.Session()
if run:
  for lang in languages:
    login(api.format(lang), session, bot_credentials)
owid_data = get(owid_url)
for lang, lang_data in languages.items():
  data = parse_json(api.format(lang), session, lang_data['page'])
  data = update_owid(session, owid_data, data, owid_translator)
  if run:
    print(edit(
      api.format(lang),
      session,
      lang_data['page'],
      data,
      lang_data['summary']
    ))
  else:
    print(
      '\n\n',
      json.dumps(data, indent=2, ensure_ascii=False, sort_keys=True)
    )
  subprocess.run(['rm', 'owid.csv'])

Licensing[edit]

This work (all source code in this level 2 section) is licensed under:

Version history[edit]

  • 1.0.0: Initial release. 23 Jul 2021.
  • 1.1.0: Use JSON latest data instead of CSV all data. 26 Jul 2021.
  • 1.1.1: Add percent fully vaccinated. 31 Aug 2021.
  • 1.1.2: Add deaths per million. 23 Sep 2021.
  • 1.2.0: Make compatible with multiple language Wikipedias. 15 Oct 2021.