Analyse du site Web Smart Voting et de la nouvelle API sur le site Web de la CEC

image



Le 13 septembre 2020, une seule journée de vote a eu lieu en Russie. Dans certaines régions, l'opposition a utilisé la stratégie du «vote intelligent», selon laquelle les électeurs d'opposition votent pour un seul candidat ayant le plus de chances de battre un représentant des autorités.



Pour la deuxième année consécutive, le processus de sélection des candidats au «Smart Voting» a suscité des discussions sur le thème de sa transparence. De plus, je suis personnellement déconcerté par les difficultés à résumer la stratégie que peuvent rencontrer les analystes indépendants. Les organisateurs de l' UMG ne publient pas les résultats détaillés de la stratégie, mais seulement des diagrammes montrant combien de candidats de l'opposition sont entrés au parlement régional.



Sur le site de "Smart Voting"vous ne pouvez pas obtenir une liste des candidats pris en charge en spécifiant, par exemple, la ville et le district. Si quelqu'un veut collecter des données sur la région, il devra faire le travail monotone de sélection des adresses pour chaque district.



En aucun cas je ne reproche aux développeurs du site UMG, il possède toutes les fonctionnalités nécessaires pour mettre en œuvre la stratégie de vote. Mais étant donné qu'en 2019 personne n'était impliqué dans la collecte et la publication de données détaillées sur les résultats de l'UMG (en dehors des élections de Moscou), lors de ces élections, j'ai décidé de prendre l'initiative en main.



Le résultat est un tableau récapitulatif comme celui-ci . Dans cet article, je vais vous expliquer comment l' ensemble de données a été obtenu , comment les informations ont été collectées à partir des sites Smart Voting et du nouveau service Web CEC .



image



Site de vote intelligent



Voyons d'abord quelles données nous pouvons extraire du site Smart Voting. Sur la page principale du site, il y a un champ pour saisir l'adresse d'inscription de l'utilisateur. Lorsque vous entrez une chaîne, une liste d'adresses suggérées s'affiche au format suivant:



image




Lors du choix de l'une des adresses proposées, nous sommes redirigés vers la page du bureau de vote à laquelle est rattachée l'adresse sélectionnée:



image


La page répertorie les campagnes électorales qui ont lieu sur ce site. Pour chaque campagne, il existe une liste de candidats pour / contre lesquels ils sont invités à voter:



image


Dans ce cas, on assiste à l'élection du gouverneur, pour laquelle l'UMG n'a pas indiqué de candidat de l'opposition. Cela est dû au fait que les élections des gouverneurs se déroulent en deux tours et peu importe pour lequel des candidats de l'opposition les électeurs voteront au premier tour.

Nous voyons également trois candidats à la fois, pour lesquels on leur propose de voter aux élections au parlement de la ville. Cela est dû au fait que les élections à Sotchi ont des circonscriptions plurinominales.

Dans toutes les autres campagnes électorales, impliquées dans l'UMG cette année, il n'y avait que des circonscriptions uninominales.



Examinons le code de la page et constatons que toutes les données décrites sont collectées dans un format JSON pratique. Dans l'élément avec id = "__ NEXT_DATA__", qui sert à dessiner la page, il y a des informations sur le bureau de vote, les campagnes électorales correspondantes et les candidats:



Contenu de l'élément __NEXT_DATA__
{
   "props":{
      "pageProps":{
         "id":"440384",
         "settings":{
            "id":1,
            "share_photo":"/ganimed-media/share_photo/smartvote_sharepic_1200x628.jpg",
            "video_on_main_page":"https://youtu.be/w8gapDGwWMY",
            "fake_mode":false,
            "title_share":",    ",
            "text_share":" ,      —    « ».   — .",
            "telegram_bot_link":"https://tlinks.run/smartvotebot",
            "viber_bot_link":"viber://public?id=smartvote",
            "facebook_bot_link":"https://facebook.com/umnoegolosovanie/",
            "alice_link":null,
            "vk_bot_link":null
         },
         "serverData":{
            "commission":{
               "id":440384,
               "number":"4317",
               "address":"354340,  ,  ,  ,   , 24",
               "descr":"   № 49 . .. ",
               "lat":"43.425923",
               "lon":"39.920152",
               "region_id":26,
               "region_intid":"135637827259064320000372513"
            },
            "campaigns":[
               {
                  "id":26,
                  "code":"krasnodar-gub-2020",
                  "title":"   ",
                  "is_regional":true,
                  "ready_date":null,
                  "district":{
                     "id":458,
                     "code":"oik-0",
                     "name":"0",
                     "leaflet":""
                  },
                  "candidates":[
                     {
                        "id":998,
                        "name":"  ",
                        "share_image":"/elections-api-media/share/26/998.png",
                        "anticandidate":true,
                        "self_nominated":false,
                        "has_won":false,
                        "has_second_round":false,
                        "party":{
                           "title":" ",
                           "antiparty":true
                        }
                     }
                  ]
               },
               {
                  "id":28,
                  "code":"krasnodar-sochi-gorduma-2020",
                  "title":"    ",
                  "is_regional":false,
                  "ready_date":null,
                  "district":{
                     "id":526,
                     "code":"oik-2",
                     "name":"2",
                     "leaflet":"/elections-api-media/28/526-1334-1335-5385.pdf"
                  },
                  "candidates":[
                     {
                        "id":1334,
                        "name":"  ",
                        "share_image":"/elections-api-media/share/28/1334.png",
                        "anticandidate":false,
                        "self_nominated":true,
                        "has_won":false,
                        "has_second_round":false,
                        "party":null
                     },
                     {
                        "id":1335,
                        "name":"  ",
                        "share_image":"/elections-api-media/share/28/1335.png",
                        "anticandidate":false,
                        "self_nominated":true,
                        "has_won":false,
                        "has_second_round":false,
                        "party":null
                     },
                     {
                        "id":5385,
                        "name":"  ",
                        "share_image":"/elections-api-media/share/28/5385.png",
                        "anticandidate":false,
                        "self_nominated":false,
                        "has_won":false,
                        "has_second_round":false,
                        "party":{
                           "title":"",
                           "antiparty":false
                        }
                     }
                  ]
               }
            ]
         },
         "error":null,
         "currentUrl":"https://votesmart.appspot.com/candidates/440384"
      }
   },
   "page":"/candidates/[id]",
   "query":{
      "id":"440384"
   },
   "buildId":"U8hjaoxZw8TINu-DU_Ixw",
   "runtimeConfig":{
      "HOST":"https://votesmart.appspot.com"
   },
   "isFallback":false,
   "customServer":true,
   "gip":true
}




Pour le bureau de vote, le numéro (numéro) du PEC correspondant et son identifiant sont indiqués dans la base de données du site UMG. Id = 440834 correspond au numéro trouvé dans l'URL de la page (/ candidats / 440834).



Pouvons-nous, connaissant le numéro PEC et la région, calculer l'identifiant de la commission sur le site UMG? Je n'ai pas pu trouver de dépendance évidente, car les identifiants sont distribués de manière plutôt chaotique:

Sotchi, PEC # 4512 -> id = 440834

Sotchi, PEC # 4513 -> id = 441403

Sotchi, PEC # 4514 -> id = 1781216



Comment collecter une liste de réflexions de nombres PEC dans les pages d'identification? Il semble extrêmement inefficace d'itérer et de vérifier toutes sortes d'identificateurs de 1 à 2 000 000, la plupart de ces identificateurs ne fonctionnent pas.



Mais, si nous avons une liste d'adresses, nous pouvons relativement facilement établir une liste des bureaux de vote concernés. Lorsque vous saisissez une chaîne sur l'écran initial, une liste d'adresses appropriées est renvoyée par le serveur, avec les identifiants de commission correspondants:



Rechercher un site par adresse



https://votesmart.appspot.com/api/v1/cik/addresses?query=ADDRESS


  • ADRESSE - adresse, de préférence au format "Sujet, ville, rue, maison". Il est également souhaitable sans abréviations "st.", "D.", puisque l'analyseur sur le serveur ne les gère pas bien


Exemple de demande:



https://votesmart.appspot.com/api/v1/cik/addresses?query= Smolensk de Lénine



Résultat de la requête
{
   "suggestions":[
      {
         "value":" ,  ,  ,  ",
         "data":{
            "fullname":" ,  ,  ,  ",
            "level":"7",
            "region_id":69,
            "commission_id":null,
            "intid":"138474570115456000000347353",
            "path":"135637827259064320000359815,135637827259064320000359819,135637827259064320000359820,138474570115456000000347353",
            "snippet":" ,  <em></em>,  , <em></em> ",
            "score":118.84238
         }
      },
      {
         "value":" ,  ,  ,  , 12",
         "data":{
            "fullname":" ,  ,  ,  , 12",
            "level":"8",
            "region_id":69,
            "commission_id":1124357,
            "intid":"135659820348349440000359937",
            "path":"135637827259064320000359815,135637827259064320000359819,135637827259064320000359822,135659820348349440000359708,135659820348349440000359937",
            "snippet":" ,  <em></em>,  , <em></em> , 12",
            "score":115.14931
         }
      },
...
   ]
}




Où puis-je obtenir une liste d'adresses pour extraire des données du site? L'énumération de la base de données de toutes les adresses dans le pays semble être une solution inefficace, car pour résoudre notre problème, nous n'avons besoin que d'une adresse par circonscription.



Chaque circonscription compte en moyenne 2 à 8 circonscriptions. Même si l'adresse d'un bureau de vote, dans de rares cas, peut ne pas correspondre à la circonscription à laquelle il appartient, je fais l'hypothèse suivante: en parcourant les adresses PEC sur le site UMG, vous pouvez collecter des informations sur chaque circonscription.



Plus tard, en utilisant cette hypothèse, j'ai pu recueillir des informations sur presque toutes les circonscriptions. En raison de l'hétérogénéité du format d'adresse dans la base de données des commissions électorales, seules les adresses de 10 circonscriptions sur 1 100 que j'ai dû sélectionner manuellement.



Sur Internet, vous pouvez trouver une base de données régulièrement mise à jour des commissions électorales de la Fédération de Russie , contenant des informations sur les adresses et même la composition des CEP. Mais pour plus de pertinence et de fiabilité des données (et aussi parce que je n'étais pas satisfait du format d'un certain champ), j'ai décidé de collecter moi-même la liste des adresses, car il s'est avéré que le site Web de la CEC dispose de toutes les fonctionnalités nécessaires pour cela.



Nouveau service Web CEC. Méthodes API



GAS "Vybory" est un système automatisé mis au point en 1995, destiné à la préparation et à la conduite d'élections et de référendums dans la Fédération de Russie.



Si vous avez déjà été intéressé par le déroulement d'une campagne électorale, alors vous êtes probablement tombé sur ce site , qui publie des informations de base du système GAS "Vybory", y compris le dépouillement des votes, avant même l'approbation des résultats des élections:



image



Et si plus tôt, pour récupérer les résultats des élections, les dataminers utilisé ce site, à l'époque du vote sur les amendements à la Constitution , un captcha est soudainement apparu sur le site . Le captcha est très persistant, il apparaît lorsque vous accédez à chaque page du site:



image


Comme vous pouvez l'évaluer visuellement, le captcha est bien sûr très simple, et quelqu'un a sûrement déjà trouvé des moyens de le contourner. Au lieu de faire du machine learning, je me suis tourné vers une nouvelle section sur le site Web de la CEC, que peu de gens connaissent encore: Services numériques



image



Cette section est apparue juste lors du vote sur les amendements et contient plusieurs services Web qui, via HTTP Les requêtes communiquent avec l'API interne pour recevoir les données du système GAS «Vybory». L'utilisateur Habr a déjà prêté attention à cette fonctionnalité. Examinons cela plus en détail.



Voici une description des principales demandes de la nouvelle API qui ont été utilisées dans ce projet:



Chaque structure de données du système contient une clé VRN- un identifiant unique pour l'entité, qu'il s'agisse d'un site, d'une campagne, d'un quartier ou d'un candidat .




Informations PEC



http://cikrf.ru/iservices/voter-services/committee/subjcode/SUBJECT_CODE/num/COMMITTEE_NUM




Exemple de demande:



http://cikrf.ru/iservices/voter-services/committee/subjcode/ 01 / num / 2



Résultat de la requête
{
   "vrn":"4014001117979",
   "name":"   №2",
   "subjCode":"01",
   "numKsa":"01T001",
   "vid":"5",
   "address":{
      "address":"385200,  ,   ,  ,   .., 16",
      "descr":"  №1",
      "phone":"8-87772-9-23-72",
      "lat":"44.882893",
      "lon":"39.187187"
   },
   "votingAddress":{
      "address":"385200,  ,   ,  ,   .., 16",
      "descr":"  №1",
      "phone":"8-87772-9-23-72",
      "lat":"44.882893",
      "lon":"39.187187"
   }
}







Informations sur les campagnes électorales sur le site



http://cikrf.ru/iservices/voter-services/vibory/committee/COMMITTEE_VRN


  • COMMITTEE_VRN - Identifiant PEC


Exemple de demande:



http://cikrf.ru/iservices/voter-services/vibory/committee/ 4544028162533



Résultat de la requête
[
   {
      "vrn":"100100163596966",
      "date":"2020-07-01",
      "name":"         ",
      "subjCode":"0",
      "pronetvd":null,
      "vidvibref":"0"
   },
   {
      "vrn":"25420001876696",
      "date":"2020-09-13",
      "name":"       ",
      "subjCode":"54",
      "pronetvd":"0",
      "vidvibref":"2"
   },
   {
      "vrn":"4544220183446",
      "date":"2020-09-13",
      "name":"        ",
      "subjCode":"54",
      "pronetvd":null,
      "vidvibref":"2"
   }
]





Liste des circonscriptions



http://cikrf.ru/iservices/sgo-visual-rest/vibory/CAMPAIGN_VRN/tvd


  • CAMPAIGN_VRN - ID de campagne


Exemple de demande:



http://cikrf.ru/iservices/sgo-visual-rest/vibory/ 457422069597 / tvd



Résultat de la requête
{
   "_embedded":{
      "tvdDtoList":[
         {
            "vrn":457422069601,
            "namtvd":"    ",
            "namik":"    ",
            "numtvd":"0",
            "vidtvd":"ROOT",
            "_links":{
               "results":{
                  "href":"http://cikrf.ru/iservices/sgo-visual-rest/vibory/457422069597/results/457422069601/proportion"
               }
            }
         },
         {
            "vrn":457422069602,
            "namik":"   № 1",
            "numtvd":"1",
            "vidtvd":"OIK",
            "_links":{
               "results":{
                  "href":"http://cikrf.ru/iservices/sgo-visual-rest/vibory/457422069597/results/457422069602/major"
               }
            }
         },
         ...
      ]
   },
   "_links":{
      "self":{
         "href":"http://cikrf.ru/iservices/sgo-visual-rest/vibory/457422069597/tvd"
      }
   }
}




NUMTVD est le numéro du comté. Le numéro zéro est généralement responsable des résultats pour un seul district. Par exemple, si les élections se déroulent dans un système mixte, la «circonscription zéro» est responsable du vote selon un système proportionnel. Les autres circonscriptions sont uninominales ou plurinominales.



Comme vous pouvez le voir, la structure de données contient également un lien qui peut être utilisé pour connaître les résultats des élections. Le lien est généré avant même la publication des résultats du vote.






Liste des candidats participant à la campagne électorale



http://cikrf.ru/iservices/sgo-visual-rest/vibory/CAMPAIGN_VRN/candidates/?page=PAGE_NUM&numokr=NUMTVD


  • CAMPAIGN_VRN - ID de campagne
  • PAGE_NUM - numéro de page de la liste
  • NUMTVD - numéro de comté (facultatif)


Exemple de demande:



http://cikrf.ru/iservices/sgo-visual-rest/vibory/ 4674220125616 / candidats /? Page = 1 & numokr = 11



Résultat de la requête
{
   "_embedded":{
      "candidateDtoList":[
         ...
         {
            "index":50,
            "vrn":4674020270868,
            "fio":"  ",
            "datroj":"23.04.1964 00:00:00",
            "vidvig":"",
            "registr":"",
            "vrnio":4674220132098,
            "namio":"    \"     \"   ",
            "numokr":11,
            "tekstat2":"1",
            "_links":{
               "self":{
                  "href":"http://cikrf.ru/iservices/sgo-visual-rest/vibory/4674220125616/candidates/4674020270868"
               }
            }
         },
         {
            "index":56,
            "vrn":4674020269642,
            "fio":"  ",
            "datroj":"15.02.1986 00:00:00",
            "vidvig":"",
            "registr":"  ",
            "namio":"",
            "numokr":11,
            "tekstat2":"1",
            "_links":{
               "self":{
                  "href":"http://cikrf.ru/iservices/sgo-visual-rest/vibory/4674220125616/candidates/4674020269642"
               }
            }
         },
         {
            "index":105,
            "vrn":4674020271181,
            "fio":"  ",
            "datroj":"15.07.1994 00:00:00",
            "vidvig":"",
            "registr":"",
            "vrnio":4674220134054,
            "namio":"     \"   \"",
            "numokr":11,
            "tekstat2":"1",
            "_links":{
               "self":{
                  "href":"http://cikrf.ru/iservices/sgo-visual-rest/vibory/4674220125616/candidates/4674020271181"
               }
            }
         },
         ...
         
      ]
   },
   "_links":{
      "self":{
         "href":"http://cikrf.ru/iservices/sgo-visual-rest/vibory/4674220125616/candidates?page=1&numokr=11"
      }
   },
   "page":{
      "size":20,
      "totalElements":9,
      "totalPages":1,
      "number":1
   }
}




La structure de page contient le nombre total de pages, elle peut être utilisée pour déterminer quand vous atteignez la dernière page (ou par une liste vide renvoyée par le serveur).






L'API contient d'autres méthodes, principalement pour obtenir plus d'informations sur les élections / candidats. Si nécessaire, vous pouvez facilement suivre les demandes requises. Maintenant, vous pouvez commencer à télécharger des données.



Téléchargement de données depuis le site Web de la CEC



Avant de commencer à télécharger les données nécessaires, il était nécessaire de dresser une liste des campagnes électorales que nous utiliserons dans le projet. Le fait est que le «Smart Voting» n'a pas eu lieu partout, mais lors d'élections:

— ,

— ,

— ( 200 )

( 4 ).

//


J'ai décidé d'ignorer les élections partielles à la Douma d'État, en raison de l'insignifiance de ces données. Un article de Wikipédia sur le jour des élections a aidé à dresser une liste des élections aux conseils locaux , car il ne faisait que lister les élections dans les grandes villes.



Me tournant vers un ami (qui m'a aidé à mettre en œuvre ce projet en effectuant le travail manuel requis), je lui ai demandé de compiler une liste d'URL pour les campagnes électorales respectives, en les prenant de la page principale du site Web classique de la CEC . Le fait est que l'URL contient les identifiants de région et de campagne dont nous aurons besoin pour une analyse plus approfondie.



vybory.izbirkom.ru/region/izbirkom?action=show&vrn=21120001136916&
region=11&prver=1&pronetvd=1


En conséquence, la liste comprenait 43 campagnes électorales. Au total, plus de 9 000 campagnes électorales distinctes ont été organisées dans les organes de différents niveaux le jour du scrutin unique.



Maintenant, avec la liste des choix et les méthodes API précédemment listées en main, il était facile de télécharger les données. Après avoir écrit un script python , effectué des requêtes régulières à l'aide du module de requêtes , j'ai enregistré les données sur les candidats et les bureaux de vote au format JSON d'origine.



Le principal élément à prendre en compte lors du téléchargement d'informations sur les bureaux de vote: il ne suffit pas de parcourir tous les numéros possibles à partir de 1 jusqu'à ce que le serveur renvoie une valeur vide. Le fait est que la numérotation des PEC dans la région peut être interrompue, et se présenter, par exemple, sous la forme suivante:

... # 1001 - # 1016, # 1101 - # 1136, 1138 ...

ou:

# 0 - # 700, # 900 - # 1002, 1004 ...

Pour déterminer le numéro PEC maximum dans la région et ne pas faire de demandes inutiles, j'ai collecté les données comme suit: j'ai essayé de télécharger des données sur les 1000 premiers numéros, puis vérifié si je + 1, i + 5, i + 100, i + 500, i + 1000 numéros correspondent à n'importe quel PEC (dans ce cas, poursuite du téléchargement).



De plus, je vous recommande de conserver le numéro PEC à partir duquel vous avez téléchargé les données sur le quartier. Le fait est que les données renvoyées ne contiennent pas le numéro PEC, mais seulement le nom sous la forme: "Commission électorale de circonscription n ° 100" . Le processus d'obtention du numéro PEC original, que j'ai dû gérer plus tard, a conduit à des bugs et à de la frustration à court terme. Il s'est avéré que la numérotation dans le nom des PEC dans certaines régions a un format différent.



Par exemple, en Oudmourtie, le nom du PEC avait la numérotation suivante: «№1 / 01, №1 / 02, №1 / 03» , dans la région de Lipetsk: «№01-01, №01-02, №01-03» . Dans la région d'Orenbourg, je suis tombé sur un vrai exotique: c'était la seule région où un certain nombre de commissions électorales portaient le nom de quelqu'un. Par exemple, "Commission électorale de circonscription no 1696 nommée d'après" Pustovitov Brothers "



Téléchargement de données depuis le site de "Smart Voting"



Désormais, pour chaque adresse PEC collectée, nous allons télécharger les données de vote depuis le site UMG. Avant cela, il convient de considérer plusieurs fonctionnalités (que j'ai apprises au cours du processus):



Premièrement, il est nécessaire de prendre en compte le fait que les adresses de la base de données CEC ont un format différent, parfois même dans certaines régions des régions. J'ai dû supprimer les abréviations «d.», «G.» et «st.», Puisque le site de «Smart Voting» n'était pas du tout capable de faire face à la recherche d'adresses pour de telles requêtes. Je recommande également de supprimer le code postal de l'adresse, ainsi que le préfixe parfois rencontré "Fédération de Russie".



Deuxièmement, le site Web UMG a une forte protection contre les attaques DDoS, et même si vous faites une centaine de requêtes avec un intervalle de 0,3 seconde, votre IP sera bannie. Il serait possible d'utiliser un ensemble de procurations payantes, mais personnellement, je viens d'utiliser des procurations gratuites et des demandes alternées de ma propre adresse IP et d'une adresse IP tierce. Afin de ne pas être banni, il y avait un intervalle d'environ 0,7 seconde entre les demandes. En conséquence, le téléchargement de toutes les données a pris environ une journée.



En utilisant les requêtes du premier chapitre, l'algorithme est le suivant:



  1. Formatage de l'adresse PEC
  2. Nous faisons une demande pour une liste d'adresses appropriées
  3. Nous obtenons une liste contenant les identifiants de page du site
  4. Nous vérifions si nous avons déjà téléchargé les données sur le site par cet identifiant
  5. Chargez la page HTML du site pour cet identifiant
  6. Nous extrayons l'élément «__NEXT_DATA__» et enregistrons les données au format JSON


La page a été analysée à l'aide de la bibliothèque beautifulsoup4 .



Ce processus n'est pas sans faille: généralement, le script ne trouve pas une douzaine de bureaux de vote dans la région sur le site Web, ou à l'adresse d'un PEC vous trouvez des informations sur un PEC complètement différent.



Peu importe, car pour chaque quartier, il suffit de trouver au moins une page correspondante sur le site.



Pour valider l'exhaustivité des données, nous écrivons un script simple qui vérifie si l'ensemble de données téléchargé depuis le site UMG contient des informations sur chaque circonscription. S'il manque quelque chose, nous reconstituons le jeu de données manuellement. Là encore, il y avait moins de 10 situations exceptionnelles de ce type sur 1 100 districts.



Combinaison des données des sites Web UMG et CEC



À ce stade, nous collectons une structure de données pratique , avec des informations sur chaque candidat par district: identifiant du candidat, nom complet, parti, tag avec des informations indiquant s'il est soutenu par l'UMG.



Exemple d'un ensemble de données candidat collecté
{
    "33": [
        {
            "name": "  ",
            "vrn": 4444032121758,
            "birthdate": "05.05.1958 00:00:00",
            "party": "",
            "smart_vote": 0
        },
        {
            "name": "  ",
            "vrn": 4444032122449,
            "birthdate": "16.11.1977 00:00:00",
            "party": "",
            "smart_vote": 0
        },
        {
            "name": "  ",
            "vrn": 4444032122782,
            "birthdate": "27.02.1996 00:00:00",
            "party": "",
            "smart_vote": 0
        },
        {
            "name": "  ",
            "vrn": 4444032123815,
            "birthdate": "20.11.1991 00:00:00",
            "party": "",
            "smart_vote": 1
        },
        {
            "name": "  ",
            "vrn": 4444032124060,
            "birthdate": "21.07.1996 00:00:00",
            "party": "",
            "smart_vote": 0
        },
        {
            "name": "  ",
            "vrn": 4444032123597,
            "birthdate": "21.05.1974 00:00:00",
            "party": "",
            "smart_vote": 0
        }
    ],
    ...
}




L'algorithme est assez simple:



  1. Sur la base du tableau de données du site Web d'UMG, nous créons une liste de candidats pris en charge pour chaque district
  2. À l'aide du tableau de données du site Web de la CEC, nous créons une liste filtrée des candidats admis pour chaque circonscription
  3. Dans chaque district, par nom, nous calculons la correspondance Candidat-UMG-Candidat-CEC


Bien entendu, un algorithme aussi simple doit tenir compte de nombreuses situations problématiques potentielles.



Premièrement, il est possible que dans une circonscription, il y ait des candidats avec des noms complètement identiques. Heureusement, parmi 5000 candidats, une telle situation ne se présentait que dans un cas, et aucun des candidats n'était soutenu par l'UMG.



Deuxièmement, il faut tenir compte du fait qu'il peut y avoir des erreurs dans la base de données du site Web de la CEC. L'erreur la plus courante: les sauts de ligne et les espaces supplémentaires dans le nom complet. De plus, lors de la collecte de données sur les résultats du vote, il y avait une situation dans laquelle la lettre «» dans le nom de famille était remplacée par «e».



Troisièmement, la pertinence des données doit être prise en compte. Les données sur le site Internet de la CEC et de l'UMG ont changé et mis à jour jusqu'à samedi: certains candidats ont été retirés / rétablis, dans certaines circonscriptions le soutien de l'UMG a changé.



Pour valider les listes UMG, un simple script a été écrit qui fait une demande par district (après tout, le jeu de données que nous avons collecté nous permet désormais d'identifier de manière unique la page dédiée à chaque district) et vérifie si les noms correspondent à ceux que nous avons reçus plus tôt.



Une tâche intéressante était d'identifier les parties par le nom de leurs succursales. Ce point pourrait être ignoré, mais j'ai décidé de le faire pour unifier les informations. Le problème est que les candidats d'un parti peuvent avoir des noms différents dans la base de données de la CEC. Par exemple, dans le cas du KPRF, il y avait plus de 40 options:



  ()    "   " 
-   ""
  
     "   "
...


La situation se transforme en un problème d'analyse intéressant, lorsqu'il y a 25 lots et presque chacun a une orthographe différente pour chaque région. Heureusement, avec l'aide de mon ami, qui m'a aidé dans tout le travail manuel, nous avons compilé une liste de mots-clés par lesquels le parti du candidat est uniquement déterminé.



Téléchargement des résultats des élections à partir du site Web de la CEC



L'ensemble de données collectées était suffisant pour atteindre l'objectif initial du projet - nous avons compilé des listes de candidats UMG-2020 pour chaque circonscription. Mais s'il existe une possibilité technique d'obtenir les résultats des élections, pourquoi ne pas en profiter?






Résultats des élections de district



http://cikrf.ru/iservices/sgo-visual-rest/vibory/CAMPAIGN_VRN/results/DISTRICT_VRN/major


  • CAMPAIGN_VRN - ID de campagne
  • DISTRICT_VRN - ID du district


Exemple de demande:

http://cikrf.ru/iservices/sgo-visual-rest/vibory/ 457422069597 / results / 457422069602 / major



Résultat de la requête
{
   "report":{
      "tvd":"",
      "date_sign":"none",
      "vrnvibref":"457422069597",
      "line":[
         {
            "txt":"     ",
            "kolza":"8488",
            "index":"1"
         },
         {
            "txt":" ,   ",
            "kolza":"6700",
            "index":"2"
         },
         ...
         {
            "txt":"  ",
            "kolza":"65",
            "index":"9"
         },
         {
            "txt":"  ",
            "kolza":"1948",
            "index":"10"
         },
         ...
         {
            "delimetr":"1"
         },
         {
            "txt":"  ",
            "numsved":"1",
            "kolza":"112",
            "index":"11",
            "namio":"    ",
            "perza":"5.56",
            "numsvreestr":"4574030258379"
         },
         {
            "txt":"  ",
            "numsved":"2",
            "kolza":"186",
            "index":"12",
            "namio":"     ",
            "perza":"9.24",
            "numsvreestr":"4574030258723"
         },
         {
            "txt":"  ",
            "numsved":"3",
            "kolza":"54",
            "index":"13",
            "namio":"",
            "perza":"2.68",
            "numsvreestr":"4574030258555"
         },
         ...
      ],
      "data_gol":"13.09.2020 00:00:00",
      "is_uik":"0",
      "type":"423",
      "version":"0",
      "sgo_version":"5.6.0",
      "isplann":"0",
      "podpisano":"1",
      "versions":{
         "ver":{
            "current":"true",
            "content":"0"
         }
      },
      "vibory":"        ",
      "repforms":"1",
      "generation_time":"14.09.2020 07:59:21",
      "nazv":"    () ",
      "datepodp":"14.09.2020 05:44:00"
   }
}




Comme vous pouvez le voir, les résultats sont renvoyés sous la forme du protocole de la commission régionale. Chaque région a un format de protocole différent et le nombre de lignes d'introduction qu'elle contient, une validation minutieuse des données que vous extrayez doit donc être effectuée.






Lorsque GAS Vybory a commencé à publier des résultats préliminaires, j'ai été confronté à une petite déception. Il s'est avéré que grâce à l'API, vous ne pouvez obtenir des données que sur les résultats officiellement approuvés. Les résultats préliminaires peuvent toujours être consultés sur l'ancien site Web de la commission électorale, mais pas via les nouveaux services Web.



Un jour plus tard, les résultats de 50% étaient connus, et à la fin de la semaine les résultats de presque toutes les élections étaient résumés, certaines régions refusaient toujours d'approuver les résultats. Au moment d'écrire ces lignes, 7 jours se sont écoulés et les résultats des élections à Tambov n'ont pas encore été approuvés. De plus, dans certaines circonscriptions, il y a un recomptage, c'est pourquoi ces résultats ne sont pas non plus disponibles via l'API.



Conclusion: les méthodes API ne sont actuellement pas adaptées pour recevoir rapidement les résultats des votes. Vous devrez soit attendre plus d'une semaine pour que les résultats soient approuvés, soit vous devrez analyser l'ancien site de la commission électorale, en trouvant un moyen de contourner le captcha.



J'en ai assez d'attendre que les élections soient approuvées dans environ 30 circonscriptions sur 1100, j'ai donc écrit un script en utilisant la bibliothèque de sélénium qui télécharge les données du site classique de la commission électorale et me demande de résoudre manuellement le captcha pour chaque demande. Avec un si petit nombre de requêtes, il ne faut pas longtemps pour résoudre manuellement un captcha.



En conséquence, j'ai collecté les données sur les résultats du vote dans la structure suivante :



Exemple de résultats de vote de comté
{
...
"33": {
        "candidate_total": {
            "4444032121758": 880,
            "4444032122449": 236,
            "4444032122782": 143,
            "4444032123597": 152,
            "4444032123815": 149,
            "4444032124060": 72
        },
        "is_final": 1,
        "non_valid_votes": 132,
        "registered_voters": 6928,
        "valid_votes": 1632
    },
...
}




Pour chaque circonscription, j'ai enregistré le nombre total d'électeurs sur les listes (pour calculer le taux de participation), le nombre de bulletins valides et non valides. La structure contient un dictionnaire: Identificateur du candidat -> Le nombre de votes qu'il a tapés.



Publication des résultats de l'UMG-2020



Tout d'abord, j'ai publié les données collectées au format JSON sur GitHub . Les données seront mises à jour jusqu'à ce que les résultats soient validés dans tous les districts.



Deuxièmement, pour attirer l'attention sur le projet, j'ai décidé de générer une feuille de calcul Google, qui contient toutes les données collectées sous une forme pratique pour l'analyse visuelle.



Je n'entrerai pas dans les détails, aucune difficulté (sauf pour étudier l'API Google Sheets) ne devrait survenir. Je recommande cet article , qui détaille l'interaction avec l'API Google Sheets en Python.



image



En conséquence, nous avons obtenu le tableau suivant, qui contient:





Épilogue



L'idée de ce mini-projet est venue 3 jours avant le jour du vote et je suis personnellement satisfait de la façon dont j'ai réussi à tout étudier et à tout mettre en œuvre dans les plus brefs délais (même si le code s'est avéré terrible).



Je ne vais pas tirer de conclusions sur les résultats de la stratégie de vote intelligent, je viens de fournir des outils pour les fans de statistiques électorales. Je suis sûr qu'il y en aura parmi vous et bientôt nous verrons de merveilleuses études, avec des graphiques et des diagrammes intéressants.



All Articles