Невозможно хранить информацию в CSV (Python Webscraping) - PullRequest
2 голосов
/ 09 июля 2019

Мой код неправильно сохраняет результат в созданный мной CSV-файл.

Мне нужно получить данные о количестве, спонсоре и партии для каждого счета с веб-сайта Конгресса США..

При запуске кода в интерпретаторе он работает правильно и дает мне нужные результаты.Однако в создаваемом мной файле csv есть одна из следующих проблем:

  • одна и та же Спонсор для каждого счета (правильный номер счета, но все они совместно используютсята же Спонсорская партия)
SPONS  PARTY NBILL
Name   D     7402
Name   D     7401
...

Интересно, что найденное мной имя (Грижалва, Рауль) соответствует законопроекту 7302.

  • Правильная Спонсорская партия,но только 100-й счет, а именно каждые 100 спонсоров, у меня есть 7402; 7302 и так далее.

Как и выше, разные Спонсоры и Партия, но количество счетов меняется только каждые 100 пар Спонсор / Партия и увеличивается на 100 на 100 (7402 для первой пары 100, 7302 для второй и т. Д.)

  • Правильный спонсор , но без счетов , что происходит со следующим кодом

РЕДАКТИРОВАТЬ: ЕслиЯ поставил Congress=[-]+[-]+[-] в конце кода, который упал в первом названном случае.

 with open('115congress.csv', 'w') as f:
        fwriter=csv.writer(f, delimiter=';')
        fwriter.writerow(['SPONS', 'PARTY', 'NBILL'])
        BillN=[]
        Spons=[]
        Party=[]
        for j in range(1, 114):
            hrurl='https://www.congress.gov/search?q=%7B%22source%22%3A%22legislation%22%2C%22congress%22%3A%22115%22%2C%22type%22%3A%22bills%22%7D&page='+str(j)
            hrpage=requests.get(hrurl, headers=headers)
            data=hrpage.text
            soup=BeautifulSoup(data, 'lxml')
            for q in soup.findAll('span', {'class':'result-item'}):
                for a in q.findAll('a', href=True, text=True, target='_blank'):
                    secondindex=secondindex+1
                    if (secondindex/2).is_integer():
                        continue
                    Spons=a.text
                    print(Spons)
                    SPONS=Spons
                    if 'R' in Spons:
                        Party='Republican'
                    if 'D' in Spons:
                        Party='Democratic'
                    print(Party)
                    PARTY=Party
                    Congress115=[SPONS]+[PARTY]
                    fwriter.writerow(Congress115)
            for r in soup.findAll('span', {'class':'result-heading'}):
                index=index+1
                if (index/2).is_integer():
                    continue
                Bill=r.findNext('a')
                BillN=Bill.text
                print(BillN)
                NBILL=BillN
                Congress115= [SPONS]+[PARTY]+[NBILL]
                fwriter.writerow(Congress115)

    f.close()

Как я могу исправить свой код, который пишет в CSV, чтобы у меня не было этих проблем?

Ответы [ 2 ]

1 голос
/ 09 июля 2019

Лучшим подходом было бы зациклить другой элемент, например <li>, а затем найти необходимые элементы внутри него.

Чтобы получить коспонсоров, сначала нужно проверить, есть ли они, проверивчисло.Если это не 0, то сначала получите ссылку на подстраницу.Запросите эту подстраницу, используя отдельный объект BeautifulSoup.Затем можно проанализировать таблицу, содержащую коспонсоров, и добавить всех коспонсоров в список.Вы можете добавить дополнительную обработку здесь, если это необходимо.Затем список объединяется в одну строку, чтобы его можно было сохранить в одном столбце в файле CSV.

from bs4 import BeautifulSoup
import csv
import requests
import string

headers = None

with open('115congress.csv', 'w', newline='') as f:
    fwriter = csv.writer(f, delimiter=';')
    fwriter.writerow(['SPONS', 'PARTY', 'NBILL', 'TITLE', 'COSPONSORS'])

    for j in range(1, 3):  #114):
        print(f'Getting page {j}')

        hrurl = 'https://www.congress.gov/search?q=%7B%22source%22%3A%22legislation%22%2C%22congress%22%3A%22115%22%2C%22type%22%3A%22bills%22%7D&page='+str(j)
        hrpage = requests.get(hrurl, headers=headers)
        soup = BeautifulSoup(hrpage.content, 'lxml')

        for li in soup.find_all('li', class_='expanded'):
            bill_or_law = li.span.text
            sponsor = li.find('span', class_='result-item').a.text
            title = li.find('span', class_='result-title').text
            nbill = li.find('a').text.strip(string.ascii_uppercase + ' .')

            if '[R' in sponsor:
                party = 'Republican'
            elif '[D' in sponsor:
                party = 'Democratic'
            else:
                party = 'Unknown'

            # Any cosponsors?
            cosponsor_link = li.find_all('a')[2]

            if cosponsor_link.text == '0':
                cosponsors = "No cosponsors"
            else:
                print(f'Getting cosponsors for {sponsor}')
                # Get the subpage containing the cosponsors
                hr_cosponsors = requests.get(cosponsor_link['href'], headers=headers)
                soup_cosponsors = BeautifulSoup(hr_cosponsors.content, 'lxml')
                table = soup_cosponsors.find('table', class_="item_table")

                # Create a list of the cosponsors
                cosponsor_list = []

                for tr in table.tbody.find_all('tr'):
                    cosponsor_list.append(tr.td.a.text)

                # Join them together into a single string
                cosponsors = ' - '.join(cosponsor_list)

            fwriter.writerow([sponsor, party, nbill, f'{bill_or_law} - {title}', cosponsors])

Предоставление выходного файла CSV, начиная с:

SPONS;PARTY;NBILL;TITLE;COSPONSORS
Rep. Ellison, Keith [D-MN-5];Democratic;7401;BILL - Strengthening Refugee Resettlement Act;No cosponsors
Rep. Wild, Susan [D-PA-15];Democratic;7400;BILL - Making continuing appropriations for the Coast Guard.;No cosponsors
Rep. Scanlon, Mary Gay [D-PA-7];Democratic;7399;BILL - Inaugural Fund Integrity Act;No cosponsors
Rep. Foster, Bill [D-IL-11];Democratic;7398;BILL - SPA Act;No cosponsors
Rep. Hoyer, Steny H. [D-MD-5];Democratic;7397;BILL - To provide further additional continuing appropriations for fiscal year 2019, and for other purposes.;No cosponsors
Rep. Torres, Norma J. [D-CA-35];Democratic;7396;BILL - Border Security and Child Safety Act;Rep. Vargas, Juan [D-CA-51]* - Rep. McGovern, James P. [D-MA-2]*
Rep. Meadows, Mark [R-NC-11];Republican;7395;BILL - To direct the Secretary of Health and Human Services to allow delivery of medical supplies by unmanned aerial systems, and for other purposes.;No cosponsors
Rep. Luetkemeyer, Blaine [R-MO-3];Republican;7394;"BILL - To prohibit the Federal financial regulators from requiring compliance with the accounting standards update of the Financial Accounting Standards Board related to current expected credit loss (""CECL""), to require the Securities and Exchange Commission to take certain impacts of a proposed accounting principle into consideration before accepting the principle, and for other purposes.";Rep. Budd, Ted [R-NC-13]*
Rep. Faso, John J. [R-NY-19];Republican;7393;BILL - Medicaid Quality Care Act;No cosponsors
Rep. Babin, Brian [R-TX-36];Republican;7392;BILL - TRACED Act;No cosponsors
Rep. Arrington, Jodey C. [R-TX-19];Republican;7391;BILL - Rural Hospital Freedom and Flexibility Act of 2018;No cosponsors
Rep. Jackson Lee, Sheila [D-TX-18];Democratic;7390;BILL - Violence Against Women Extension Act of 2018;Rep. Hoyer, Steny H. [D-MD-5] - Rep. Clyburn, James E. [D-SC-6]

При использовании csv.writer() файл всегда должен открываться с параметром newline=''.Это позволяет избежать получения строк с двойным интервалом в CSV-файле.

Я предлагаю поискать [D или [R в тексте, поскольку, вероятно, уже будет D или R в остальной частитекст.

1 голос
/ 09 июля 2019

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

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

Если вы хотите извлечь bill_nr, spons и party из каждой записи, вы можете сделать следующее (см. Комментарии в коде):

import csv
import requests
from bs4 import BeautifulSoup

for j in range(1,114):
  hrurl=f'https://www.congress.gov/search?q=%7B%22source%22%3A%22legislation%22%2C%22congress%22%3A%22115%22%2C%22type%22%3A%22bills%22%7D&page={j}'
  hrpage=requests.get(hrurl)
  data=hrpage.text
  soup=BeautifulSoup(data, 'html5lib')

  # get the main div, that contains all entries on the page
  main_div = soup.find('div', {'id':'main'})
  # every entry is within a <li> element
  all_li = main_div.findAll('li', {'class':'expanded'})

  # iterate over <li>-elements
  for li in all_li:
    # get BILL_NR
    bill_nr_raw = li.find('span', {'class':'result-heading'}).text
    # I assume only the first part is the Nr, so you could extract it with the following
    bill_nr = bill_nr_raw.split()[0]
    # get SPONS
    spons_raw = li.find('span', {'class':'result-item'})
    spons = spons_raw.find('a').text

    # get PARTY
    # check if the string starts with one of the following to ensure you pick the right party
    if spons.startswith('Rep'):
      party = 'Republican'
    elif spons.startswith('Dem'):
      party = 'Democratic'

    # put all the information you extracted from this single entry (=<li>-element) into a list and write that list (=one row) to the csv file
    entry = [bill_nr, spons, party]
    with open('output.csv', 'a') as out_file:
      out = csv.writer(out_file)
      out.writerow(entry)

Обратите внимание, что использование f-строк (в началеосновной цикл) поддерживается только в Python> 3.6.

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