Downloading bill data from LegiScan#

There is a website called LegiScan. From their about page:

LegiScan launched to support the release of the national LegiScan data service, providing the nation's first impartial real-time legislative tracking service designed for both public citizens and government affairs professionals across all sectors in organizations large and small. Utilizing the LegiScan API, having nearly 20 years of development maturity, allows us to provide monitoring of every bill in the 50 states and Congress. Giving our users and clients a central and uniform interface with the ability to easily track a wide array of legislative information. Paired with one of the country's most powerful national full bill text legislative search engines.

We're using to use their API to download data on over a million different pieces of legislation in the US.

Imports#

import zipfile
import base64
import io
import glob
import time
import json
import os
import requests
import mimetypes

pylegiscan#

To talk to LegiScan's API, we're borrowing some code from pylegiscan. Since it isn't a package you can install with pip, it wound up being easier for distribution to just cut and paste it here.

# Taken from https://github.com/poliquin/pylegiscan/blob/master/pylegiscan/legiscan.py

import os
import json
import requests
from urllib.parse import urlencode
from urllib.parse import quote_plus

# current aggregate status of bill
BILL_STATUS = {1: "Introduced",
               2: "Engrossed",
               3: "Enrolled",
               4: "Passed",
               5: "Vetoed",
               6: "Failed/Dead"}

# significant steps in bill progress.
BILL_PROGRESS = {1: "Introduced",
                 2: "Engrossed",
                 3: "Enrolled",
                 4: "Passed",
                 5: "Vetoed",
                 6: "Failed/Dead",
                 7: "Veto Override",
                 8: "Chapter/Act/Statute",
                 9: "Committee Referral",
                10: "Committee Report Pass",
                11: "Committee Report DNP"}


"""
Interact with LegiScan API.

"""

# a helpful list of valid legiscan state abbreviations (no Puerto Rico)
STATES = ['ak', 'al', 'ar', 'az', 'ca', 'co', 'ct', 'dc', 'de', 'fl', 'ga',
          'hi', 'ia', 'id', 'il', 'in', 'ks', 'ky', 'la', 'ma', 'md', 'me',
          'mi', 'mn', 'mo', 'ms', 'mt', 'nc', 'nd', 'ne', 'nh', 'nj', 'nm',
          'nv', 'ny', 'oh', 'ok', 'or', 'pa', 'ri', 'sc', 'sd', 'tn', 'tx',
          'ut', 'va', 'vt', 'wa', 'wi', 'wv', 'wy']

class LegiScanError(Exception):
    pass

class LegiScan(object):
    BASE_URL = 'http://api.legiscan.com/?key={0}&op={1}&{2}'

    def __init__(self, apikey=None):
        """LegiScan API.  State parameters should always be passed as
           USPS abbreviations.  Bill numbers and abbreviations are case
           insensitive.  Register for API at http://legiscan.com/legiscan
        """
        # see if API key available as environment variable
        if apikey is None:
            apikey = os.environ['LEGISCAN_API_KEY']
        self.key = apikey.strip()

    def _url(self, operation, params=None):
        """Build a URL for querying the API."""
        if not isinstance(params, str) and params is not None:
            params = urlencode(params)
        elif params is None:
            params = ''
        return self.BASE_URL.format(self.key, operation, params)

    def _get(self, url):
        """Get and parse JSON from API for a url."""
        req = requests.get(url)
        if not req.ok:
            raise LegiScanError('Request returned {0}: {1}'\
                    .format(req.status_code, url))
        data = json.loads(req.content)
        if data['status'] == "ERROR":
            raise LegiScanError(data['alert']['message'])
        return data

    def get_session_list(self, state):
        """Get list of available sessions for a state."""
        url = self._url('getSessionList', {'state': state})
        data = self._get(url)
        return data['sessions']

    def get_dataset_list(self, state=None, year=None):
        """Get list of available datasets, with optional state and year filtering.
        """
        if state is not None:
            url = self._url('getDatasetList', {'state': state})
        elif year is not None:
            url = self._url('getDatasetList', {'year': year})
        else:
            url = self._url('getDatasetList')
        data = self._get(url)
        # return a list of the bills
        return data['datasetlist']

    def get_dataset(self, id, access_key):
        """Get list of available datasets, with optional state and year filtering.
        """
        url = self._url('getDataset', {'id': id, 'access_key': access_key})
        data = self._get(url)
        # return a list of the bills
        return data['dataset']
      
    def get_master_list(self, state=None, session_id=None):
        """Get list of bills for the current session in a state or for
           a given session identifier.
        """
        if state is not None:
            url = self._url('getMasterList', {'state': state})
        elif session_id is not None:
            url = self._url('getMasterList', {'id': session_id})
        else:
            raise ValueError('Must specify session identifier or state.')
        data = self._get(url)
        # return a list of the bills
        return [data['masterlist'][i] for i in data['masterlist']]

    def get_bill(self, bill_id=None, state=None, bill_number=None):
        """Get primary bill detail information including sponsors, committee
           references, full history, bill text, and roll call information.

           This function expects either a bill identifier or a state and bill
           number combination.  The bill identifier is preferred, and required
           for fetching bills from prior sessions.
        """
        if bill_id is not None:
            url = self._url('getBill', {'id': bill_id})
        elif state is not None and bill_number is not None:
            url = self._url('getBill', {'state': state, 'bill': bill_number})
        else:
            raise ValueError('Must specify bill_id or state and bill_number.')
        return self._get(url)['bill']

    def get_bill_text(self, doc_id):
        """Get bill text, including date, draft revision information, and
           MIME type.  Bill text is base64 encoded to allow for PDF and Word
           data transfers.
        """
        url = self._url('getBillText', {'id': doc_id})
        return self._get(url)['text']

    def get_amendment(self, amendment_id):
        """Get amendment text including date, adoption status, MIME type, and
           title/description information.  The amendment text is base64 encoded
           to allow for PDF and Word data transfer.
        """
        url = self._url('getAmendment', {'id': amendment_id})
        return self._get(url)['amendment']

    def get_supplement(self, supplement_id):
        """Get supplement text including type of supplement, date, MIME type
           and text/description information.  Supplement text is base64 encoded
           to allow for PDF and Word data transfer.
        """
        url = self._url('getSupplement', {'id': supplement_id})
        return self._get(url)['supplement']

    def get_roll_call(self, roll_call_id):
        """Roll call detail for individual votes and summary information."""
        data = self._get(self._url('getRollcall', {'id': roll_call_id}))
        return data['roll_call']

    def get_sponsor(self, people_id):
        """Sponsor information including name, role, and a followthemoney.org
           person identifier.
        """
        url = self._url('getSponsor', {'id': people_id})
        return self._get(url)['person']

    def search(self, state, bill_number=None, query=None, year=2, page=1):
        """Get a page of results for a search against the LegiScan full text
           engine; returns a paginated result set.

           Specify a bill number or a query string.  Year can be an exact year
           or a number between 1 and 4, inclusive.  These integers have the
           following meanings:
               1 = all years
               2 = current year, the default
               3 = recent years
               4 = prior years
           Page is the result set page number to return.
        """
        if bill_number is not None:
            params = {'state': state, 'bill': bill_number}
        elif query is not None:
            params = {'state': state, 'query': query,
                      'year': year, 'page': page}
        else:
            raise ValueError('Must specify bill_number or query')
        data = self._get(self._url('search', params))['searchresult']
        # return a summary of the search and the results as a dictionary
        summary = data.pop('summary')
        results = {'summary': summary, 'results': [data[i] for i in data]}
        return results

    def __str__(self):
        return '<LegiScan API {0}>'.format(self.key)

    def __repr__(self):
        return str(self)

Connect to LegiScan#

Using pylegiscan, you just pass your API key to LegiScan and you're good to go. I set up an environment variable for mine, but you can also just paste yours at OR_PUT_YOUR_API_KEY_HERE.

api_key = os.environ.get('LEGISCAN_API_KEY', 'OR_PUT_YOUR_API_KEY_HERE')
legis = LegiScan(api_key)

If you wanted to search for bills based on state or text, that's easy to do.

bills = legis.search(state='tx', query='abortion')
bills['summary'] # how many results did we get?
{'page': '1 of 2',
 'range': '1 - 50',
 'relevancy': '100% - 87%',
 'count': 59,
 'page_current': '1',
 'page_total': 2,
 'query': '(Zabort:(pos=1))'}

You can also get single bills, one at a time, as long as you know their ID in the LegiScan database.

legis.get_bill('1256258')
{'bill_id': 1256258,
 'change_hash': 'c5fc7aa0673f84a38a93d77abf9a29d8',
 'session_id': 1650,
 'session': {'session_id': 1650,
  'session_name': '123rd General Assembly',
  'session_title': '123rd General Assembly',
  'year_start': 2019,
  'year_end': 2020,
  'special': 0},
 'url': 'https://legiscan.com/SC/bill/H4523/2019',
 'state_link': 'https://www.scstatehouse.gov/billsearch.php?billnumbers=4523&session=123&summary=B',
 'completed': 1,
 'status': 4,
 'status_date': '2019-05-02',
 'progress': [{'date': '2019-05-02', 'event': 1},
  {'date': '2019-05-02', 'event': 4}],
 'state': 'SC',
 'state_id': 40,
 'bill_number': 'H4523',
 'bill_type': 'R',
 'bill_type_id': '2',
 'body': 'H',
 'body_id': 85,
 'current_body': 'H',
 'current_body_id': 85,
 'title': 'Debi Chard',
 'description': 'Honor Debi Chard On The Occasion Of Her Retirement From Wcsc Live 5 News In Charleston, South Carolina, After Forty-three Years Of Dedicated Service And To Wish Her Many Happy Years In A Well-deserved Retirement.',
 'committee': [],
 'pending_committee_id': 0,
 'history': [{'date': '2019-05-02',
   'action': 'Introduced and adopted',
   'chamber': 'H',
   'chamber_id': 85,
   'importance': 1}],
 'sponsors': [{'people_id': 2240,
   'person_hash': 'oif0llyl',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Wendell Gilliard',
   'first_name': 'Wendell',
   'middle_name': 'G.',
   'last_name': 'Gilliard',
   'suffix': '',
   'nickname': '',
   'district': 'HD-111',
   'ftm_eid': 13006541,
   'votesmart_id': 78936,
   'opensecrets_id': '',
   'ballotpedia': 'Wendell_Gilliard',
   'sponsor_type_id': 1,
   'sponsor_order': 1,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2202,
   'person_hash': '3dpclq1a',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Terry Alexander',
   'first_name': 'Terry',
   'middle_name': '',
   'last_name': 'Alexander',
   'suffix': '',
   'nickname': '',
   'district': 'HD-059',
   'ftm_eid': 13006428,
   'votesmart_id': 56704,
   'opensecrets_id': '',
   'ballotpedia': 'Terry_Alexander',
   'sponsor_type_id': 2,
   'sponsor_order': 2,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2204,
   'person_hash': 'ggo9ab00',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Merita Allison',
   'first_name': 'Merita',
   'middle_name': 'A.',
   'last_name': 'Allison',
   'suffix': '',
   'nickname': 'Rita',
   'district': 'HD-036',
   'ftm_eid': 8212214,
   'votesmart_id': 3956,
   'opensecrets_id': '',
   'ballotpedia': 'Merita_Ann_Allison',
   'sponsor_type_id': 2,
   'sponsor_order': 3,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2205,
   'person_hash': 'yl3d3hav',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Carl Anderson',
   'first_name': 'Carl',
   'middle_name': 'L.',
   'last_name': 'Anderson',
   'suffix': '',
   'nickname': '',
   'district': 'HD-103',
   'ftm_eid': 13006528,
   'votesmart_id': 48270,
   'opensecrets_id': '',
   'ballotpedia': 'Carl_Anderson_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 4,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18085,
   'person_hash': 'h4rcyzkb',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Frank Atkinson',
   'first_name': 'Frank',
   'middle_name': 'Lucas',
   'last_name': 'Atkinson',
   'suffix': '',
   'nickname': 'Lucas',
   'district': 'HD-057',
   'ftm_eid': 36099207,
   'votesmart_id': 168971,
   'opensecrets_id': '',
   'ballotpedia': 'Lucas_Atkinson',
   'sponsor_type_id': 2,
   'sponsor_order': 5,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 20147,
   'person_hash': 'ctszemla',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Bailey',
   'first_name': 'William',
   'middle_name': 'H.',
   'last_name': 'Bailey',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-104',
   'ftm_eid': 44932254,
   'votesmart_id': 181058,
   'opensecrets_id': '',
   'ballotpedia': 'William_Bailey',
   'sponsor_type_id': 2,
   'sponsor_order': 6,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2207,
   'person_hash': '6by3rgal',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Jimmy Bales',
   'first_name': 'Jimmy',
   'middle_name': 'C.',
   'last_name': 'Bales',
   'suffix': '',
   'nickname': '',
   'district': 'HD-080',
   'ftm_eid': 6377633,
   'votesmart_id': 25059,
   'opensecrets_id': '',
   'ballotpedia': 'Jimmy_Bales',
   'sponsor_type_id': 2,
   'sponsor_order': 7,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2208,
   'person_hash': '6weacsjc',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Nathan Ballentine',
   'first_name': 'Nathan',
   'middle_name': '',
   'last_name': 'Ballentine',
   'suffix': '',
   'nickname': '',
   'district': 'HD-071',
   'ftm_eid': 6660566,
   'votesmart_id': 47966,
   'opensecrets_id': '',
   'ballotpedia': 'Nathan_Ballentine',
   'sponsor_type_id': 2,
   'sponsor_order': 8,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16320,
   'person_hash': 'j0x8wxt3',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Justin Bamberg',
   'first_name': 'Justin',
   'middle_name': 'T.',
   'last_name': 'Bamberg',
   'suffix': '',
   'nickname': '',
   'district': 'HD-090',
   'ftm_eid': 23424525,
   'votesmart_id': 152607,
   'opensecrets_id': '',
   'ballotpedia': 'Justin_Bamberg',
   'sponsor_type_id': 2,
   'sponsor_order': 9,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2209,
   'person_hash': 'dqwjrax3',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Bruce Bannister',
   'first_name': 'Bruce',
   'middle_name': 'W.',
   'last_name': 'Bannister',
   'suffix': '',
   'nickname': '',
   'district': 'HD-024',
   'ftm_eid': 6669937,
   'votesmart_id': 59275,
   'opensecrets_id': '',
   'ballotpedia': 'Bruce_Bannister',
   'sponsor_type_id': 2,
   'sponsor_order': 10,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18086,
   'person_hash': 'wuj8tleq',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Linda Bennett',
   'first_name': 'Linda',
   'middle_name': 'C.',
   'last_name': 'Bennett',
   'suffix': '',
   'nickname': 'Lin',
   'district': 'HD-114',
   'ftm_eid': 6675997,
   'votesmart_id': 105053,
   'opensecrets_id': '',
   'ballotpedia': 'Linda_Angona',
   'sponsor_type_id': 2,
   'sponsor_order': 11,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14187,
   'person_hash': 'yo8mlxv6',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Beth Bernstein',
   'first_name': 'Beth',
   'middle_name': 'E.',
   'last_name': 'Bernstein',
   'suffix': '',
   'nickname': '',
   'district': 'HD-078',
   'ftm_eid': 13006475,
   'votesmart_id': 139541,
   'opensecrets_id': '',
   'ballotpedia': 'Beth_Bernstein',
   'sponsor_type_id': 2,
   'sponsor_order': 12,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18087,
   'person_hash': 'fwkxlb8d',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Bart Blackwell',
   'first_name': 'Bart',
   'middle_name': 'T.',
   'last_name': 'Blackwell',
   'suffix': '',
   'nickname': '',
   'district': 'HD-081',
   'ftm_eid': 7963701,
   'votesmart_id': 168988,
   'opensecrets_id': '',
   'ballotpedia': 'Bart_Blackwell',
   'sponsor_type_id': 2,
   'sponsor_order': 13,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16321,
   'person_hash': '2svzk8cx',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Jeffrey Bradley',
   'first_name': 'Jeffrey',
   'middle_name': 'A.',
   'last_name': 'Bradley',
   'suffix': '',
   'nickname': 'Jeff',
   'district': 'HD-123',
   'ftm_eid': 25760836,
   'votesmart_id': 152611,
   'opensecrets_id': '',
   'ballotpedia': 'Jeff_Bradley',
   'sponsor_type_id': 2,
   'sponsor_order': 14,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19464,
   'person_hash': '0gg4lr9j',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Wendy Brawley',
   'first_name': 'Wendy',
   'middle_name': 'C.',
   'last_name': 'Brawley',
   'suffix': '',
   'nickname': '',
   'district': 'HD-070',
   'ftm_eid': 8117558,
   'votesmart_id': 105063,
   'opensecrets_id': '',
   'ballotpedia': 'Wendy_Brawley',
   'sponsor_type_id': 2,
   'sponsor_order': 15,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2221,
   'person_hash': 'ifssib9s',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Robert Brown',
   'first_name': 'Robert',
   'middle_name': 'L.',
   'last_name': 'Brown',
   'suffix': '',
   'nickname': '',
   'district': 'HD-116',
   'ftm_eid': 6377680,
   'votesmart_id': 48137,
   'opensecrets_id': '',
   'ballotpedia': 'Robert_Brown,_South_Carolina_Representative',
   'sponsor_type_id': 2,
   'sponsor_order': 16,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19434,
   'person_hash': 'xho5gloz',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Bruce Bryant',
   'first_name': 'Bruce',
   'middle_name': 'M.',
   'last_name': 'Bryant',
   'suffix': '',
   'nickname': '',
   'district': 'HD-048',
   'ftm_eid': 43550162,
   'votesmart_id': 176195,
   'opensecrets_id': '',
   'ballotpedia': 'Bruce_Bryant_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 17,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 15975,
   'person_hash': 'xaevg7ex',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'James Burns',
   'first_name': 'James',
   'middle_name': 'Mikell',
   'last_name': 'Burns',
   'suffix': '',
   'nickname': 'Mike',
   'district': 'HD-017',
   'ftm_eid': 15393737,
   'votesmart_id': 144188,
   'opensecrets_id': '',
   'ballotpedia': 'Mike_Burns',
   'sponsor_type_id': 2,
   'sponsor_order': 18,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 20399,
   'person_hash': 'lcqpphru',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Paula Rawl Calhoon',
   'first_name': 'Paula',
   'middle_name': 'Rawl',
   'last_name': 'Calhoon',
   'suffix': '',
   'nickname': '',
   'district': 'HD-087',
   'ftm_eid': 44932265,
   'votesmart_id': 181047,
   'opensecrets_id': '',
   'ballotpedia': 'Paula_Rawl_Calhoon',
   'sponsor_type_id': 2,
   'sponsor_order': 19,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18654,
   'person_hash': 'vh80p1ub',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Micajah Caskey',
   'first_name': 'Micajah',
   'middle_name': 'P.',
   'last_name': 'Caskey',
   'suffix': 'IV',
   'nickname': '',
   'district': 'HD-089',
   'ftm_eid': 39714660,
   'votesmart_id': 168999,
   'opensecrets_id': '',
   'ballotpedia': 'Micah_Caskey',
   'sponsor_type_id': 2,
   'sponsor_order': 20,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 20400,
   'person_hash': '0yycqi8n',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Con Chellis',
   'first_name': 'Converse',
   'middle_name': 'A.',
   'last_name': 'Chellis',
   'suffix': 'IV',
   'nickname': 'Con',
   'district': 'HD-094',
   'ftm_eid': 38255175,
   'votesmart_id': 181051,
   'opensecrets_id': '',
   'ballotpedia': 'Con_Chellis',
   'sponsor_type_id': 2,
   'sponsor_order': 21,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 11216,
   'person_hash': 'roidxyv0',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Chumley',
   'first_name': 'William',
   'middle_name': 'M.',
   'last_name': 'Chumley',
   'suffix': '',
   'nickname': 'Bill',
   'district': 'HD-035',
   'ftm_eid': 8353531,
   'votesmart_id': 150169,
   'opensecrets_id': '',
   'ballotpedia': 'Bill_Chumley',
   'sponsor_type_id': 2,
   'sponsor_order': 22,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16322,
   'person_hash': 'we2jonod',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Gary Clary',
   'first_name': 'Gary',
   'middle_name': 'E.',
   'last_name': 'Clary',
   'suffix': '',
   'nickname': '',
   'district': 'HD-003',
   'ftm_eid': 23424534,
   'votesmart_id': 152448,
   'opensecrets_id': '',
   'ballotpedia': 'Gary_Clary',
   'sponsor_type_id': 2,
   'sponsor_order': 23,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2224,
   'person_hash': '6u8ngkw9',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Alan Clemmons',
   'first_name': 'Alan',
   'middle_name': 'D.',
   'last_name': 'Clemmons',
   'suffix': '',
   'nickname': '',
   'district': 'HD-107',
   'ftm_eid': 6602594,
   'votesmart_id': 48166,
   'opensecrets_id': '',
   'ballotpedia': 'Alan_Clemmons',
   'sponsor_type_id': 2,
   'sponsor_order': 24,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2225,
   'person_hash': 'k4wbt6kv',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Clyburn',
   'first_name': 'William',
   'middle_name': '',
   'last_name': 'Clyburn',
   'suffix': '',
   'nickname': 'Bill',
   'district': 'HD-082',
   'ftm_eid': 756743,
   'votesmart_id': 4006,
   'opensecrets_id': '',
   'ballotpedia': 'William_Clyburn,_Sr.',
   'sponsor_type_id': 2,
   'sponsor_order': 25,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2226,
   'person_hash': 'z90ut39b',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Gilda Cobb-Hunter',
   'first_name': 'Gilda',
   'middle_name': '',
   'last_name': 'Cobb-Hunter',
   'suffix': '',
   'nickname': '',
   'district': 'HD-066',
   'ftm_eid': 6377713,
   'votesmart_id': 4005,
   'opensecrets_id': '',
   'ballotpedia': 'Gilda_Cobb-Hunter',
   'sponsor_type_id': 2,
   'sponsor_order': 26,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18655,
   'person_hash': 'azqh75h0',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Cogswell',
   'first_name': 'William',
   'middle_name': 'Scott',
   'last_name': 'Cogswell',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-110',
   'ftm_eid': 39714673,
   'votesmart_id': 169004,
   'opensecrets_id': '',
   'ballotpedia': 'William_S._Cogswell_Jr.',
   'sponsor_type_id': 2,
   'sponsor_order': 27,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16323,
   'person_hash': 'jb89r2zp',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Neal Collins',
   'first_name': 'Neal',
   'middle_name': 'A.',
   'last_name': 'Collins',
   'suffix': '',
   'nickname': '',
   'district': 'HD-005',
   'ftm_eid': 17766551,
   'votesmart_id': 121780,
   'opensecrets_id': '',
   'ballotpedia': 'Neal_Collins',
   'sponsor_type_id': 2,
   'sponsor_order': 28,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19927,
   'person_hash': '5qpbm0ov',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Bobby Cox',
   'first_name': 'Bobby',
   'middle_name': 'J.',
   'last_name': 'Cox',
   'suffix': '',
   'nickname': '',
   'district': 'HD-021',
   'ftm_eid': 43101592,
   'votesmart_id': 181020,
   'opensecrets_id': '',
   'ballotpedia': 'Bobby_Cox_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 29,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19928,
   'person_hash': 'x18ivysv',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'West Cox',
   'first_name': 'Westley',
   'middle_name': 'P',
   'last_name': 'Cox',
   'suffix': '',
   'nickname': 'West',
   'district': 'HD-010',
   'ftm_eid': 45316148,
   'votesmart_id': 184234,
   'opensecrets_id': '',
   'ballotpedia': 'West_Cox',
   'sponsor_type_id': 2,
   'sponsor_order': 30,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14300,
   'person_hash': '2elcjfwy',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Heather Crawford',
   'first_name': 'Heather',
   'middle_name': 'Ammons',
   'last_name': 'Crawford',
   'suffix': '',
   'nickname': '',
   'district': 'HD-068',
   'ftm_eid': 11023570,
   'votesmart_id': 140708,
   'opensecrets_id': '',
   'ballotpedia': 'Heather_Ammons_Crawford',
   'sponsor_type_id': 2,
   'sponsor_order': 31,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2230,
   'person_hash': 'nbuonqge',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Joseph Daning',
   'first_name': 'Joseph',
   'middle_name': 'S.',
   'last_name': 'Daning',
   'suffix': '',
   'nickname': 'Joe',
   'district': 'HD-092',
   'ftm_eid': 13006504,
   'votesmart_id': 104750,
   'opensecrets_id': '',
   'ballotpedia': 'Joseph_Daning',
   'sponsor_type_id': 2,
   'sponsor_order': 32,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 17959,
   'person_hash': 'ower915x',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Sylleste Davis',
   'first_name': 'Sylleste',
   'middle_name': 'H.',
   'last_name': 'Davis',
   'suffix': '',
   'nickname': '',
   'district': 'HD-100',
   'ftm_eid': 40585456,
   'votesmart_id': 172947,
   'opensecrets_id': '',
   'ballotpedia': 'Sylleste_Davis',
   'sponsor_type_id': 2,
   'sponsor_order': 33,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2232,
   'person_hash': 'p2db1jbs',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Chandra Dillard',
   'first_name': 'Chandra',
   'middle_name': 'E.',
   'last_name': 'Dillard',
   'suffix': '',
   'nickname': '',
   'district': 'HD-023',
   'ftm_eid': 13006348,
   'votesmart_id': 77602,
   'opensecrets_id': '',
   'ballotpedia': 'Chandra_Dillard',
   'sponsor_type_id': 2,
   'sponsor_order': 34,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18088,
   'person_hash': '5lfuel77',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Jason Elliott',
   'first_name': 'Jason',
   'middle_name': 'T.',
   'last_name': 'Elliott',
   'suffix': '',
   'nickname': '',
   'district': 'HD-022',
   'ftm_eid': 39714580,
   'votesmart_id': 168956,
   'opensecrets_id': '',
   'ballotpedia': 'Jason_Elliott',
   'sponsor_type_id': 2,
   'sponsor_order': 35,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2235,
   'person_hash': '2c5ihx5y',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Shannon Erickson',
   'first_name': 'Shannon',
   'middle_name': 'S.',
   'last_name': 'Erickson',
   'suffix': '',
   'nickname': '',
   'district': 'HD-124',
   'ftm_eid': 13006579,
   'votesmart_id': 101096,
   'opensecrets_id': '',
   'ballotpedia': 'Shannon_Erickson',
   'sponsor_type_id': 2,
   'sponsor_order': 36,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14297,
   'person_hash': '9swdhog7',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Raye Felder',
   'first_name': 'Raye',
   'middle_name': '',
   'last_name': 'Felder',
   'suffix': '',
   'nickname': '',
   'district': 'HD-026',
   'ftm_eid': 16540144,
   'votesmart_id': 139456,
   'opensecrets_id': '',
   'ballotpedia': 'R._Raye_Felder',
   'sponsor_type_id': 2,
   'sponsor_order': 37,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14067,
   'person_hash': 'lb9u3n72',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Kirkman Finlay',
   'first_name': 'Kirkman',
   'middle_name': '',
   'last_name': 'Finlay',
   'suffix': 'III',
   'nickname': '',
   'district': 'HD-075',
   'ftm_eid': 7953192,
   'votesmart_id': 78982,
   'opensecrets_id': '',
   'ballotpedia': 'Kirkman_Finlay,_III',
   'sponsor_type_id': 2,
   'sponsor_order': 38,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18089,
   'person_hash': '2h2oibfq',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Cally Forrest',
   'first_name': 'Cally',
   'middle_name': 'R.',
   'last_name': 'Forrest',
   'suffix': 'Jr.',
   'nickname': 'Cal',
   'district': 'HD-039',
   'ftm_eid': 7956897,
   'votesmart_id': 168962,
   'opensecrets_id': '',
   'ballotpedia': 'Cal_Forrest',
   'sponsor_type_id': 2,
   'sponsor_order': 39,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2236,
   'person_hash': 'imetg4tg',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Michael Forrester',
   'first_name': 'P. Michael',
   'middle_name': '',
   'last_name': 'Forrester',
   'suffix': '',
   'nickname': 'Mike',
   'district': 'HD-034',
   'ftm_eid': 6676025,
   'votesmart_id': 105014,
   'opensecrets_id': '',
   'ballotpedia': 'Mike_Forrester',
   'sponsor_type_id': 2,
   'sponsor_order': 40,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 17737,
   'person_hash': '17ajxw8h',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Russell Fry',
   'first_name': 'Russell',
   'middle_name': 'W.',
   'last_name': 'Fry',
   'suffix': '',
   'nickname': '',
   'district': 'HD-106',
   'ftm_eid': 31649738,
   'votesmart_id': 157265,
   'opensecrets_id': '',
   'ballotpedia': 'Russell_Fry',
   'sponsor_type_id': 2,
   'sponsor_order': 41,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2238,
   'person_hash': 'pnv0a0n4',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Laurie Funderburk',
   'first_name': 'Laurie',
   'middle_name': 'Slade',
   'last_name': 'Funderburk',
   'suffix': '',
   'nickname': '',
   'district': 'HD-052',
   'ftm_eid': 6457028,
   'votesmart_id': 47875,
   'opensecrets_id': '',
   'ballotpedia': 'Laurie_Funderburk',
   'sponsor_type_id': 2,
   'sponsor_order': 42,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14298,
   'person_hash': '1hi5i27n',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Craig Gagnon',
   'first_name': 'Craig',
   'middle_name': 'A.',
   'last_name': 'Gagnon',
   'suffix': '',
   'nickname': '',
   'district': 'HD-011',
   'ftm_eid': 11023547,
   'votesmart_id': 139451,
   'opensecrets_id': '',
   'ballotpedia': 'Craig_Gagnon',
   'sponsor_type_id': 2,
   'sponsor_order': 43,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19929,
   'person_hash': '915cbhqo',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Kambrell Garvin',
   'first_name': 'Kambrell',
   'middle_name': 'Houston',
   'last_name': 'Garvin',
   'suffix': '',
   'nickname': '',
   'district': 'HD-077',
   'ftm_eid': 44932292,
   'votesmart_id': 181046,
   'opensecrets_id': '',
   'ballotpedia': 'Kambrell_Garvin',
   'sponsor_type_id': 2,
   'sponsor_order': 44,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19930,
   'person_hash': '0iibkq9m',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Doug Gilliam',
   'first_name': 'Leon',
   'middle_name': 'D.',
   'last_name': 'Gilliam',
   'suffix': '',
   'nickname': 'Doug',
   'district': 'HD-042',
   'ftm_eid': 44423475,
   'votesmart_id': 181033,
   'opensecrets_id': '',
   'ballotpedia': 'Doug_Gilliam',
   'sponsor_type_id': 2,
   'sponsor_order': 45,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2241,
   'person_hash': 'ix62i9mb',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Jerry Govan',
   'first_name': 'Jerry',
   'middle_name': 'N.',
   'last_name': 'Govan',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-095',
   'ftm_eid': 12403301,
   'votesmart_id': 8501,
   'opensecrets_id': '',
   'ballotpedia': 'Jerry_Govan,_Jr.',
   'sponsor_type_id': 2,
   'sponsor_order': 46,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14033,
   'person_hash': 'fetxpbfx',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Kevin Hardee',
   'first_name': 'Kevin',
   'middle_name': '',
   'last_name': 'Hardee',
   'suffix': '',
   'nickname': '',
   'district': 'HD-105',
   'ftm_eid': 13006530,
   'votesmart_id': 94982,
   'opensecrets_id': '',
   'ballotpedia': 'Kevin_J._Hardee',
   'sponsor_type_id': 2,
   'sponsor_order': 47,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2248,
   'person_hash': 'mqrdh141',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Christopher Hart',
   'first_name': 'Christopher',
   'middle_name': 'R.',
   'last_name': 'Hart',
   'suffix': '',
   'nickname': 'Chris',
   'district': 'HD-073',
   'ftm_eid': 13006465,
   'votesmart_id': 56705,
   'opensecrets_id': '',
   'ballotpedia': 'Christopher_Hart',
   'sponsor_type_id': 2,
   'sponsor_order': 48,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2250,
   'person_hash': '184i27zr',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Jackie Hayes',
   'first_name': 'Jackie',
   'middle_name': 'E.',
   'last_name': 'Hayes',
   'suffix': '',
   'nickname': 'Coach',
   'district': 'HD-055',
   'ftm_eid': 6377783,
   'votesmart_id': 24996,
   'opensecrets_id': '',
   'ballotpedia': 'Jackie_Hayes',
   'sponsor_type_id': 2,
   'sponsor_order': 49,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19496,
   'person_hash': '9q87vybb',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Rosalyn Henderson-Myers',
   'first_name': 'Rosalyn',
   'middle_name': 'D.',
   'last_name': 'Henderson-Myers',
   'suffix': '',
   'nickname': '',
   'district': 'HD-031',
   'ftm_eid': 43855056,
   'votesmart_id': 174445,
   'opensecrets_id': '',
   'ballotpedia': 'Rosalyn_Henderson_Myers',
   'sponsor_type_id': 2,
   'sponsor_order': 50,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16326,
   'person_hash': 'cb41qaqc',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Patricia Henegan',
   'first_name': 'Patricia',
   'middle_name': 'Moore',
   'last_name': 'Henegan',
   'suffix': '',
   'nickname': 'Pat',
   'district': 'HD-054',
   'ftm_eid': 23424521,
   'votesmart_id': 152553,
   'opensecrets_id': '',
   'ballotpedia': 'Patricia_Henegan',
   'sponsor_type_id': 2,
   'sponsor_order': 51,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2252,
   'person_hash': 'x6e7fof2',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Herbkersman',
   'first_name': 'William',
   'middle_name': 'G.',
   'last_name': 'Herbkersman',
   'suffix': '',
   'nickname': 'Bill',
   'district': 'HD-118',
   'ftm_eid': 6602517,
   'votesmart_id': 47897,
   'opensecrets_id': '',
   'ballotpedia': 'Bill_Herbkersman',
   'sponsor_type_id': 2,
   'sponsor_order': 52,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18090,
   'person_hash': 'ctf0n8id',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Hewitt',
   'first_name': 'William',
   'middle_name': 'Lee',
   'last_name': 'Hewitt',
   'suffix': '',
   'nickname': '',
   'district': 'HD-108',
   'ftm_eid': 16072515,
   'votesmart_id': 139488,
   'opensecrets_id': '',
   'ballotpedia': 'Lee_Hewitt',
   'sponsor_type_id': 2,
   'sponsor_order': 53,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16327,
   'person_hash': 'i7knwix7',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Jonathon Hill',
   'first_name': 'Jonathon',
   'middle_name': 'D.',
   'last_name': 'Hill',
   'suffix': '',
   'nickname': '',
   'district': 'HD-008',
   'ftm_eid': 23424541,
   'votesmart_id': 139553,
   'opensecrets_id': '',
   'ballotpedia': 'Jonathon_Hill',
   'sponsor_type_id': 2,
   'sponsor_order': 54,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2253,
   'person_hash': '1b5psxmk',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Davey Hiott',
   'first_name': 'Davey',
   'middle_name': 'R.',
   'last_name': 'Hiott',
   'suffix': '',
   'nickname': 'David',
   'district': 'HD-004',
   'ftm_eid': 6660621,
   'votesmart_id': 47851,
   'opensecrets_id': '',
   'ballotpedia': 'Davey_Hiott',
   'sponsor_type_id': 2,
   'sponsor_order': 55,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 10949,
   'person_hash': 'x2enfgv7',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Hixon',
   'first_name': 'William',
   'middle_name': 'M.',
   'last_name': 'Hixon',
   'suffix': '',
   'nickname': 'Bill',
   'district': 'HD-083',
   'ftm_eid': 6687268,
   'votesmart_id': 121738,
   'opensecrets_id': '',
   'ballotpedia': 'Bill_Hixon',
   'sponsor_type_id': 2,
   'sponsor_order': 56,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2256,
   'person_hash': 'ilfe41ba',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Lonnie Hosey',
   'first_name': 'Lonnie',
   'middle_name': '',
   'last_name': 'Hosey',
   'suffix': '',
   'nickname': '',
   'district': 'HD-091',
   'ftm_eid': 6377816,
   'votesmart_id': 15258,
   'opensecrets_id': '',
   'ballotpedia': 'Lonnie_Hosey',
   'sponsor_type_id': 2,
   'sponsor_order': 57,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2257,
   'person_hash': '2awdo7wt',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Leon Howard',
   'first_name': 'Leon',
   'middle_name': '',
   'last_name': 'Howard',
   'suffix': '',
   'nickname': '',
   'district': 'HD-076',
   'ftm_eid': 6377824,
   'votesmart_id': 8610,
   'opensecrets_id': '',
   'ballotpedia': 'Leon_Howard',
   'sponsor_type_id': 2,
   'sponsor_order': 58,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2258,
   'person_hash': 'a5dnhptl',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Chip Huggins',
   'first_name': 'Chip',
   'middle_name': '',
   'last_name': 'Huggins',
   'suffix': '',
   'nickname': '',
   'district': 'HD-085',
   'ftm_eid': 6573884,
   'votesmart_id': 15249,
   'opensecrets_id': '',
   'ballotpedia': 'Chip_Huggins',
   'sponsor_type_id': 2,
   'sponsor_order': 59,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19931,
   'person_hash': 'f799gfu6',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Max Hyde',
   'first_name': 'Max',
   'middle_name': 'T.',
   'last_name': 'Hyde',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-032',
   'ftm_eid': 44932312,
   'votesmart_id': 104963,
   'opensecrets_id': '',
   'ballotpedia': 'Max_Hyde',
   'sponsor_type_id': 2,
   'sponsor_order': 60,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2260,
   'person_hash': '2oqjjwaq',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Joseph Jefferson',
   'first_name': 'Joseph',
   'middle_name': 'H.',
   'last_name': 'Jefferson',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-102',
   'ftm_eid': 6457062,
   'votesmart_id': 48122,
   'opensecrets_id': '',
   'ballotpedia': 'Joseph_Jefferson,_Jr.',
   'sponsor_type_id': 2,
   'sponsor_order': 61,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16328,
   'person_hash': '90mwv01a',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Jeffrey Johnson',
   'first_name': 'Jeffrey',
   'middle_name': 'E.',
   'last_name': 'Johnson',
   'suffix': '',
   'nickname': 'Jeff',
   'district': 'HD-058',
   'ftm_eid': 23424555,
   'votesmart_id': 152557,
   'opensecrets_id': '',
   'ballotpedia': 'Jeff_Johnson_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 62,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 21358,
   'person_hash': 'lqh7eii7',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Stewart Jones',
   'first_name': 'Stewart',
   'middle_name': 'O.',
   'last_name': 'Jones',
   'suffix': '',
   'nickname': '',
   'district': 'HD-014',
   'ftm_eid': 28144426,
   'votesmart_id': 164595,
   'opensecrets_id': '',
   'ballotpedia': 'Stewart_Jones',
   'sponsor_type_id': 2,
   'sponsor_order': 63,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 17693,
   'person_hash': 'f8x06gu0',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Wallace Jordan',
   'first_name': 'Wallace',
   'middle_name': 'H.',
   'last_name': 'Jordan',
   'suffix': 'Jr.',
   'nickname': 'Jay',
   'district': 'HD-063',
   'ftm_eid': 17658352,
   'votesmart_id': 173023,
   'opensecrets_id': '',
   'ballotpedia': 'Jay_Jordan',
   'sponsor_type_id': 2,
   'sponsor_order': 64,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 20401,
   'person_hash': 'zjxbhwet',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Mandy Kimmons',
   'first_name': 'Mandy',
   'middle_name': 'W.',
   'last_name': 'Kimmons',
   'suffix': '',
   'nickname': '',
   'district': 'HD-097',
   'ftm_eid': 44932314,
   'votesmart_id': 181054,
   'opensecrets_id': '',
   'ballotpedia': 'Mandy_Kimmons',
   'sponsor_type_id': 2,
   'sponsor_order': 65,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2264,
   'person_hash': '5ip6zguw',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'John King',
   'first_name': 'John',
   'middle_name': 'R.',
   'last_name': 'King',
   'suffix': '',
   'nickname': '',
   'district': 'HD-049',
   'ftm_eid': 6399425,
   'votesmart_id': 57918,
   'opensecrets_id': '',
   'ballotpedia': 'John_King_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 66,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16329,
   'person_hash': 'x92ixhfi',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Roger Kirby',
   'first_name': 'Roger',
   'middle_name': 'K.',
   'last_name': 'Kirby',
   'suffix': '',
   'nickname': '',
   'district': 'HD-061',
   'ftm_eid': 24867934,
   'votesmart_id': 139590,
   'opensecrets_id': '',
   'ballotpedia': 'Roger_Kirby',
   'sponsor_type_id': 2,
   'sponsor_order': 67,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19932,
   'person_hash': 'yulzsqc0',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Randy Ligon',
   'first_name': 'Thomas',
   'middle_name': 'R.',
   'last_name': 'Ligon',
   'suffix': '',
   'nickname': 'Randy',
   'district': 'HD-043',
   'ftm_eid': 44932315,
   'votesmart_id': 181034,
   'opensecrets_id': '',
   'ballotpedia': 'Randy_Ligon',
   'sponsor_type_id': 2,
   'sponsor_order': 68,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18214,
   'person_hash': '2uaqw0kc',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Steven Long',
   'first_name': 'Steven',
   'middle_name': 'Wayne',
   'last_name': 'Long',
   'suffix': '',
   'nickname': '',
   'district': 'HD-037',
   'ftm_eid': 39714601,
   'votesmart_id': 168960,
   'opensecrets_id': '',
   'ballotpedia': 'Steven_Long',
   'sponsor_type_id': 2,
   'sponsor_order': 69,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2271,
   'person_hash': 'k5aiv4wr',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Phillip Lowe',
   'first_name': 'Phillip',
   'middle_name': 'D.',
   'last_name': 'Lowe',
   'suffix': '',
   'nickname': '',
   'district': 'HD-060',
   'ftm_eid': 13006429,
   'votesmart_id': 60353,
   'opensecrets_id': '',
   'ballotpedia': 'Phillip_Lowe',
   'sponsor_type_id': 2,
   'sponsor_order': 70,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2272,
   'person_hash': 'prl02q21',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'James Lucas',
   'first_name': 'James',
   'middle_name': 'H.',
   'last_name': 'Lucas',
   'suffix': '',
   'nickname': 'Jay',
   'district': 'HD-065',
   'ftm_eid': 6573936,
   'votesmart_id': 24993,
   'opensecrets_id': '',
   'ballotpedia': 'James_Lucas',
   'sponsor_type_id': 2,
   'sponsor_order': 71,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19545,
   'person_hash': '2el8ocat',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Nancy Mace',
   'first_name': 'Nancy',
   'middle_name': '',
   'last_name': 'Mace',
   'suffix': '',
   'nickname': '',
   'district': 'HD-099',
   'ftm_eid': 23424620,
   'votesmart_id': 146076,
   'opensecrets_id': '',
   'ballotpedia': 'Nancy_Mace',
   'sponsor_type_id': 2,
   'sponsor_order': 72,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2273,
   'person_hash': '76ujg2mr',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'David Mack',
   'first_name': 'David',
   'middle_name': 'J.',
   'last_name': 'Mack',
   'suffix': 'III',
   'nickname': '',
   'district': 'HD-109',
   'ftm_eid': 6377896,
   'votesmart_id': 11965,
   'opensecrets_id': '',
   'ballotpedia': 'David_Mack',
   'sponsor_type_id': 2,
   'sponsor_order': 73,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18091,
   'person_hash': '1id5tvhx',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Roy Magnuson',
   'first_name': 'Roy',
   'middle_name': 'Josiah',
   'last_name': 'Magnuson',
   'suffix': '',
   'nickname': '',
   'district': 'HD-038',
   'ftm_eid': 39714605,
   'votesmart_id': 173067,
   'opensecrets_id': '',
   'ballotpedia': 'Roy_G._Magnuson',
   'sponsor_type_id': 2,
   'sponsor_order': 74,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18657,
   'person_hash': '5i6y94xz',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Richard Martin',
   'first_name': 'Richard',
   'middle_name': 'A.',
   'last_name': 'Martin',
   'suffix': 'Jr.',
   'nickname': 'Rick',
   'district': 'HD-040',
   'ftm_eid': 24862373,
   'votesmart_id': 152540,
   'opensecrets_id': '',
   'ballotpedia': 'Richard_Martin_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 75,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 10950,
   'person_hash': '4rxw3zle',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Peter McCoy',
   'first_name': 'Peter',
   'middle_name': 'M.',
   'last_name': 'McCoy',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-115',
   'ftm_eid': 6687315,
   'votesmart_id': 121752,
   'opensecrets_id': '',
   'ballotpedia': 'Peter_McCoy',
   'sponsor_type_id': 2,
   'sponsor_order': 76,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18092,
   'person_hash': 'qs7ypw0z',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'John Mccravy',
   'first_name': 'John',
   'middle_name': 'R.',
   'last_name': 'Mccravy',
   'suffix': 'III',
   'nickname': '',
   'district': 'HD-013',
   'ftm_eid': 7975200,
   'votesmart_id': 139452,
   'opensecrets_id': '',
   'ballotpedia': 'John_McCravy',
   'sponsor_type_id': 2,
   'sponsor_order': 77,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19933,
   'person_hash': 'mhexahaj',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Annie McDaniel',
   'first_name': 'Annie',
   'middle_name': 'E.',
   'last_name': 'McDaniel',
   'suffix': '',
   'nickname': '',
   'district': 'HD-041',
   'ftm_eid': 15044362,
   'votesmart_id': 48010,
   'opensecrets_id': '',
   'ballotpedia': 'Annie_McDaniel',
   'sponsor_type_id': 2,
   'sponsor_order': 78,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19502,
   'person_hash': 'ed3ydzfo',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Timothy McGinnis',
   'first_name': 'Timothy',
   'middle_name': 'A.',
   'last_name': 'McGinnis',
   'suffix': '',
   'nickname': 'Tim',
   'district': 'HD-056',
   'ftm_eid': 44059947,
   'votesmart_id': 176728,
   'opensecrets_id': '',
   'ballotpedia': 'Tim_McGinnis',
   'sponsor_type_id': 2,
   'sponsor_order': 79,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16331,
   'person_hash': '4z9dkcte',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Cezar McKnight',
   'first_name': 'Cezar',
   'middle_name': 'E.',
   'last_name': 'McKnight',
   'suffix': '',
   'nickname': '',
   'district': 'HD-101',
   'ftm_eid': 11023023,
   'votesmart_id': 139555,
   'opensecrets_id': '',
   'ballotpedia': 'Cezar_McKnight',
   'sponsor_type_id': 2,
   'sponsor_order': 80,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19934,
   'person_hash': '2cmwsiug',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'JA Moore',
   'first_name': 'JA',
   'middle_name': '',
   'last_name': 'Moore',
   'suffix': '',
   'nickname': '',
   'district': 'HD-015',
   'ftm_eid': 45316155,
   'votesmart_id': 184240,
   'opensecrets_id': '',
   'ballotpedia': 'J.A._Moore',
   'sponsor_type_id': 2,
   'sponsor_order': 81,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19935,
   'person_hash': 'y3x6sumd',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Adam Morgan',
   'first_name': 'Adam',
   'middle_name': 'M.',
   'last_name': 'Morgan',
   'suffix': '',
   'nickname': '',
   'district': 'HD-020',
   'ftm_eid': 44932324,
   'votesmart_id': 181018,
   'opensecrets_id': '',
   'ballotpedia': 'Adam_Morgan',
   'sponsor_type_id': 2,
   'sponsor_order': 82,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2280,
   'person_hash': 'born13ek',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Dennis Moss',
   'first_name': 'Dennis',
   'middle_name': 'Carroll',
   'last_name': 'Moss',
   'suffix': '',
   'nickname': '',
   'district': 'HD-029',
   'ftm_eid': 6476398,
   'votesmart_id': 59289,
   'opensecrets_id': '',
   'ballotpedia': 'Dennis_Moss_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 83,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2281,
   'person_hash': 'zhnullct',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Steve Moss',
   'first_name': 'Steve',
   'middle_name': '',
   'last_name': 'Moss',
   'suffix': '',
   'nickname': '',
   'district': 'HD-030',
   'ftm_eid': 13006364,
   'votesmart_id': 111198,
   'opensecrets_id': '',
   'ballotpedia': 'Steve_Moss_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 84,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 10951,
   'person_hash': '4zc45o5k',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Christopher Murphy',
   'first_name': 'Christopher',
   'middle_name': 'J.',
   'last_name': 'Murphy',
   'suffix': '',
   'nickname': 'Chris',
   'district': 'HD-098',
   'ftm_eid': 6687301,
   'votesmart_id': 97738,
   'opensecrets_id': '',
   'ballotpedia': 'Chris_Murphy_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 85,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18094,
   'person_hash': '3liwh2wu',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Brandon Newton',
   'first_name': 'Brandon',
   'middle_name': 'Michael',
   'last_name': 'Newton',
   'suffix': '',
   'nickname': '',
   'district': 'HD-045',
   'ftm_eid': 7991767,
   'votesmart_id': 95106,
   'opensecrets_id': '',
   'ballotpedia': 'Brandon_Newton',
   'sponsor_type_id': 2,
   'sponsor_order': 86,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14301,
   'person_hash': 'wmpiapod',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Weston Newton',
   'first_name': 'Weston',
   'middle_name': '',
   'last_name': 'Newton',
   'suffix': '',
   'nickname': '',
   'district': 'HD-120',
   'ftm_eid': 7991767,
   'votesmart_id': 95106,
   'opensecrets_id': '',
   'ballotpedia': 'Weston_Newton',
   'sponsor_type_id': 2,
   'sponsor_order': 87,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14302,
   'person_hash': 'lwdai60q',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Mandy Norrell',
   'first_name': 'Mandy',
   'middle_name': 'Powers',
   'last_name': 'Norrell',
   'suffix': '',
   'nickname': '',
   'district': 'HD-044',
   'ftm_eid': 8017223,
   'votesmart_id': 105059,
   'opensecrets_id': '',
   'ballotpedia': 'Mandy_Powers_Norrell',
   'sponsor_type_id': 2,
   'sponsor_order': 88,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16116,
   'person_hash': 'szne3iyz',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Russell Ott',
   'first_name': 'Russell',
   'middle_name': 'L.',
   'last_name': 'Ott',
   'suffix': '',
   'nickname': '',
   'district': 'HD-093',
   'ftm_eid': 18912306,
   'votesmart_id': 144829,
   'opensecrets_id': '',
   'ballotpedia': 'Russell_L._Ott',
   'sponsor_type_id': 2,
   'sponsor_order': 89,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2290,
   'person_hash': 'pcvaxpsn',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Anne Parks',
   'first_name': 'Anne',
   'middle_name': '',
   'last_name': 'Parks',
   'suffix': '',
   'nickname': '',
   'district': 'HD-012',
   'ftm_eid': 6377982,
   'votesmart_id': 139559,
   'opensecrets_id': '',
   'ballotpedia': 'Julia_Parks',
   'sponsor_type_id': 2,
   'sponsor_order': 90,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19449,
   'person_hash': 'n5fv2llh',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Marvin Pendarvis',
   'first_name': 'Marvin',
   'middle_name': 'R.',
   'last_name': 'Pendarvis',
   'suffix': '',
   'nickname': '',
   'district': 'HD-113',
   'ftm_eid': 41609737,
   'votesmart_id': 176604,
   'opensecrets_id': '',
   'ballotpedia': 'Marvin_Pendarvis',
   'sponsor_type_id': 2,
   'sponsor_order': 91,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 11219,
   'person_hash': 'fq3lygdh',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Thomas Pope',
   'first_name': 'Thomas',
   'middle_name': 'E.',
   'last_name': 'Pope',
   'suffix': '',
   'nickname': 'Tommy',
   'district': 'HD-047',
   'ftm_eid': 6687222,
   'votesmart_id': 121790,
   'opensecrets_id': '',
   'ballotpedia': 'Tommy_Pope',
   'sponsor_type_id': 2,
   'sponsor_order': 92,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14303,
   'person_hash': 'z5dj8goh',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Robert Ridgeway',
   'first_name': 'Robert',
   'middle_name': 'L.',
   'last_name': 'Ridgeway',
   'suffix': 'III',
   'nickname': '',
   'district': 'HD-064',
   'ftm_eid': 16501222,
   'votesmart_id': 139562,
   'opensecrets_id': '',
   'ballotpedia': 'Robert_L._Ridgeway,_III',
   'sponsor_type_id': 2,
   'sponsor_order': 93,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14305,
   'person_hash': 'ru504y2r',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Samuel Rivers',
   'first_name': 'Samuel',
   'middle_name': '',
   'last_name': 'Rivers',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-015',
   'ftm_eid': 16072505,
   'votesmart_id': 139455,
   'opensecrets_id': '',
   'ballotpedia': 'Samuel_Rivers,_Jr.',
   'sponsor_type_id': 2,
   'sponsor_order': 94,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 14306,
   'person_hash': 'eubppo7a',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Leola Robinson-Simpson',
   'first_name': 'Leola',
   'middle_name': 'C.',
   'last_name': 'Robinson-Simpson',
   'suffix': '',
   'nickname': '',
   'district': 'HD-025',
   'ftm_eid': 16072507,
   'votesmart_id': 139563,
   'opensecrets_id': '',
   'ballotpedia': 'Leola_Robinson-Simpson',
   'sponsor_type_id': 2,
   'sponsor_order': 95,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19936,
   'person_hash': 'ymvtjr6n',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Seth Rose',
   'first_name': 'Seth',
   'middle_name': 'C.',
   'last_name': 'Rose',
   'suffix': '',
   'nickname': '',
   'district': 'HD-072',
   'ftm_eid': 45316216,
   'votesmart_id': 132461,
   'opensecrets_id': '',
   'ballotpedia': 'Seth_Rose',
   'sponsor_type_id': 2,
   'sponsor_order': 96,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2295,
   'person_hash': '1g9zkv86',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Todd Rutherford',
   'first_name': 'J. Todd',
   'middle_name': '',
   'last_name': 'Rutherford',
   'suffix': '',
   'nickname': '',
   'district': 'HD-074',
   'ftm_eid': 8298907,
   'votesmart_id': 25057,
   'opensecrets_id': '',
   'ballotpedia': 'James_Rutherford',
   'sponsor_type_id': 2,
   'sponsor_order': 97,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2296,
   'person_hash': '5uj869sj',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Sandifer',
   'first_name': 'William',
   'middle_name': 'E.',
   'last_name': 'Sandifer',
   'suffix': 'III',
   'nickname': 'Bill',
   'district': 'HD-002',
   'ftm_eid': 6574037,
   'votesmart_id': 8945,
   'opensecrets_id': '',
   'ballotpedia': 'Bill_Sandifer,_III',
   'sponsor_type_id': 2,
   'sponsor_order': 98,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19938,
   'person_hash': '01d5l7tl',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Krystle Simmons',
   'first_name': 'Krystle',
   'middle_name': 'N.',
   'last_name': 'Simmons',
   'suffix': '',
   'nickname': '',
   'district': 'HD-117',
   'ftm_eid': 45316270,
   'votesmart_id': 184255,
   'opensecrets_id': '',
   'ballotpedia': 'Krystle_Simmons',
   'sponsor_type_id': 2,
   'sponsor_order': 99,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2299,
   'person_hash': 'icmutsmr',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Gary Simrill',
   'first_name': 'J. Gary',
   'middle_name': '',
   'last_name': 'Simrill',
   'suffix': '',
   'nickname': '',
   'district': 'HD-046',
   'ftm_eid': 6574066,
   'votesmart_id': 8951,
   'opensecrets_id': '',
   'ballotpedia': 'Gary_Simrill',
   'sponsor_type_id': 2,
   'sponsor_order': 100,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2302,
   'person_hash': '9bg2vf9m',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Murrell Smith',
   'first_name': 'Murrell',
   'middle_name': '',
   'last_name': 'Smith',
   'suffix': 'Jr.',
   'nickname': '',
   'district': 'HD-067',
   'ftm_eid': 13006450,
   'votesmart_id': 121732,
   'opensecrets_id': '',
   'ballotpedia': 'George_Smith,_Jr.',
   'sponsor_type_id': 2,
   'sponsor_order': 101,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2303,
   'person_hash': 'v8t2lc0v',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Garry Smith',
   'first_name': 'Garry',
   'middle_name': 'R.',
   'last_name': 'Smith',
   'suffix': '',
   'nickname': '',
   'district': 'HD-027',
   'ftm_eid': 13006356,
   'votesmart_id': 48091,
   'opensecrets_id': '',
   'ballotpedia': 'Garry_Smith,_South_Carolina_Representative',
   'sponsor_type_id': 2,
   'sponsor_order': 102,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2306,
   'person_hash': '6ptu0vtp',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Michael Sottile',
   'first_name': 'F. Michael',
   'middle_name': '',
   'last_name': 'Sottile',
   'suffix': '',
   'nickname': 'Mike',
   'district': 'HD-112',
   'ftm_eid': 13006546,
   'votesmart_id': 105061,
   'opensecrets_id': '',
   'ballotpedia': 'Mike_Sottile',
   'sponsor_type_id': 2,
   'sponsor_order': 103,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2307,
   'person_hash': 'lo846xd2',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Kit Spires',
   'first_name': 'L. Kit',
   'middle_name': '',
   'last_name': 'Spires',
   'suffix': '',
   'nickname': '',
   'district': 'HD-096',
   'ftm_eid': 13006513,
   'votesmart_id': 57358,
   'opensecrets_id': '',
   'ballotpedia': 'Lawrence_Kit_Spires',
   'sponsor_type_id': 2,
   'sponsor_order': 104,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2308,
   'person_hash': 'jjlgvx7e',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Leonidas Stavrinakis',
   'first_name': 'Leonidas',
   'middle_name': 'E.',
   'last_name': 'Stavrinakis',
   'suffix': '',
   'nickname': 'Leon',
   'district': 'HD-119',
   'ftm_eid': 13006560,
   'votesmart_id': 59396,
   'opensecrets_id': '',
   'ballotpedia': 'Leonidas_Stavrinakis',
   'sponsor_type_id': 2,
   'sponsor_order': 105,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2310,
   'person_hash': 'rwzgbmgt',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Tommy Stringer',
   'first_name': 'Tommy',
   'middle_name': 'M.',
   'last_name': 'Stringer',
   'suffix': '',
   'nickname': '',
   'district': 'HD-018',
   'ftm_eid': 13006341,
   'votesmart_id': 104995,
   'opensecrets_id': '',
   'ballotpedia': 'Tommy_Stringer',
   'sponsor_type_id': 2,
   'sponsor_order': 106,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 11222,
   'person_hash': 'erg2celo',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Edward Tallon',
   'first_name': 'Edward',
   'middle_name': 'R.',
   'last_name': 'Tallon',
   'suffix': 'Sr.',
   'nickname': 'Eddie',
   'district': 'HD-033',
   'ftm_eid': 6687184,
   'votesmart_id': 121711,
   'opensecrets_id': '',
   'ballotpedia': 'Eddie_Tallon',
   'sponsor_type_id': 2,
   'sponsor_order': 107,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 10954,
   'person_hash': 'i0oxx7wl',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Bill Taylor',
   'first_name': 'Bill',
   'middle_name': '',
   'last_name': 'Taylor',
   'suffix': '',
   'nickname': '',
   'district': 'HD-086',
   'ftm_eid': 13006490,
   'votesmart_id': 121739,
   'opensecrets_id': '',
   'ballotpedia': 'Bill_Taylor_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 108,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 10955,
   'person_hash': 'c4p8ao4l',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Anne Thayer',
   'first_name': 'Anne',
   'middle_name': 'J.',
   'last_name': 'Thayer',
   'suffix': '',
   'nickname': '',
   'district': 'HD-009',
   'ftm_eid': 13006313,
   'votesmart_id': 121699,
   'opensecrets_id': '',
   'ballotpedia': 'Anne_Thayer',
   'sponsor_type_id': 2,
   'sponsor_order': 109,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18656,
   'person_hash': '839638na',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Ivory Thigpen',
   'first_name': 'Ivory',
   'middle_name': 'Torrey',
   'last_name': 'Thigpen',
   'suffix': '',
   'nickname': '',
   'district': 'HD-079',
   'ftm_eid': 39714644,
   'votesmart_id': 168981,
   'opensecrets_id': '',
   'ballotpedia': 'Ivory_Thigpen',
   'sponsor_type_id': 2,
   'sponsor_order': 110,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2312,
   'person_hash': 'rl9w7dbh',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'McLain Toole',
   'first_name': 'McLain',
   'middle_name': 'R.',
   'last_name': 'Toole',
   'suffix': '',
   'nickname': 'Mac',
   'district': 'HD-088',
   'ftm_eid': 6602559,
   'votesmart_id': 48227,
   'opensecrets_id': '',
   'ballotpedia': 'McLain_Toole',
   'sponsor_type_id': 2,
   'sponsor_order': 111,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19546,
   'person_hash': 'sy5c1egh',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Ashley Trantham',
   'first_name': 'Ashley',
   'middle_name': 'B.',
   'last_name': 'Trantham',
   'suffix': '',
   'nickname': '',
   'district': 'HD-028',
   'ftm_eid': 44059954,
   'votesmart_id': 176785,
   'opensecrets_id': '',
   'ballotpedia': 'Ashley_Trantham',
   'sponsor_type_id': 2,
   'sponsor_order': 112,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2316,
   'person_hash': 'rwcwb8ra',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'David Weeks',
   'first_name': 'J. David',
   'middle_name': '',
   'last_name': 'Weeks',
   'suffix': '',
   'nickname': '',
   'district': 'HD-051',
   'ftm_eid': 13006416,
   'votesmart_id': 47971,
   'opensecrets_id': '',
   'ballotpedia': 'J._David_Weeks',
   'sponsor_type_id': 2,
   'sponsor_order': 113,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18246,
   'person_hash': 'k1pkp3w1',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'John West',
   'first_name': 'John',
   'middle_name': 'Taliaferro',
   'last_name': 'West',
   'suffix': 'IV',
   'nickname': '',
   'district': 'HD-007',
   'ftm_eid': 39714555,
   'votesmart_id': 48173,
   'opensecrets_id': '',
   'ballotpedia': 'Jay_West',
   'sponsor_type_id': 2,
   'sponsor_order': 114,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 18095,
   'person_hash': 'a6tyigst',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Wheeler',
   'first_name': 'William',
   'middle_name': 'Walter',
   'last_name': 'Wheeler',
   'suffix': 'III',
   'nickname': '',
   'district': 'HD-050',
   'ftm_eid': 39714630,
   'votesmart_id': 168970,
   'opensecrets_id': '',
   'ballotpedia': 'Will_Wheeler',
   'sponsor_type_id': 2,
   'sponsor_order': 115,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2318,
   'person_hash': 'd23pgoxl',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Brian White',
   'first_name': 'W. Brian',
   'middle_name': '',
   'last_name': 'White',
   'suffix': '',
   'nickname': '',
   'district': 'HD-006',
   'ftm_eid': 6574209,
   'votesmart_id': 24998,
   'opensecrets_id': '',
   'ballotpedia': 'Brian_White_(South_Carolina)',
   'sponsor_type_id': 2,
   'sponsor_order': 116,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2319,
   'person_hash': 'tbhvknl4',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'William Whitmire',
   'first_name': 'William',
   'middle_name': 'R.',
   'last_name': 'Whitmire',
   'suffix': '',
   'nickname': 'Bill',
   'district': 'HD-001',
   'ftm_eid': 13006297,
   'votesmart_id': 47969,
   'opensecrets_id': '',
   'ballotpedia': 'Bill_Whitmire',
   'sponsor_type_id': 2,
   'sponsor_order': 117,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2320,
   'person_hash': 'aggzahkg',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Robert Williams',
   'first_name': 'Robert',
   'middle_name': 'Q.',
   'last_name': 'Williams',
   'suffix': '',
   'nickname': '',
   'district': 'HD-062',
   'ftm_eid': 6513334,
   'votesmart_id': 130663,
   'opensecrets_id': '',
   'ballotpedia': 'Robert_Williams,_South_Carolina_Representative',
   'sponsor_type_id': 2,
   'sponsor_order': 118,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19937,
   'person_hash': 'hcucj11q',
   'party_id': 1,
   'party': 'D',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Shedron Williams',
   'first_name': 'Shedron',
   'middle_name': 'D.',
   'last_name': 'Williams',
   'suffix': '',
   'nickname': '',
   'district': 'HD-122',
   'ftm_eid': 44932355,
   'votesmart_id': 132375,
   'opensecrets_id': '',
   'ballotpedia': 'Shedron_Williams',
   'sponsor_type_id': 2,
   'sponsor_order': 119,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 2321,
   'person_hash': 'helc0nks',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Mark Willis',
   'first_name': 'Mark',
   'middle_name': 'N.',
   'last_name': 'Willis',
   'suffix': '',
   'nickname': '',
   'district': 'HD-016',
   'ftm_eid': 6670052,
   'votesmart_id': 57624,
   'opensecrets_id': '',
   'ballotpedia': 'Mark_Willis',
   'sponsor_type_id': 2,
   'sponsor_order': 120,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19645,
   'person_hash': 'szw5m8pl',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Christopher Wooten',
   'first_name': 'Christopher',
   'middle_name': 'Sloan',
   'last_name': 'Wooten',
   'suffix': '',
   'nickname': 'Chris',
   'district': 'HD-069',
   'ftm_eid': 44210946,
   'votesmart_id': 177641,
   'opensecrets_id': '',
   'ballotpedia': 'Chris_Wooten',
   'sponsor_type_id': 2,
   'sponsor_order': 121,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 19394,
   'person_hash': 'j6lki0u8',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Ronald Young',
   'first_name': 'Ronald',
   'middle_name': '',
   'last_name': 'Young',
   'suffix': '',
   'nickname': 'Ronnie',
   'district': 'HD-084',
   'ftm_eid': 43550182,
   'votesmart_id': 10050,
   'opensecrets_id': '',
   'ballotpedia': 'Ronnie_Young',
   'sponsor_type_id': 2,
   'sponsor_order': 122,
   'committee_sponsor': 0,
   'committee_id': '0'},
  {'people_id': 16332,
   'person_hash': 'vu8nc1aw',
   'party_id': 2,
   'party': 'R',
   'role_id': 1,
   'role': 'Rep',
   'name': 'Richard Yow',
   'first_name': 'Richard',
   'middle_name': 'L.',
   'last_name': 'Yow',
   'suffix': '',
   'nickname': 'Richie',
   'district': 'HD-053',
   'ftm_eid': 11023563,
   'votesmart_id': 139467,
   'opensecrets_id': '',
   'ballotpedia': 'Richie_Yow',
   'sponsor_type_id': 2,
   'sponsor_order': 123,
   'committee_sponsor': 0,
   'committee_id': '0'}],
 'sasts': [],
 'subjects': [],
 'texts': [{'doc_id': 2008443,
   'date': '2019-05-02',
   'type': 'Introduced',
   'type_id': 1,
   'mime': 'text/html',
   'mime_id': 1,
   'url': 'https://legiscan.com/SC/text/H4523/id/2008443',
   'state_link': 'https://www.scstatehouse.gov/sess123_2019-2020/prever/4523_20190502.htm',
   'text_size': 3597}],
 'votes': [],
 'amendments': [],
 'supplements': [],
 'calendar': []}
 

LegiScan Datasets#

It'd take forever to download the bills one at a time, so we take advantage of LegiScan's datasets capability. They're a whole set of bill data for each session of the legislature.

datasets = legis.get_dataset_list()
dataset = legis.get_dataset(datasets[20]['session_id'], datasets[20]['access_key'])
dataset.keys()
dict_keys(['state_id', 'session_id', 'session_name', 'dataset_hash', 'dataset_date', 'dataset_size', 'mime_type', 'zip'])

They come in a really weird format, though: a base64-encoded zip file. SO first we need to convert the base64 zipfile into a normal file, then unzip it!

z_bytes = base64.b64decode(dataset['zip'])
z = zipfile.ZipFile(io.BytesIO(z_bytes))
z.extractall("./sample-data")

It creates a lot lot lot lot lot of .json files. For example, let's take a look at a sample of what we just extracted.

import glob

filenames = glob.glob("./sample-data/*/*/bill/*", recursive=True)
filenames[:15]
['./sample-data/AK/2017-2018_30th_Legislature/bill/SCR10.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/SB124.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HB65.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HB392.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HB238.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HCR25.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HB111.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HJR2.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HCR1.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HB404.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HB280.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/SB173.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/SCR9.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HCR401.json',
 './sample-data/AK/2017-2018_30th_Legislature/bill/HB32.json']

Each file has all sorts of information about the bill, but none of the text of the bill itself! You can see for yourself:

import json

json_data = json.load(open("./sample-data/AK/2017-2018_30th_Legislature/bill/SCR10.json"))
json_data
{'bill': {'bill_id': 1004624,
  'change_hash': '557d10e3e229284c17c4354e988bad06',
  'session_id': 1397,
  'session': {'session_id': 1397,
   'session_name': '30th Legislature',
   'session_title': '30th Legislature',
   'year_start': 2017,
   'year_end': 2018,
   'special': 0},
  'url': 'https://legiscan.com/AK/bill/SCR10/2017',
  'state_link': 'http://www.akleg.gov/basis/Bill/Detail/30?Root=SCR10',
  'completed': 0,
  'status': 3,
  'status_date': '2018-04-28',
  'progress': [{'date': '2017-04-07', 'event': 1},
   {'date': '2018-02-02', 'event': 10},
   {'date': '2018-02-09', 'event': 2},
   {'date': '2018-03-09', 'event': 10},
   {'date': '2018-04-28', 'event': 3}],
  'state': 'AK',
  'state_id': 2,
  'bill_number': 'SCR10',
  'bill_type': 'CR',
  'bill_type_id': '3',
  'body': 'S',
  'body_id': 14,
  'current_body': 'H',
  'current_body_id': 13,
  'title': 'Alaska Year Of Innovation',
  'description': 'Proclaiming 2019 to be the Year of Innovation in Alaska.',
  'committee': [],
  'pending_committee_id': 0,
  'history': [{'date': '2017-04-07',
    'action': 'READ THE FIRST TIME - REFERRALS',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 1},
   {'date': '2017-04-07',
    'action': 'L&C, STA',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2017-04-07',
    'action': 'COSPONSOR(S): HUGHES, BEGICH',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2017-04-12',
    'action': 'L&C RPT CS 4DP 1AM NEW TITLE',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2017-04-12',
    'action': 'DP: COSTELLO, HUGHES, MEYER, GARDNER',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2017-04-12',
    'action': 'AM: STEVENS',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2017-04-12',
    'action': 'FN1: ZERO(LEG)',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-02',
    'action': 'STA RPT CS 2DP 2NR NEW TITLE',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 1},
   {'date': '2018-02-02',
    'action': 'DP: MEYER, EGAN',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-02',
    'action': 'NR: WILSON, GIESSEL',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-02',
    'action': 'FN2: ZERO(LEG)',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-09',
    'action': 'RULES TO CALENDAR 2/9/2018',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-09',
    'action': 'READ THE SECOND TIME',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-09',
    'action': 'STA CS ADOPTED UC',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-09',
    'action': 'BEFORE SENATE ON FINAL PASSAGE',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-09',
    'action': 'PASSED Y18 N- E1 V1',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-09',
    'action': 'TRANSMITTED TO (H)',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 1},
   {'date': '2018-02-09',
    'action': 'VERSION: CSSCR 10(STA)',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-02-12',
    'action': 'READ THE FIRST TIME - REFERRALS',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-02-12',
    'action': 'STA, L&C',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-03-09',
    'action': 'STA RPT 5DP',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 1},
   {'date': '2018-03-09',
    'action': 'DP: LEDOUX, WOOL, JOHNSON, BIRCH, KREISS-TOMKINS',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-03-09',
    'action': 'FN2: ZERO(LEG)',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-04-23',
    'action': 'L&C REFERRAL WAIVED',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-04-28',
    'action': 'RULES TO CALENDAR 4/28/2018',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-04-28',
    'action': 'READ THE SECOND TIME',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-04-28',
    'action': 'PASSED Y35 N1 E4',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-04-28',
    'action': 'RETURN TO (S), TRANSMIT TO GOV NEXT',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 1},
   {'date': '2018-04-28',
    'action': 'VERSION: CSSCR 10(STA)',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-04-28',
    'action': 'CROSS SPONSOR(S): MILLETT, JOSEPHSON, KAWASAKI',
    'chamber': 'H',
    'chamber_id': 13,
    'importance': 0},
   {'date': '2018-04-30',
    'action': 'AWAITING TRANSMITTAL TO GOV',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0},
   {'date': '2018-06-28',
    'action': 'LEGISLATIVE RESOLVE 34',
    'chamber': 'S',
    'chamber_id': 14,
    'importance': 0}],
  'sponsors': [{'people_id': 11301,
    'person_hash': '00r0668y',
    'party_id': 2,
    'party': 'R',
    'role_id': 2,
    'role': 'Sen',
    'name': 'Mia Costello',
    'first_name': 'Mia',
    'middle_name': 'C.',
    'last_name': 'Costello',
    'suffix': '',
    'nickname': '',
    'district': 'SD-K',
    'ftm_eid': 6692539,
    'votesmart_id': 117406,
    'opensecrets_id': '',
    'ballotpedia': 'Mia_Costello',
    'sponsor_type_id': 1,
    'sponsor_order': 1,
    'committee_sponsor': 0,
    'committee_id': '0'},
   {'people_id': 14388,
    'person_hash': 'ybr0ht47',
    'party_id': 2,
    'party': 'R',
    'role_id': 2,
    'role': 'Sen',
    'name': 'Shelley Hughes',
    'first_name': 'Shelley',
    'middle_name': '',
    'last_name': 'Hughes',
    'suffix': '',
    'nickname': '',
    'district': 'SD-F',
    'ftm_eid': 13789707,
    'votesmart_id': 140422,
    'opensecrets_id': '',
    'ballotpedia': 'Shelley_Hughes',
    'sponsor_type_id': 2,
    'sponsor_order': 2,
    'committee_sponsor': 0,
    'committee_id': '0'},
   {'people_id': 18978,
    'person_hash': 'dbulwgc3',
    'party_id': 1,
    'party': 'D',
    'role_id': 2,
    'role': 'Sen',
    'name': 'Tom Begich',
    'first_name': 'Tom',
    'middle_name': '',
    'last_name': 'Begich',
    'suffix': '',
    'nickname': '',
    'district': 'SD-J',
    'ftm_eid': 9424831,
    'votesmart_id': 171468,
    'opensecrets_id': '',
    'ballotpedia': 'Tom_Begich',
    'sponsor_type_id': 2,
    'sponsor_order': 3,
    'committee_sponsor': 0,
    'committee_id': '0'},
   {'people_id': 6043,
    'person_hash': 'cpj136u0',
    'party_id': 2,
    'party': 'R',
    'role_id': 1,
    'role': 'Rep',
    'name': 'Charisse Millett',
    'first_name': 'Charisse',
    'middle_name': 'E.',
    'last_name': 'Millett',
    'suffix': '',
    'nickname': '',
    'district': 'HD-025',
    'ftm_eid': 6678391,
    'votesmart_id': 107815,
    'opensecrets_id': '',
    'ballotpedia': 'Charisse_E._Millett',
    'sponsor_type_id': 2,
    'sponsor_order': 4,
    'committee_sponsor': 0,
    'committee_id': '0'},
   {'people_id': 14389,
    'person_hash': '459b60g1',
    'party_id': 1,
    'party': 'D',
    'role_id': 1,
    'role': 'Rep',
    'name': 'Andrew Josephson',
    'first_name': 'Andrew',
    'middle_name': 'L.',
    'last_name': 'Josephson',
    'suffix': '',
    'nickname': 'Andy',
    'district': 'HD-017',
    'ftm_eid': 9400827,
    'votesmart_id': 140434,
    'opensecrets_id': '',
    'ballotpedia': 'Andrew_L._Josephson',
    'sponsor_type_id': 2,
    'sponsor_order': 5,
    'committee_sponsor': 0,
    'committee_id': '0'},
   {'people_id': 6052,
    'person_hash': 'vfp8rwqc',
    'party_id': 1,
    'party': 'D',
    'role_id': 2,
    'role': 'Sen',
    'name': 'Scott Kawasaki',
    'first_name': 'Scott',
    'middle_name': '',
    'last_name': 'Kawasaki',
    'suffix': '',
    'nickname': '',
    'district': 'SD-A',
    'ftm_eid': 6464847,
    'votesmart_id': 27313,
    'opensecrets_id': '',
    'ballotpedia': 'Scott_J._Kawasaki',
    'sponsor_type_id': 2,
    'sponsor_order': 6,
    'committee_sponsor': 0,
    'committee_id': '0'}],
  'sasts': [],
  'subjects': [{'subject_id': 4526, 'subject_name': 'Business'},
   {'subject_id': 4657, 'subject_name': 'Economic Development'},
   {'subject_id': 4690, 'subject_name': 'Economy'},
   {'subject_id': 4702, 'subject_name': 'Partnerships'},
   {'subject_id': 4527, 'subject_name': 'Proclamations'},
   {'subject_id': 4553, 'subject_name': 'Science & Technology'}],
  'texts': [{'doc_id': 1587841,
    'date': '2017-04-07',
    'type': 'Introduced',
    'type_id': 1,
    'mime': 'application/pdf',
    'mime_id': 2,
    'url': 'https://legiscan.com/AK/text/SCR10/id/1587841',
    'state_link': 'http://www.legis.state.ak.us/PDF/30/Bills/SCR010A.PDF',
    'text_size': 87767},
   {'doc_id': 1592227,
    'date': '2017-04-12',
    'type': 'Comm Sub',
    'type_id': 2,
    'mime': 'application/pdf',
    'mime_id': 2,
    'url': 'https://legiscan.com/AK/text/SCR10/id/1592227',
    'state_link': 'http://www.legis.state.ak.us/PDF/30/Bills/SCR010B.PDF',
    'text_size': 94024},
   {'doc_id': 1717195,
    'date': '2018-02-02',
    'type': 'Comm Sub',
    'type_id': 2,
    'mime': 'application/pdf',
    'mime_id': 2,
    'url': 'https://legiscan.com/AK/text/SCR10/id/1717195',
    'state_link': 'http://www.legis.state.ak.us/PDF/30/Bills/SCR010C.PDF',
    'text_size': 93179},
   {'doc_id': 1790359,
    'date': '2018-05-01',
    'type': 'Enrolled',
    'type_id': 5,
    'mime': 'application/pdf',
    'mime_id': 2,
    'url': 'https://legiscan.com/AK/text/SCR10/id/1790359',
    'state_link': 'http://www.legis.state.ak.us/PDF/30/Bills/SCR010Z.PDF',
    'text_size': 592822}],
  'votes': [{'roll_call_id': 698344,
    'date': '2018-02-09',
    'desc': 'Senate: Second Reading - Final Passage',
    'yea': 18,
    'nay': 0,
    'nv': 0,
    'absent': 1,
    'total': 19,
    'passed': 1,
    'chamber': 'S',
    'chamber_id': 14,
    'url': 'https://legiscan.com/AK/rollcall/SCR10/id/698344',
    'state_link': 'http://www.legis.state.ak.us/basis/get_jrn_page.asp?session=30&bill=SCR10&jrn=1972&hse=S'},
   {'roll_call_id': 745305,
    'date': '2018-04-28',
    'desc': 'House: Second Reading Final Passage',
    'yea': 35,
    'nay': 1,
    'nv': 0,
    'absent': 4,
    'total': 40,
    'passed': 1,
    'chamber': 'H',
    'chamber_id': 13,
    'url': 'https://legiscan.com/AK/rollcall/SCR10/id/745305',
    'state_link': 'http://www.legis.state.ak.us/basis/get_jrn_page.asp?session=30&bill=SCR10&jrn=3481&hse=H'}],
  'amendments': [],
  'supplements': [],
  'calendar': [{'type_id': 1,
    'type': 'Hearing',
    'date': '2017-04-10',
    'time': '09:00',
    'location': 'Senate Labor & Commerce Hearing',
    'description': 'Senate Labor & Commerce Hearing'},
   {'type_id': 1,
    'type': 'Hearing',
    'date': '2017-04-11',
    'time': '09:00',
    'location': 'Senate Labor & Commerce Hearing',
    'description': 'Senate Labor & Commerce Hearing'},
   {'type_id': 1,
    'type': 'Hearing',
    'date': '2017-04-11',
    'time': '13:30',
    'location': 'Senate Labor & Commerce Hearing',
    'description': 'Senate Labor & Commerce Hearing'},
   {'type_id': 1,
    'type': 'Hearing',
    'date': '2018-02-01',
    'time': '15:30',
    'location': 'Senate State Affairs Hearing',
    'description': 'Senate State Affairs Hearing'},
   {'type_id': 1,
    'type': 'Hearing',
    'date': '2018-03-06',
    'time': '15:15',
    'location': 'House State Affairs Hearing',
    'description': 'House State Affairs Hearing'},
   {'type_id': 1,
    'type': 'Hearing',
    'date': '2018-03-08',
    'time': '15:15',
    'location': 'House State Affairs Hearing',
    'description': 'House State Affairs Hearing'}]}}

You can download the bill text if you have the ID, but... for some reason we don't do this. I'm going to be honest: I don't remember why. Maybe it's because they're older versions? They're incomplete? I truly have forgotten.

doc = legis.get_bill_text('2015157')
contents = base64.b64decode(doc['doc'])
with open("filename.html", "wb") as file:
    file.write(contents)

What we're going to need is the URL to the published version.

json_data['bill']['texts'][-1]
{'doc_id': 1790359,
 'date': '2018-05-01',
 'type': 'Enrolled',
 'type_id': 5,
 'mime': 'application/pdf',
 'mime_id': 2,
 'url': 'https://legiscan.com/AK/text/SCR10/id/1790359',
 'state_link': 'http://www.legis.state.ak.us/PDF/30/Bills/SCR010Z.PDF',
 'text_size': 592822}

We're going to need the URL to the published version from every single one of those JSON files.

Download and extract all of the datasets from LegiScan#

datasets = legis.get_dataset_list()
len(datasets)
583

Downloading and extracting all 583 is going to take a while, so we'll use a progress bar from tqdm to keep track of where we're at.

import tqdm

total = len(datasets)
for dataset in tqdm.tqdm_notebook(datasets):
    session_id = dataset['session_id']
    access_key = dataset['access_key']
    details = legis.get_dataset(session_id, access_key)
    z_bytes = base64.b64decode(details['zip'])
    z = zipfile.ZipFile(io.BytesIO(z_bytes))
    z.extractall("./bill_data")

 

Converting the many JSON files to single CSV file#

The data isn't doing us much good sitting around as a zillion json files, so we'll convert them into a CSV file with the pieces of information we're interested in. Those pieces are:

  • State
  • Bill title
  • Bill URL
filenames = glob.glob("bill_data/*/*/bill/*.json")
len(filenames)
1253402
filenames[:5]
['bill_data/VT/2011-2012_Regular_Session/bill/HCR143.json',
 'bill_data/VT/2011-2012_Regular_Session/bill/H0291.json',
 'bill_data/VT/2011-2012_Regular_Session/bill/S0162.json',
 'bill_data/VT/2011-2012_Regular_Session/bill/S0027.json',
 'bill_data/VT/2011-2012_Regular_Session/bill/H0784.json']

If we want to process over a million rows, it's going to take a while! To speed things up we're going to turn to swifter, a package that can parallelize work on pandas dataframes. It's pretty easy to use:

without swifter:

df = pd.Series(filenames).apply(process_json)

with swifter:

df = pd.Series(filenames).swifter.apply(process_json)

And it does all the hard work for you! You just use it and hope for the best.

import json
import os
import swifter
import pandas as pd

def process_json(filename):
    with open(filename) as file:
        bill_data = {}
        # We need to do a little string replacing so the 
        json_str = file.read().replace('"0000-00-00"', 'null')
        content = json.loads(json_str)['bill']

        bill_data['bill_id'] = content['bill_id']
        bill_data['code'] = os.path.splitext(os.path.basename(filename))[0]
        bill_data['bill_number'] = content['bill_number']
        bill_data['title'] = content['title']
        bill_data['description'] = content['description']
        bill_data['state'] = content['state']
        bill_data['session'] = content['session']['session_name']
        bill_data['filename'] = filename
        bill_data['status'] = content['status']
        bill_data['status_date'] = content['status_date']

        try:
            bill_data['url'] = content['texts'][-1]['state_link']
        except:
            pass

        return pd.Series(bill_data)

df = pd.Series(filenames).swifter.apply(process_json)
df.head()

bill_id code bill_number title description state session filename status status_date url
0 325258 HCR143 HCR143 House Concurrent Resolution Congratulating The... House Concurrent Resolution Congratulating The... VT 2011-2012 Session bill_data/VT/2011-2012_Regular_Session/bill/HC... 4 2011-04-22 http://www.leg.state.vt.us/docs/2012/Acts/ACTR...
1 285625 H0291 H0291 An Act Relating To Raising The Penalties For A... An Act Relating To Raising The Penalties For A... VT 2011-2012 Session bill_data/VT/2011-2012_Regular_Session/bill/H0... 1 2011-02-22 http://www.leg.state.vt.us/docs/2012/bills/Int...
2 398232 S0162 S0162 An Act Relating To Powers Of Attorney An Act Relating To Powers Of Attorney VT 2011-2012 Session bill_data/VT/2011-2012_Regular_Session/bill/S0... 1 2012-01-03 http://www.leg.state.vt.us/docs/2012/bills/Int...
3 243054 S0027 S0027 An Act Relating To The Role Of Municipalities ... An Act Relating To The Role Of Municipalities ... VT 2011-2012 Session bill_data/VT/2011-2012_Regular_Session/bill/S0... 1 2011-01-25 http://www.leg.state.vt.us/docs/2012/bills/Int...
4 417691 H0784 H0784 An Act Relating To Approval Of The Adoption An... An Act Relating To Approval Of The Adoption An... VT 2011-2012 Session bill_data/VT/2011-2012_Regular_Session/bill/H0... 4 2012-05-05 http://www.leg.state.vt.us/docs/2012/Acts/ACTM...

And now we'll save it to prepare for the next step: inserting it into a database.

df.to_csv("data/bills-with-urls.csv", index=False)