Análisis del sitio web de Smart Voting y la nueva API en el sitio web de la CCA

imagen



El 13 de septiembre de 2020 se celebró un solo día de votación en Rusia. En algunas regiones, la oposición ha utilizado la estrategia de “Smart Voting”, mediante la cual los votantes con mentalidad de oposición votan por un solo candidato con la mayor probabilidad de derrotar a un representante de las autoridades.



Por segundo año consecutivo, el proceso de selección de candidatos para "Smart Voting" ha provocado discusiones sobre el tema de su transparencia. Además, personalmente me confunden las dificultades para resumir la estrategia que pueden enfrentar los analistas independientes. Los organizadores de la UMG no publican resultados detallados de la estrategia, sino solo diagramas que muestran cuántos candidatos de la oposición ingresaron al parlamento regional.



En el sitio de "Smart Voting"no puede obtener una lista de candidatos admitidos especificando, por ejemplo, ciudad y distrito. Si alguien quiere recopilar datos sobre la región, tendrá que hacer el monótono trabajo de seleccionar direcciones para cada distrito.



En ningún caso reprocho a los desarrolladores del sitio web de la UMG, tiene toda la funcionalidad requerida para implementar la estrategia de votación. Pero debido a que en 2019 nadie participó en la recopilación y publicación de datos detallados sobre los resultados de la UMG (fuera de las elecciones de Moscú), en estas elecciones decidí tomar la iniciativa en mis propias manos.



El resultado es una tabla resumen como esta . En este artículo, le diré cómo se obtuvo el conjunto de datos dado , cómo se recopiló la información de los sitios de Smart Voting y el nuevo servicio web de la CEC .



imagen



Sitio de votación inteligente



Primero, veamos qué datos podemos extraer del sitio de Smart Voting. En la página principal del sitio hay un campo para ingresar la dirección de registro del usuario. Cuando ingresa una cadena, aparece una lista de direcciones sugeridas en el siguiente formato:



imagen




Al elegir una de las direcciones propuestas, se nos lleva a la página del colegio electoral a la que se adjunta la dirección seleccionada:



imagen


La página enumera las campañas electorales que tienen lugar en este sitio. Para cada campaña, hay una lista de candidatos a favor / en contra de los cuales se le ofrece votar:



imagen


En este caso, vemos la elección del gobernador, para lo cual la UMG no indicó candidato de oposición. Esto se debe a que las elecciones de gobernadores se realizan en dos rondas y no importa a cuál de los candidatos de la oposición votarán los votantes en la primera ronda.

También vemos tres candidatos a la vez, por quienes se les ofrece votar en las elecciones al parlamento de la ciudad. Esto se debe al hecho de que las elecciones en Sochi tienen distritos electorales de varios miembros.

En todas las demás campañas electorales, involucradas en la UMG este año, solo hubo distritos electorales de un solo miembro.



Veamos el código de la página y veamos que todos los datos descritos se recopilan en un formato JSON conveniente. En el elemento con id = "__ NEXT_DATA__", que se utiliza para dibujar la página, hay información sobre el colegio electoral, las campañas electorales correspondientes y los candidatos:



Contenido del elemento __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
}




Para la mesa de votación, el número (número) del PEC correspondiente y su identificador se indican en la base de datos de la web de la UMG. Id = 440834 coincide con el número que se encuentra en la URL de la página (/ candidatos / 440834).



¿Podemos, conociendo el número de PEC y la región, calcular el identificador de comisión en el sitio web de UMG? No pude encontrar una dependencia obvia, ya que los identificadores se distribuyen de manera bastante caótica:

Sochi, PEC # 4512 -> id = 440834

Sochi, PEC # 4513 -> id = 441403

Sochi, PEC # 4514 -> id = 1781216



Cómo recopilar una lista de reflejos de números PEC en páginas de identificación? Suena extremadamente ineficiente iterar y verificar todo tipo de identificadores de 1 a 2,000,000, la mayoría de estos identificadores no funcionan.



Pero, si tenemos una lista de direcciones, podemos armar con relativa facilidad una lista de los colegios electorales relevantes. Cuando ingresa una cadena en la pantalla inicial, el servidor devuelve una lista de direcciones adecuadas, junto con los identificadores de comisión correspondientes:



Buscar un sitio por dirección



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


  • DIRECCIÓN - dirección, preferiblemente en el formato "Asunto, ciudad, calle, casa". También es deseable sin las abreviaturas "calle", "d.", Ya que el analizador del servidor no las maneja bien


Solicitud de ejemplo:



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



Resultado de la consulta
{
   "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
         }
      },
...
   ]
}




¿Dónde puedo obtener una lista de direcciones para extraer datos del sitio? Enumerar la base de datos de todas las direcciones del país parece una solución ineficaz, porque para resolver nuestro problema solo necesitamos una dirección por circunscripción.



Cada circunscripción tiene un promedio de 2 a 8 distritos. Aunque la dirección de una mesa electoral, en casos excepcionales, puede no corresponder a la circunscripción a la que pertenece, presento la siguiente hipótesis: al revisar las direcciones de PEC en el sitio web de la UMG, puede recopilar información sobre cada circunscripción.



Más tarde, utilizando esta hipótesis, pude recopilar información sobre casi todos los distritos electorales. Debido a la heterogeneidad del formato de dirección en la base de datos de las comisiones electorales, solo las direcciones de 10 de 1100 distritos electorales tuve que seleccionar manualmente.



En Internet, puede encontrar una base de datos actualizada periódicamente de las comisiones electorales de la Federación de Rusia , que contiene información sobre las direcciones e incluso la composición de los PEC. Pero para una mayor relevancia y confiabilidad de los datos (y también porque no estaba satisfecho con el formato de cierto campo), decidí recopilar la lista de direcciones yo mismo, porque, como resultó, el sitio web de la CEC tiene toda la funcionalidad necesaria para esto.



Nuevo servicio web CEC. Métodos API



GAS "Vybory" es un sistema automatizado, desarrollado en 1995, destinado a la preparación y realización de elecciones y referendos en la Federación de Rusia.



Si alguna vez ha estado interesado en el progreso de la campaña electoral, probablemente se haya encontrado con este sitio web , que se publica con la información básica del Sistema SAS "Elecciones", incluido el progreso del conteo de votos, incluso antes de la aprobación de los resultados de las elecciones:



imagen



Y si antes, para recuperar los resultados de las elecciones Usé este sitio, durante los días de la Votación de enmiendas a la Constitución , un captcha apareció repentinamente en el sitio . El captcha es muy persistente, aparece cuando vas a cada página del sitio:



imagen


Como usted mismo puede evaluar visualmente, el captcha es, por supuesto, muy simple, y seguramente alguien ya ha encontrado formas de evitarlo. En lugar de hacer aprendizaje automático, pasé a una nueva sección en el sitio web de la CCA, que pocas personas conocen todavía: Servicios digitales



imagen



Esta sección apareció justo durante la votación de enmiendas y contiene varios servicios web que, a través de HTTP las solicitudes se comunican con la API interna para recibir datos del sistema GAS "Vybory". El usuario de Habr ya ha prestado atención a esta funcionalidad. Consideremos esto con más detalle.



La siguiente es una descripción de las principales solicitudes de la nueva API que se utilizaron en este proyecto:



Cada estructura de datos en el sistema contiene una clave VRN- un identificador único para la entidad, ya sea un sitio, campaña, distrito o candidato .




Información PEC



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




Solicitud de ejemplo:



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



Resultado de la consulta
{
   "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"
   }
}







Información sobre campañas electorales en el sitio



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


  • COMMITTEE_VRN - Identificador de PEC


Ejemplo de solicitud:



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



Resultado de la consulta
[
   {
      "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"
   }
]





Lista de distritos electorales



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


  • CAMPAIGN_VRN : ID de campaña


Ejemplo de solicitud:



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



Resultado de la consulta
{
   "_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 es el número de condado. El número cero suele ser responsable de los resultados de un solo distrito. Por ejemplo, si las elecciones se celebran bajo un sistema mixto, la "circunscripción cero" es responsable de votar bajo un sistema proporcional. El resto de las circunscripciones son de un solo miembro o de varios miembros.



Como puede ver, la estructura de datos también contiene un enlace que se puede utilizar para conocer los resultados de las elecciones. El enlace se genera incluso antes de la publicación de los resultados de la votación.






Lista de candidatos que participan en la campaña electoral



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


  • CAMPAIGN_VRN : ID de campaña
  • PAGE_NUM : número de página de lista
  • NUMTVD - número de condado (opcional)


Ejemplo de solicitud:



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



Resultado de la consulta
{
   "_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 estructura de la página contiene el número total de páginas, se puede utilizar para determinar cuándo llega a la última página (o mediante una lista vacía devuelta por el servidor).






La API contiene otros métodos, principalmente para obtener más información sobre elecciones / candidatos. Si es necesario, puede rastrear fácilmente las solicitudes requeridas. Ahora, puede comenzar a cargar datos.



Descarga de datos del sitio web de la CCA



Antes de proceder con la descarga de los datos necesarios, fue necesario compilar una lista de campañas electorales que usaremos en el proyecto. El caso es que el “Smart Voting” no tuvo lugar en todas partes, sino en las elecciones:

— ,

— ,

— ( 200 )

( 4 ).

//


Decidí ignorar las elecciones parciales a la Duma del Estado, por la insignificancia de estos datos. Un artículo de Wikipedia sobre el día de las elecciones ayudó a compilar una lista de elecciones para los consejos locales , porque solo enumeraba las elecciones en las grandes ciudades.



Dirigiéndome a un amigo (que me ayudó a implementar este proyecto haciendo el trabajo manual requerido), le pedí que compilara una lista de URL para las respectivas campañas electorales, tomándolas de la página principal del sitio web clásico de la CCA . El hecho es que la URL contiene los identificadores de región y campaña que necesitaremos para analizar más.



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


Como resultado, la lista constaba de 43 campañas electorales. En total, se llevaron a cabo más de 9000 campañas electorales separadas en los órganos de varios niveles en el Día de Elección Única.



Ahora, con la lista de opciones y los métodos API enumerados anteriormente en la mano, fue fácil descargar los datos. Al escribir un script de Python , hacer solicitudes regulares usando el módulo de solicitudes , guardé los datos sobre candidatos y mesas de votación en el formato JSON original.



Lo principal a tener en cuenta al descargar información sobre los colegios electorales: no es suficiente clasificar todos los números posibles desde 1 hasta que el servidor devuelve un valor vacío. El caso es que se puede interrumpir la numeración de PECs en la región, y pasar, por ejemplo, de la siguiente forma:

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

o:

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

Para determinar el máximo número de PEC en la región y no realizar solicitudes innecesarias, he recogido los datos de la siguiente manera: traté de cargar datos en los primeros 1000 números y, a continuación, comprobé si i Los números + 1, i + 5, i + 100, i + 500, i + 1000 corresponden a cualquier PEC (en cuyo caso, la descarga continúa).



Además, recomiendo mantener el número de PEC del que descargó los datos sobre el recinto. El hecho es que los datos devueltos no contienen el número de PEC, sino solo el nombre en el formulario: "Comisión Electoral de Precinto No. 100" . El proceso de obtención del número PEC original, con el que tuve que lidiar más tarde, provocó errores a corto plazo y frustración. Al final resultó que, la numeración en el nombre de los PEC en algunas regiones tiene un formato diferente.



Por ejemplo, en Udmurtia, el nombre del PEC tenía la siguiente numeración: “№1 / 01, №1 / 02, №1 / 03" , en la región de Lipetsk: "№01-01, №01-02, №01-03" . En la región de Orenburg, me encontré con algo realmente exótico: era la única región donde varias comisiones electorales llevaban el nombre de alguien. Por ejemplo, "Comisión electoral de distrito núm. 1696 que lleva el nombre de" Hermanos Pustovitov "



Descarga de datos del sitio de "Smart Voting"



Ahora, para cada dirección PEC recopilada, vamos a descargar los datos de votación del sitio web de UMG. Antes de eso, vale la pena considerar varias características (que aprendí en el proceso):



Primero, es necesario tomar en cuenta que las direcciones en la base de datos de la CCA tienen un formato diferente, a veces incluso en ciertas regiones de las regiones. Tuve que eliminar las abreviaturas "d.", "G." y "st.", Ya que el sitio de "Smart Voting" no podía hacer frente a la búsqueda de direcciones para este tipo de consultas. También recomiendo eliminar el código postal de la dirección, así como el prefijo "Federación de Rusia" que a veces se encuentra.



En segundo lugar, el sitio de UMG tiene una fuerte protección contra ataques DDoS, e incluso si realiza cien solicitudes con un intervalo de 0.3 segundos, su IP será prohibida. Sería posible usar un conjunto de proxies pagados, pero personalmente solo usé proxies gratuitos y solicitudes alternas de mi propia IP y la de un tercero. Para no ser baneado, hubo un intervalo de aproximadamente 0,7 segundos entre las solicitudes. Como resultado, descargar todos los datos tomó alrededor de un día.



Usando las consultas del primer capítulo, el algoritmo es el siguiente:



  1. Formateo de la dirección PEC
  2. Solicitamos una lista de direcciones adecuadas.
  3. Obtenemos una lista que contiene los ID de las páginas del sitio.
  4. Comprobamos si ya hemos descargado los datos sobre el sitio mediante este identificador
  5. Cargue la página HTML del sitio para este identificador
  6. Extraemos el elemento "__NEXT_DATA__" y guardamos los datos en formato JSON


La página se analizó utilizando la biblioteca beautifulsoup4 .



Este proceso no es perfecto: por lo general, el guión no encuentra una docena de colegios electorales de la región en el sitio web, o en la dirección de un PEC se encuentra información sobre un PEC completamente diferente.



No importa, porque para cada distrito, solo necesitamos encontrar al menos una página correspondiente en el sitio.



Para validar la integridad de los datos, escribimos un script simple que verifica si el conjunto de datos descargado del sitio de UMG contiene información sobre cada grupo. Si falta algo, reponemos el conjunto de datos manualmente. Una vez más, hubo menos de 10 situaciones excepcionales de este tipo en 1,100 distritos.



Combinando datos de los sitios web de UMG y CEC



En esta etapa, recopilamos una estructura de datos conveniente , con información sobre cada candidato por distrito: identificación del candidato, nombre completo, partido, etiqueta con información sobre si cuenta con el apoyo de la UMG.



Ejemplo de un conjunto de datos candidato recopilado
{
    "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
        }
    ],
    ...
}




El algoritmo es bastante sencillo:



  1. Basándonos en la matriz de datos del sitio web de UMG, creamos una lista de candidatos admitidos para cada distrito.
  2. Utilizando la matriz de datos del sitio web de la CCA, creamos una lista filtrada de candidatos admitidos para cada circunscripción
  3. En cada distrito, por nombre, calculamos la correspondencia Candidate-UMG-Candidate-CEC


Por supuesto, un algoritmo tan simple debe tener en cuenta muchas situaciones problemáticas potenciales.



Primero, existe la posibilidad de que en una circunscripción haya candidatos con nombres completamente idénticos. Afortunadamente, entre 5000 candidatos, tal situación fue solo en un caso, y ninguno de los candidatos fue apoyado por la UMG.



En segundo lugar, debe tenerse en cuenta que pueden existir errores en la base de datos del sitio web de la CCA. El error más común: saltos de línea y espacios adicionales en el nombre completo. Además, al recopilar datos sobre los resultados de la votación, hubo una situación en la que la letra "" del apellido fue reemplazada por "e".



En tercer lugar, debe tenerse en cuenta la relevancia de los datos. Los datos en el sitio web de la CCA y UMG cambiaron y actualizaron hasta el sábado: algunos candidatos fueron removidos / restaurados, en algunas circunscripciones cambió el apoyo de la UMG.



Para validar las listas de UMG, se escribió un script simple que hace una solicitud por distrito (después de todo, el conjunto de datos que hemos recopilado ahora nos permite identificar de manera única la página dedicada a cada distrito) y verifica si los nombres coinciden con los que recibimos antes.



Una tarea interesante fue la identificación de los partidos por el nombre de sus sucursales. Este punto podría omitirse, pero decidí hacerlo para unificar la información. El problema es que los candidatos de un partido pueden tener diferentes nombres en la base de datos de la CCA. Por ejemplo, en el caso del KPRF, había más de 40 opciones:



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


La situación se convierte en un problema de análisis interesante, cuando hay 25 lotes y casi cada uno tiene una ortografía diferente para cada región. Afortunadamente, con la ayuda de mi amigo, quien me ayudó con todo el trabajo manual, compilamos una lista de palabras clave por las cuales se determina de manera única el partido del candidato.



Carga de resultados electorales del sitio web de la CCA



El conjunto de datos recopilados fue suficiente para lograr el objetivo inicial del proyecto: compilamos listas de candidatos UMG-2020 para cada circunscripción. Pero si existe una oportunidad técnica para obtener los resultados de las elecciones, ¿por qué no aprovecharla?






Resultados de las elecciones de distrito



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


  • CAMPAIGN_VRN : ID de campaña
  • DISTRICT_VRN : ID de distrito


Ejemplo de solicitud:

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



Resultado de la consulta
{
   "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"
   }
}




Como puede ver, los resultados se devuelven en forma de protocolo de la comisión regional. Cada región difiere en el formato del protocolo y el número de líneas introductorias en él, por lo que se debe realizar una validación cuidadosa de los datos que extrajo.






Cuando GAS "Vybory" comenzó a publicar resultados preliminares, me encontré con una pequeña decepción. Resultó que a través de la API puede obtener datos solo sobre aquellos resultados que están aprobados oficialmente. Los resultados preliminares todavía se pueden ver en el antiguo sitio web de la comisión electoral, pero no a través de los nuevos servicios web.



Un día después se conocieron los resultados del 50%, y al final de la semana se resumieron los resultados de casi todas las elecciones, algunas regiones aún se negaron a aprobar los resultados. En el momento de escribir este artículo, han pasado 7 días y los resultados de las elecciones en Tambov aún no han sido aprobados. Además, en algunos distritos existe un recuento, por lo que estos resultados tampoco están disponibles a través de la API.



Conclusión: los métodos API actualmente no son adecuados para recibir rápidamente los resultados de la votación. Tendrá que esperar más de una semana para que se aprueben los resultados, o tendrá que analizar el antiguo sitio de la comisión electoral, encontrando una manera de evitar el captcha.



Estoy cansado de esperar a que se aprueben las elecciones en ~ 30 de los 1100 distritos electorales, así que escribí un script usando la biblioteca de selenio que descarga datos del sitio clásico de la comisión electoral y me pide que resuelva manualmente el captcha para cada solicitud. Con una cantidad tan pequeña de solicitudes, no se necesita mucho tiempo para resolver manualmente un captcha.



Como resultado, recopilé los datos sobre los resultados de la votación en la siguiente estructura :



Ejemplo de resultados de votación del condado
{
...
"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
    },
...
}




Para cada circunscripción, guardé el número total de votantes en las listas (para calcular la participación), el número de boletas válidas e inválidas. La estructura contiene un diccionario: Identificador del candidato -> El número de votos que escribió.



Publicación de los resultados de la UMG-2020



Primero, publiqué los datos recopilados en formato JSON en GitHub . Los datos se actualizarán hasta que los resultados se validen en todos los distritos.



En segundo lugar, para llamar la atención sobre el proyecto, decidí generar una hoja de cálculo de Google, que contiene todos los datos recopilados en una forma conveniente para el análisis visual.



No entraré en detalles, no deberían surgir dificultades (excepto para estudiar la API de Google Sheets). Recomiendo este artículo , que detalla la interacción con la API de Google Sheets en Python.



imagen



Como resultado, obtuvimos la siguiente tabla, que contiene:





Epílogo



La idea de este mini-proyecto surgió 3 días antes del día de la votación, y personalmente estoy satisfecho de cómo logré estudiar e implementar todo en el menor tiempo posible (aunque el código resultó terrible).



No voy a sacar ninguna conclusión sobre los resultados de la estrategia Smart Voting, solo proporcioné herramientas para los fanáticos de las estadísticas electorales. Estoy seguro de que habrá algunos entre ustedes y pronto veremos estupendos estudios, con interesantes gráficos y diagramas.



All Articles