Как я могу использовать Красивый суп, чтобы очистить данные о выборах - PullRequest
2 голосов
/ 01 июля 2019

Я пытаюсь вычеркнуть результаты выборов на техасских всеобщих выборах 2018 года.У меня есть следующий код, но я не могу избавиться от строки итогов.Есть побочный эффект, заставляющий всех не американских представителей быть помеченными также.

import requests
from bs4 import BeautifulSoup
import re, os, csv

fileDir = os.path.dirname(__file__)
csvFile = os.path.join(fileDir, 'election2018.csv')

sos_2018_site = 'https://elections.sos.state.tx.us/elchist331_state.htm'
r = requests.get(sos_2018_site)

soup = BeautifulSoup(r.text)
district_campaigns = soup.find_all(text=re.compile('^U. S. Representative District'))
districts = [district.string for district in district_campaigns]

table_rows = soup.find_all('tr')
# print(us_rep)
for district in district_campaigns:
    candidate = district.parent.parent.next_sibling.td.next_element

current_district = ''
with open(csvFile, 'w') as csv_file:
    writer = csv.writer(csv_file, delimiter=',')
    for tr in table_rows:
        table_data = []
        for td in tr.children:
            if td.string in districts:
                current_district = td.string
                continue
            if td.string == None:
                continue
            table_data.append(td.string)
        table_data.append(current_district)
        if any("U. S. Representative" in s for s in table_data) and any("-" not in s for s in table_data):
            writer.writerow(table_data)

Ответы [ 2 ]

3 голосов
/ 01 июля 2019

Хотелось бы сделать быстрое исправление, но вот переписывание с использованием итераторов (не знаю, удобны ли вы с ними - одна проблема при отладке, вам нужно преобразовать генератор в список, используя list(...)).

Основная идея состоит в том, чтобы извлечь список списков строк из HTML, используя BeautifulSoup, аналогично чтению CSV, а затем отфильтровать списки по мере необходимости.

Также хорошая идея дляотдельная логика синтаксического анализа (создание переменной output ниже) и операция сохранения файла.Таким образом, код легче модифицировать и «рассуждать».

import re
import csv
import itertools

import requests
from bs4 import BeautifulSoup

def row_to_list(tr):
    return list(map(lambda x: x.string, tr.children))

def is_separator(x):
    try: 
        return x[0].startswith("-")
    except AttributeError:
        return False

def separate_by(xs, sep_func):
    return [list(x[1]) for x in itertools.groupby(xs, sep_func) if not x[0]] 

def is_representative(block):
    return block[0][0].startswith("U. S. Representative District")

def num_district(headline):
    return re.search("\d+", headline)[0]

def yield_entry(block):
    """
    Args:
    - *block* example:
     [['U. S. Representative District 4 - ', None, None, None],
     [None, 'John Ratcliffe(I)', 'REP', '188,667', '75.70%'],
     [None, 'Catherine Krantz', 'DEM', '57,400', '23.03%'],
     [None, 'Ken Ashby', 'LIB', '3,178', '1.28%'],
     [None, None, None, '-----------', None],
     [None, None, 'Race Total', '249,245\n', None]]
    """
    district = num_district(block[0][0])
    for line in block[1:-2]:
        line[0] = district
        line[3] = line[3].replace(",", "")
        yield line

if __name__ == "__main__":
    sos_2018_site = 'https://elections.sos.state.tx.us/elchist331_state.htm'
    r = requests.get(sos_2018_site)
    soup = BeautifulSoup(r.text, features="lxml")
    table_rows = soup.find_all('tr')
    table = [row_to_list(tr) for tr in table_rows]
    blocks = separate_by(table, is_separator)
    blocks_rep = filter(is_representative, blocks)        
    output = []
    for br in blocks_rep:
        for k in yield_entry(br): 
            print(k)         
            output.append(k)
    with open('election2018.csv', 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerows(output)

PS После написания этого кода я думаю, что любая настоящая демократия должна сообщать о результатах выборов в JSON, а не в HTML.

1 голос
/ 02 июля 2019
import requests

from bs4 import BeautifulSoup
import re, os
import pandas as pd

fileDir = os.path.dirname(__file__)
csvFile = os.path.join(fileDir, 'election2018.csv')

sos_2018_site = 'https://elections.sos.state.tx.us/elchist331_state.htm'

r = requests.get(sos_2018_site)
soup = BeautifulSoup(r.text)
trs=soup.findAll('tr')

vote_type=''
result_list=[]

for tr in trs[1:]:
    tds=tr.findAll('td')
    try:
        if tds[0]['colspan']=='2':
            vote_type=re.sub(' - $', '', tds[0].text)
    except KeyError:
        if re.search('Race Total',tds[2].text) is None and re.search('-{2,}',tds[3].text) is None:
            result_list.append({'TYPE':vote_type, 'NAME':tds[1].text, 'PARTY':tds[2].text, 'VOTE':int(tds[3].text.replace(',', '')), 'PERCENT':float(tds[4].text.replace('%', ''))})


pdf_vote=pd.DataFrame(result_list)
pdf_vote.to_csv(csvFile, sep=';', index=False)

Я бы предпочел вложить все в панд, а затем отфильтровать то, что вам нужно. А в csv-файле от панд проще, и не только в csv можно ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...