데이터

선관위 웹사이트에서 데이터를 다운로드 받습니다.

서울시장

선관위 웹사이트 에서 2021년 서울/부산 시장 재보궐선거 개표결과를 공지하여 데이터를 제공하고 있다.

서울시장 - 종로구

# 0. 환경설정 -----
library(tidyverse)
library(rvest)
library(httr)

# 1. 데이터 받아오기 -----
## 1.1 POST() 함수를 사용하여 개표 결과를 수집합니다.
resp <- POST(
    url = 'http://info.nec.go.kr/electioninfo/electionInfo_report.xhtml',
    encode = 'form', 
    body = list(
       electionId = "0020210407",
       requestURI = "/WEB-INF/jsp/electioninfo/0020210407/vc/vccp08.jsp",
       topMenuId = "VC",
       secondMenuId = "VCCP08",
       menuId = "VCCP08",
       statementId = "VCCP08_#3",
       electionCode = "3",
       cityCode = "1100",
       sggCityCode = "-1",
       townCodeFromSgg = "-1",
       townCode = "1101",
       checkCityCode = "-1",
       x = "17",
       y = "9"
    )
  )

vote_raw <- content(x=resp, as = 'text') %>% 
  read_html() %>% 
  html_node(xpath = '//*[@id="table01"]') %>% 
  html_table(fill=TRUE) %>% 
  janitor::clean_names() %>% 
  as_tibble() 

vote_tbl <- vote_raw %>% 
    set_names(c("읍면동명", "투표구명", "선거인수", "투표수", "민주당", "국힘당", glue::glue("후보{1:10}"), "계", "무효", "기권")) %>% 
    select(읍면동명, 투표구명, 선거인수, 투표수, 민주당, 국힘당, 기권) %>% 
    slice(2:n()) %>% 
    mutate(읍면동명 = ifelse(읍면동명 == "", NA, 읍면동명)) %>% 
    mutate(읍면동명 = zoo::na.locf(읍면동명)) %>% 
    filter(읍면동명 != "합계", 
           투표구명 != "소계") %>% 
    mutate_at(c("선거인수", "투표수", "민주당", "국힘당", "기권"), parse_number) %>% 
    mutate(구명 = "종로구") %>% 
    relocate(구명, before = "읍면동명")

sum(vote_tbl$투표수) == 78852
[1] TRUE

서울시장 - 종로구 함수

get_vote <- function(gu_code) {
    resp <- POST(
        url = 'http://info.nec.go.kr/electioninfo/electionInfo_report.xhtml',
        encode = 'form', 
        body = list(
           electionId = "0020210407",
           requestURI = "/WEB-INF/jsp/electioninfo/0020210407/vc/vccp08.jsp",
           topMenuId = "VC",
           secondMenuId = "VCCP08",
           menuId = "VCCP08",
           statementId = "VCCP08_#3",
           electionCode = "3",
           cityCode = "1100",
           sggCityCode = "-1",
           townCodeFromSgg = "-1",
           townCode = gu_code,
           checkCityCode = "-1",
           x = "17",
           y = "9"
        )
      )
    
    vote_raw <- content(x=resp, as = 'text') %>% 
      read_html() %>% 
      html_node(xpath = '//*[@id="table01"]') %>% 
      html_table(fill=TRUE) %>% 
      janitor::clean_names() %>% 
      as_tibble() 
    
    vote_tbl <- vote_raw %>% 
        set_names(c("읍면동명", "투표구명", "선거인수", "투표수", "민주당", "국힘당", glue::glue("후보{1:10}"), "계", "무효", "기권")) %>% 
        select(읍면동명, 투표구명, 선거인수, 투표수, 민주당, 국힘당, 기권) %>% 
        slice(2:n()) %>% 
        mutate(읍면동명 = ifelse(읍면동명 == "", NA, 읍면동명)) %>% 
        mutate(읍면동명 = zoo::na.locf(읍면동명)) %>% 
    filter(읍면동명 != "합계", 
           투표구명 != "소계") %>% 
        mutate_at(c("선거인수", "투표수", "민주당", "국힘당", "기권"), parse_number) %>% 
        mutate(구코드 = gu_code) %>% 
        relocate(구코드, .before = "읍면동명")
    
    vote_tbl    
}

get_vote("1101")
# A tibble: 63 x 8
   구코드 읍면동명    투표구명     선거인수 투표수 민주당 국힘당  기권
   <chr>  <chr>       <chr>           <dbl>  <dbl>  <dbl>  <dbl> <dbl>
 1 1101   거소투표    ""                910    870    235    530    40
 2 1101   관외사전투표… ""               4962   4961   2218   2508     1
 3 1101   청운효자동  "관내사전투표"…     2318   2318   1296    952     0
 4 1101   청운효자동  "청운효자동제1투"…     2428   1187    404    732  1241
 5 1101   청운효자동  "청운효자동제2투"…     2408   1157    440    661  1251
 6 1101   청운효자동  "청운효자동제3투"…     2503   1274    554    638  1229
 7 1101   사직동      "관내사전투표"…     1737   1736    863    808     1
 8 1101   사직동      "사직동제1투"…     2305    919    354    530  1386
 9 1101   사직동      "사직동제2투"…     4191   2267    527   1666  1924
10 1101   삼청동      "관내사전투표"…      505    505    248    240     0
# … with 53 more rows

서울시장 - 서울시 전체

gu_code <- glue::glue("11{str_pad(1:25, width = 2, side='left', pad =0)}")

gu_name_tbl <- tribble(~"구코드", ~"구명",
"1101", "종로구",
"1102", "중구",
"1103", "용산구",
"1104", "성동구",
"1105", "광진구",
"1106", "동대문구",
"1107", "중랑구",
"1108", "성북구",
"1109", "강북구",
"1110", "도봉구",
"1111", "노원구",
"1112", "은평구",
"1113", "서대문구",
"1114", "마포구",
"1115", "양천구",
"1116", "강서구",
"1117", "구로구",
"1118", "금천구",
"1119", "영등포구",
"1120", "동작구",
"1121", "관악구",
"1122", "서초구",
"1123", "강남구",
"1124", "송파구",
"1125", "강동구")

# seoul_raw <- map_df(gu_code, get_vote)
# 
# seoul_tbl <- seoul_raw %>%
#     left_join(gu_name_tbl) %>%
#     select(-구코드) %>%
#     relocate(구명, .before = "읍면동명")
# 
# seoul_tbl %>%
#     write_rds("data/seoul_tbl.rds")

seoul_tbl <- read_rds("data/seoul_tbl.rds")

seoul_tbl %>% 
  reactable::reactable()

부산시장

부산시장 - 중구

# 1. 데이터 받아오기 -----
## 1.1 POST() 함수를 사용하여 개표 결과를 수집합니다.
pusan_resp <- POST(
    url = 'http://info.nec.go.kr/electioninfo/electionInfo_report.xhtml',
    encode = 'form', 
    body = list(
       electionId = "0020210407",
       requestURI = "/WEB-INF/jsp/electioninfo/0020210407/vc/vccp08.jsp",
       topMenuId = "VC",
       secondMenuId = "VCCP08",
       menuId = "VCCP08",
       statementId = "VCCP08_#3",
       electionCode = "3",
       cityCode = "2600",
       sggCityCode = "-1",
       townCodeFromSgg = "-1",
       townCode = "2601",
       checkCityCode = "-1",
       x = "17",
       y = "9"
    )
  )

busan_vote_raw <- content(x = pusan_resp, as = 'text') %>% 
  read_html() %>% 
  html_node(xpath = '//*[@id="table01"]') %>% 
  html_table(fill=TRUE) %>% 
  janitor::clean_names() %>% 
  as_tibble() 

busan_vote_tbl <- busan_vote_raw %>% 
    set_names(c("읍면동명", "투표구명", "선거인수", "투표수", "민주당", "국힘당", glue::glue("후보{1:4}"), "계", "무효", "기권")) %>% 
    select(읍면동명, 투표구명, 선거인수, 투표수, 민주당, 국힘당, 기권) %>% 
    slice(2:n()) %>% 
    mutate(읍면동명 = ifelse(읍면동명 == "", NA, 읍면동명)) %>% 
    mutate(읍면동명 = zoo::na.locf(읍면동명)) %>% 
    filter(읍면동명 != "합계", 
           투표구명 != "소계") %>% 
    mutate_at(c("선거인수", "투표수", "민주당", "국힘당", "기권"), parse_number) %>% 
    mutate(구명 = "중구") %>% 
    relocate(구명, before = "읍면동명")

busan_vote_tbl
# A tibble: 34 x 8
   구명  before      투표구명      선거인수 투표수 민주당 국힘당  기권
   <chr> <chr>       <chr>            <dbl>  <dbl>  <dbl>  <dbl> <dbl>
 1 중구  거소투표    ""                 208    199     68     91     9
 2 중구  관외사전투표… ""                1332   1332    559    710     0
 3 중구  중앙동      "관내사전투표"…      334    334    130    187     0
 4 중구  중앙동      "중앙동제1투"     1126    308    103    187   818
 5 중구  중앙동      "중앙동제2투"      798    263     87    159   535
 6 중구  동광동      "관내사전투표"…      619    619    236    363     0
 7 중구  동광동      "동광동제1투"     1126    349    118    220   777
 8 중구  동광동      "동광동제2투"      986    395    121    258   591
 9 중구  대청동      "관내사전투표"…      914    914    371    524     0
10 중구  대청동      "대청동제1투"     2017    755    241    485  1262
# … with 24 more rows

부산시장 - 중구 함수

get_busan_vote <- function(gu_code) {
    resp <- POST(
        url = 'http://info.nec.go.kr/electioninfo/electionInfo_report.xhtml',
        encode = 'form', 
        body = list(
           electionId = "0020210407",
           requestURI = "/WEB-INF/jsp/electioninfo/0020210407/vc/vccp08.jsp",
           topMenuId = "VC",
           secondMenuId = "VCCP08",
           menuId = "VCCP08",
           statementId = "VCCP08_#3",
           electionCode = "3",
           cityCode = "2600",
           sggCityCode = "-1",
           townCodeFromSgg = "-1",
           townCode = gu_code,
           checkCityCode = "-1",
           x = "17",
           y = "9"
        )
      )
    
    vote_raw <- content(x=resp, as = 'text') %>% 
      read_html() %>% 
      html_node(xpath = '//*[@id="table01"]') %>% 
      html_table(fill=TRUE) %>% 
      janitor::clean_names() %>% 
      as_tibble() 
    
    vote_tbl <- vote_raw %>% 
        set_names(c("읍면동명", "투표구명", "선거인수", "투표수", "민주당", "국힘당", glue::glue("후보{1:4}"), "계", "무효", "기권")) %>% 
        select(읍면동명, 투표구명, 선거인수, 투표수, 민주당, 국힘당, 기권) %>% 
        slice(2:n()) %>% 
        mutate(읍면동명 = ifelse(읍면동명 == "", NA, 읍면동명)) %>% 
        mutate(읍면동명 = zoo::na.locf(읍면동명)) %>% 
    filter(읍면동명 != "합계", 
           투표구명 != "소계") %>% 
        mutate_at(c("선거인수", "투표수", "민주당", "국힘당", "기권"), parse_number) %>% 
        mutate(구코드 = gu_code) %>% 
        relocate(구코드, .before = "읍면동명")
    
    vote_tbl    
}

get_busan_vote("2601")
# A tibble: 34 x 8
   구코드 읍면동명    투표구명     선거인수 투표수 민주당 국힘당  기권
   <chr>  <chr>       <chr>           <dbl>  <dbl>  <dbl>  <dbl> <dbl>
 1 2601   거소투표    ""                208    199     68     91     9
 2 2601   관외사전투표… ""               1332   1332    559    710     0
 3 2601   중앙동      "관내사전투표"…      334    334    130    187     0
 4 2601   중앙동      "중앙동제1투"…     1126    308    103    187   818
 5 2601   중앙동      "중앙동제2투"…      798    263     87    159   535
 6 2601   동광동      "관내사전투표"…      619    619    236    363     0
 7 2601   동광동      "동광동제1투"…     1126    349    118    220   777
 8 2601   동광동      "동광동제2투"…      986    395    121    258   591
 9 2601   대청동      "관내사전투표"…      914    914    371    524     0
10 2601   대청동      "대청동제1투"…     2017    755    241    485  1262
# … with 24 more rows

부산시장 - 부산시 전체

gu_busan_code <- glue::glue("26{str_pad(1:16, width = 2, side='left', pad =0)}")
gu_name_busan_tbl <- tribble(~"구코드", ~"구명",
                              "2601", "중구",
                              "2602", "서구",
                              "2603", "동구",
                              "2604", "영도구",
                              "2605", "부산진구",
                              "2606", "동래구",
                              "2607", "남구",
                              "2608", "북구",
                              "2609", "해운대구",
                              "2610", "기장군",
                              "2611", "사하구",
                              "2612", "금정구",
                              "2613", "강서구",
                              "2614", "연제구",
                              "2615", "수영구",
                              "2616", "사상구")

# busan_raw <- map_df(gu_busan_code, get_busan_vote)
# 
# busan_tbl <- busan_raw %>%
#     left_join(gu_name_busan_tbl) %>%
#     select(-구코드) %>%
#     relocate(구명, .before = "읍면동명")
# 
# busan_tbl %>%
#     write_rds("data/busan_tbl.rds")

busan_tbl <- read_rds("data/busan_tbl.rds")

busan_tbl %>% 
  reactable::reactable()