From 76deffaae53da3a734798b943fc60dcdf981dabf Mon Sep 17 00:00:00 2001 From: Nathaniel Fruchter Date: Sat, 25 Feb 2017 15:00:22 -0500 Subject: [PATCH 1/5] Add requests to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8f08ae9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests>=2.5.1 From 6e32048bf34ebf73b5e168291ce15f20c2520ecf Mon Sep 17 00:00:00 2001 From: Nathaniel Fruchter Date: Sat, 25 Feb 2017 15:00:33 -0500 Subject: [PATCH 2/5] Update documentation to reflect new class structure --- .gitignore | 1 + README.md | 27 ++++++++++++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/README.md b/README.md index 956f933..e8d3263 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ python >= 2.4 simplejson >= 1.8 (not required with python 2.6, will use built in json module) +requests >= 2.5.0 ##Installation @@ -34,12 +35,12 @@ register for one.) Import modules: ``` - >>> from crpapi import CRP, CRPApiError + >>> import crpapi ``` And set your API key: ``` - >>> CRP.apikey = 'yr-api-key' + >>> CRP = crpapi.CRPApi("your-api-key") ``` See below for specific method usage. Full documentation of the methods is located here: https://www.opensecrets.org/resources/create/api_doc.php @@ -51,12 +52,12 @@ See below for specific method usage. Full documentation of the methods is locate #####getLegislators ``` ->>> print CRP.getLegislators.get(id='NJ04') +>>> print CRP.getLegislators(id='NJ04') [{u'@attributes': {u'website': u'http://chrissmith.house.gov', u'fax': u'202-225-7768', u'birthdate': u'1953-03-04', u'office': u'NJ04', u'cid': u'N00009816', u'twitter_id': u'', u'lastname': u'SMITH', u'feccandid': u'H8NJ04014', u'webform': u'http://chrissmith.house.gov/zipauth.html', u'exit_code': u'0', u'comments':u'',u'firstlast': u'Chris Smith', u'phone': u'202-225-3765', u'facebook_id': u'', u'first_elected': u'1980', u'congress_office': u'2373 Rayburn HouseOffice Building', u'gender': u'M', u'party': u'R', u'youtube_url': u'http://youtube.com/USRepChrisSmith', u'bioguide_id': u'S000522', u'votesmart_id':u'26952'}}, {u'@attributes': {u'website': u'http://menendez.senate.gov', u'fax': u'202-228-2197',u'birthdate': u'1954-01-01', u'office': u'NJS1',u'cid': u'N00000699', u'twitter_id': u'SenatorMenendez', u'lastname': u'MENENDEZ', u'feccandid': u'H2NJ13075',u'webform': uhttp://menendez.senate.gov/contact', u'exit_code': u'0', u'comments': u'', u'firstlast': u'Robert Menendez', u'phone': u'202-224-4744', u'facebook_id': u'senatormenendez', u'first_elected': u'2006',u'congress_office': u'528Hart Senate Office Building', u'gender': u'M', u'party': u'D', u'youtube_url': u'http://youtube.com/SenatorMenendezNJ',u'bioguide_id': u'M000639', u'votesmart_id': u'26961'}}, {u'@attributes': {u'website': u'http://www.lautenberg.senate.gov', u'fax': u'202-228-4054', u'birthdate':u'1924-01-23', u'office': u'NJS2', u'cid': u'N00000659', u'twitter_id': u'franklautenberg', u'lastname': u'LAUTENBERG', u'feccandid': u'S2NJ00080',u'webform': u'http://www.lautenberg.senate.gov/contact/routing.cfm', u'exit_code': u'1', u'comments': u'Died on June 3, 2013', u'firstlast': u'FrankLautenberg', u'phone': u'202-224-3224', u'facebook_id': u'franklautenberg', u'first_elected': u'2002', u'congress_office': u'324 Hart Senate Office Building',u'gender': u'M', u'party': u'D', u'youtube_url': u'http://youtube.com/franklautenberg', u'bioguide_id': u'L000123', u'votesmart_id': u'53324'}},{u'@attributes': {u'website': u'', u'fax': u'', u'birthdate': u'', u'office': u'NJS2', u'cid': u'N00035267', u'twitter_id': u'', u'lastname': u'BOOKER', u'feccandid': u'', u'webform': u'', u'exit_code': u'0', u'comments': u'Elected in special on 10/17/2013', u'firstlast': u'Cory Booker', u'phone': u'', u'facebook_id': u'', u'first_elected': u'2013', u'congress_office': u'', u'gender': u'M', u'party': u'D', u'youtube_url': u'', u'bioguide_id': u'', u'votesmart_id':u''}}] ``` #####memPFDprofile ``` ->>> print CRP.memPFDprofile.get(cid='N00007364',year='2010') +>>> print CRP.memPFDprofile(cid='N00007364',year='2010') {u'@attributes': {u'origin': u'Center for Responsive Politics', u'tx_low': u'1658021', u'asset_high': u'95707022', u'transaction_count': u'21', u'name': u'Feinstein,Dianne', u'update_timestamp': u'6/6/13', u'net_high': u'93707020', u'net_low': u'44386225', u'data_year': u'2010', u'source': u'http://www.opensecrets.org/pfds/CIDSummary.php?CID=N00007364&year=2010', u'tx_high': u'2620001', u'member_id': u'N00007364', u'positions_held_count': u'0',u'asset_low': u'46386227', u'asset_count': u'137'}, u'assets': {u'asset': [{u'@attributes': {u'sector': u'Misc Business', u'name': u'Carlton Hotel Properties',u'industry': u'Lodging/Tourism', u'holdings_low': u'5000001', u'subsidiary_of': u'', u'holdings_high': u'25000000'}}, {u'@attributes': {u'sector':u'Finance/Insur/RealEst', u'name': u'CB Richard Ellis', u'industry': u'Real Estate', u'holdings_low': u'3130012', u'subsidiary_of': u'CBRE Holding',u'holdings_high': u'5453001'}}, {u'@attributes': {u'sector': u'Finance/Insur/RealEst', u'name': u'Condominium/Princeville, Kauai-Hawaii', u'industry':u'RealEstate', u'holdings_low': u'1000001', u'subsidiary_of':u'', u'holdings_high': u'5000000'}}, {u'@attributes': {u'sector': u'Unknown', u'name':u'Dianne Feinstein 1991 Blind Trust', u'industry': u'Unknown', u'holdings_low': u'1000001', u'subsidiary_of': u'', u'holdings_high': u'5000000'}}, {u'@attributes': {u'sector': u'Other', u'name': u'Career Education Corp', u'industry': u'Education', u'holdings_low': u'2165010', u'subsidiary_of': u'', u'holdings_high': u'4551000'}}]}, u'transactions': {u'transaction': [{u'@attributes': {u'asset_name': u'JPMorgan Chase & Co', u'tx_date': u'Dec 3 2010',u'value_high': u'1000001', u'value_low': u'1000001', u'tx_action': u'Purchased'}}, {u'@attributes': {u'asset_name': u'Vanguard Life Strategy Income Fund',u'tx_date': u'Jul 15 2010', u'value_high': u'500000', u'value_low': u'250001', u'tx_action': u'Purchased'}}, {u'@attributes': {u'asset_name': u'Vanguard LifeStrategy Conservative Grw', u'tx_date': u'Jul 15 2010', u'value_high': u'500000', u'value_low': u'250001', u'tx_action': u'Purchased'}}, {u'@attributes':{u'asset_name': u'Franklin Small Mid Cap Growth Fund', u'tx_date': u'Aug 31 2010', u'value_high': u'50000', u'value_low': u'15001', u'tx_action':u'Sold'}}, {u'@attributes': {u'asset_name': u'JHT International Value', u'tx_date': u'Aug 27 2010', u'value_high': u'50000', u'value_low': u'15001',u'tx_action': u'Purchased'}}]}} ``` @@ -64,31 +65,31 @@ See below for specific method usage. Full documentation of the methods is locate #####candSummary ``` ->>> print CRP.candSummary.get(cid='N00007360',cycle='2014') +>>> print CRP.candSummary(cid='N00007360',cycle='2014') {u'origin': u'Center for Responsive Politics', u'next_election': u'2014', u'debt': u'0', u'last_updated': u'12/31/2013', u'cand_name': u'Pelosi, Nancy', u'cid': u'N00007360', u'spent': u'1304840.24', u'chamber': u'H', u'state': u'CA', u'first_elected': u'1987', u'source': u'http://www.opensecrets.org/politicians/summary.php?cid=N00007360&cycle=2014', u'party': u'D', u'total': u'1294719.87', u'cash_on_hand': u'439206.96', u'cycle':u'2014'} ``` #####candContrib: ``` ->>> print CRP.candContrib.get(cid='N00007360',cycle='2014') -{u'origin': u'Center for Responsive Politics', u'next_election': u'2014', u'debt': u'0', u'last_updated': u'12/31/2013', u'cand_name': u'Pelosi, Nancy', u'cid': u'N00007360', u'spent': u'1304840.24', u'chamber': u'H', u'state': u'CA', u'first_elected': u'1987', u'source': u'http://www.opensecrets.org/politicians/summary.php?cid=N00007360&cycle=2014', u'party': u'D', u'total': u'1294719.87', u'cash_on_hand': u'439206.96', u'cycle':u'2014'}>>> print CRP.candContrib.get(cid='N00007360',cycle='2014')[{u'@attributes': {u'org_name': u'Certain Software Inc', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Chartwell Hotels', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Jewish Community Federation', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Marcus & Millichap', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Stanford University', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Facebook Inc', u'total': u'10200'}}, {u'@attributes': {u'org_name': u'American Assn for Justice', u'total': u'10000'}},{u'@attributes': {u'org_name': u'American Health Care Assn', u'total': u'10000'}}, {u'@attributes': {u'org_name': u'Boeing Co', u'total': u'10000'}},{u'@attributes': {u'org_name': u'Francisco Partners', u'total': u'10000'}}] +>>> print CRP.candContrib(cid='N00007360',cycle='2014') +{u'origin': u'Center for Responsive Politics', u'next_election': u'2014', u'debt': u'0', u'last_updated': u'12/31/2013', u'cand_name': u'Pelosi, Nancy', u'cid': u'N00007360', u'spent': u'1304840.24', u'chamber': u'H', u'state': u'CA', u'first_elected': u'1987', u'source': u'http://www.opensecrets.org/politicians/summary.php?cid=N00007360&cycle=2014', u'party': u'D', u'total': u'1294719.87', u'cash_on_hand': u'439206.96', u'cycle':u'2014'}>>> print CRP.candContrib(cid='N00007360',cycle='2014')[{u'@attributes': {u'org_name': u'Certain Software Inc', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Chartwell Hotels', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Jewish Community Federation', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Marcus & Millichap', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Stanford University', u'total': u'10400'}}, {u'@attributes': {u'org_name': u'Facebook Inc', u'total': u'10200'}}, {u'@attributes': {u'org_name': u'American Assn for Justice', u'total': u'10000'}},{u'@attributes': {u'org_name': u'American Health Care Assn', u'total': u'10000'}}, {u'@attributes': {u'org_name': u'Boeing Co', u'total': u'10000'}},{u'@attributes': {u'org_name': u'Francisco Partners', u'total': u'10000'}}] ``` #####candIndustry: ``` ->>> print CRP.candIndustry.get(cid='N00007360',cycle='2014') +>>> print CRP.candIndustry(cid='N00007360',cycle='2014') [{u'@attributes': {u'total': u'74750', u'industry_code': u'H01', u'industry_name': u'Health Professionals', u'pacs': u'70500', u'indivs': u'4250'}}, {u'@attributes':{u'total': u'62500', u'industry_code': u'K01', u'industry_name': u'Lawyers/Law Firms', u'pacs': u'21500', u'indivs': u'41000'}}, {u'@attributes':{u'total': u'51200', u'industry_code': u'F10', u'industry_name': u'Real Estate', u'pacs': u'27500', u'indivs': u'23700'}}, {u'@attributes':{u'total':u'50600', u'industry_code': u'B12', u'industry_name': u'Computers/Internet', u'pacs': u'25000', u'indivs': u'25600'}}, {u'@attributes':{u'total': u'45000', u'industry_code': u'P01', u'industry_name': u'Building Trade Unions', u'pacs': u'45000', u'indivs':u'0'}}, {u'@attributes':{u'total': u'39250', u'industry_code': u'F07', u'industry_name': u'Securities & Investment', u'pacs': u'16000', u'indivs': u'23250'}},{u'@attributes': {u'total': u'39000', u'industry_code': u'H02', u'industry_name': u'Hospitals/Nursing Homes', u'pacs': u'35000', u'indivs': u'4000'}},{u'@attributes': {u'total': u'38000', u'industry_code': u'P04', u'industry_name': u'Public Sector Unions', u'pacs': u'38000', u'indivs': u'0'}},{u'@attributes': {u'total': u'37900', u'industry_code': u'B02', u'industry_name': u'TV/Movies/Music', u'pacs': u'14500', u'indivs': u'23400'}},{u'@attributes': {u'total': u'35800', u'industry_code': u'F13', u'industry_name': u'Misc Finance', u'pacs': u'0', u'indivs': u'35800'}}] ``` #####candIndByInd: ``` ->>> print CRP.candIndByInd.get(cid='N00007360',cycle='2014',ind='H01') +>>> print CRP.candIndByInd(cid='N00007360',cycle='2014',ind='H01') {u'origin': u'Center for Responsive Politics', u'last_updated': u'2/18/14', u'cand_name': u'Pelosi, Nancy', u'cid': u'N00007360', u'industry': u'Health Professionals', u'pacs': u'70500', u'rank': u'36', u'indivs': u'4250', u'chamber': u'H', u'state': u'California', u'source': uhttp://www.opensecrets.org/industries/recips.php?Ind=H01&cycle=2014&recipdetail=H&Mem=Y&sortorder=U', u'party': u'D', u'total': u'74750', u'cycle': u'2014'} ``` #####candSector: ``` ->>> print CRP.candSector.get(cid='N00007360',cycle='2014') +>>> print CRP.candSector(cid='N00007360',cycle='2014') [{u'@attributes': {u'total': u'11000', u'indivs': u'0', u'sectorid': u'A', u'pacs': u'11000', u'sector_name': u'Agribusiness'}}, {u'@attributes': {u'total': u'104900', u'indivs': u'59400', u'sectorid': u'B', u'pacs': u'45500', u'sector_name': u'Communic/Electronics'}}, {u'@attributes': {u'total': u'15800', u'indivs': u'9800', u'sectorid': u'C', u'pacs': u'6000', u'sector_name': u'Construction'}},{u'@attributes': {u'total': u'24000', u'indivs': u'0', u'sectorid': u'D', u'pacs':u'24000', u'sector_name': u'Defense'}}, {u'@attributes': {u'total': u'5500',u'indivs': u'0', u'sectorid': u'E', u'pacs': u'5500', u'sector_name': u'Energy/Nat Resource'}}, {u'@attributes': {u'total': u'154500', u'indivs': u'84000', u'sectorid': u'F', u'pacs': u'70500', u'sector_name':u'Finance/Insur/RealEst'}}, {u'@attributes': {u'total': u'126500', u'indivs': u'8500', u'sectorid': u'H', u'pacs': u'118000', u'sector_name':u'Health'}}, {u'@attributes': {u'total': u'73600', u'indivs': u'52100', u'sectorid': u'K', u'pacs': u'21500', u'sector_name': u'Lawyers &Lobbyists'}},{u'@attributes': {u'total': u'21000', u'indivs': u'0', u'sectorid': u'M', u'pacs': u'21000', u'sector_name': u'Transportation'}}, {u'@attributes':{u'total': u'82900', u'indivs': u'67400', u'sectorid': u'N', u'pacs': u'15500', u'sector_name': u'Misc Business'}}, {u'@attributes': {u'total': u'165500', u'indivs': u'0', u'sectorid': u'P', u'pacs': u'165500', u'sector_name': u'Labor'}}, {u'@attributes': {u'total': u'67030', u'indivs': u'36680', u'sectorid': u'Q', u'pacs': u'30350', u'sector_name': u'Ideology/Single-Issue'}}, {u'@attributes': {u'total': u'65850', u'indivs': u'63850', u'sectorid': u'W',u'pacs': u'2000', u'sector_name': u'Other'}}] ``` @@ -96,13 +97,13 @@ See below for specific method usage. Full documentation of the methods is locate #####getOrgs ``` ->>> print CRP.getOrgs.get(org='Goog') +>>> print CRP.getOrgs(org='Goog') [{u'@attributes': {u'orgname': u'Googasian Firm', u'orgid': u'D000051419'}}, {u'@attributes': {u'orgname': u'Google Inc', u'orgid': u'D000022008'}}] ``` #####orgSummary ``` ->>> print CRP.orgSummary.get(id='D000022008') +>>> print CRP.orgSummary(id='D000022008') {u'@attributes': {u'gave_to_party': u'394046', u'gave_to_pac': u'215000', u'pacs': u'381500', u'orgname': u'Google Inc', u'gave_to_cand': u'680409', u'source':u'www.opensecrets.org/orgs/summary.php?id=D000022008', u'repubs': u'481717', u'indivs': u'667655', u'lobbying': u'15800000', u'outside': u'0', u'orgid':u'D000022008', u'dems': u'715598', u'mems_invested': u'25', u'total': u'1424019', u'soft': u'220500', u'tot527': u'154364', u'gave_to_527': u'154364',u'cycle': u'2014'}} ``` @@ -110,6 +111,6 @@ See below for specific method usage. Full documentation of the methods is locate #####congCmteIndus ``` ->>> print CRP.congCmteIndus.get(indus='F10',cmte='HARM') +>>> print CRP.congCmteIndus(indus='F10',cmte='HARM') [{u'@attributes': {u'cid': u'N00024753', u'pacs': u'9500', u'indivs': u'81800',u'state': u'Colorado', u'member_name': u'Coffman, Mike', u'party': u'R', u'total':u'91300'}}, {u'@attributes': {u'cid': u'N00031244', u'pacs': u'12500', u'indivs': u'36300', u'state': u'Nevada', u'member_name': u'Heck, Joe', u'party': u'R', u'total': u'48800'}}, {u'@attributes': {u'cid': u'N00030962', u'pacs': u'4500', u'indivs': u'40150', u'state': u'Virginia', u'member_name': u'Rigell, Scott',u'party': u'R', u'total': u'44650'}}, {u'@attributes': {u'cid': u'N00025881', u'pacs': u'2000', u'indivs': u'41200', u'state': u'Hawaii', u'member_name': u'Hanabusa, Colleen', u'party': u'D', u'total': u'43200'}}, {u'@attributes': {u'cid':u'N00033591', u'pacs': u'6000', u'indivs': u'37000', u'state': u'California', u'member_name': u'Peters, Scott', u'party': u'D', u'total': u'43000'}}, {u'@attributes': {u'cid': u'N00031005', u'pacs': u'0', u'indivs': u'36050', u'state': u'Missouri', u'member_name': u'Hartzler, Vicky', u'party': u'R', u'total': u'36050'}}, {u'@attributes': {u'cid': u'N00033839', u'pacs': u'10000', u'indivs': u'22650', u'state': u'Texas', u'member_name': u'Veasey, Marc', u'party': u'D', u'total': u'32650'}}, {u'@attributes': {u'cid': u'N00004436', u'pacs': u'7000', u'indivs': u'24550', u'state': u'Minnesota', u'member_name': u'Kline, John', u'party': u'R', u'total': u'31550'}}, {u'@attributes': {u'cid': u'N00030768', u'pacs':u'3000', u'indivs': u'28250', u'state': u'Alabama', u'member_name': u'Roby, Martha', u'party': u'R', u'total': u'31250'}}, {u'@attributes': {u'cid':u'N00029026', u'pacs': u'2000', u'indivs': u'27500', u'state': u'Massachusetts', u'member_name': u'Tsongas, Niki', u'party': u'D', u'total': u'29500'}},{u'@attributes': {u'cid': u'N00032022', u'pacs': u'6500', u'indivs': u'20250', u'state': u'South Dakota', u'member_name': u'Noem, Kristi', u'party': u'R',u'total': u'26750'}}, {u'@attributes': {u'cid': u'N00013770', u'pacs': u'11500', u'indivs': u'13500', u'state': u'Pennsylvania', u'member_name': u'Shuster,Bill', u'party': u'R', u'total': u'25000'}}, {u'@attributes': {u'cid': u'N00008274', u'pacs': u'2000', u'indivs': u'21440', u'state': u'California',u'member_name': u'Sanchez, Loretta', u'party': u'D', u'total': u'23440'}}, {u'@attributes': {u'cid': u'N00013799', u'pacs': u'2000', u'indivs':u'19800', u'state': u'Virginia', u'member_name': u'Forbes, Randy', u'party': u'R', u'total': u'21800'}}, {u'@attributes': {u'cid': u'N00033981', u'pacs':u'4000', u'indivs': u'17750', u'state': u'Arizona', u'member_name': u'Barber, Ron', u'party': u'D', u'total': u'21750'}}, {u'@attributes': {u'cid':u'N00033310', u'pacs': u'10000', u'indivs': u'11350', u'state': u'Ohio', u'member_name': u'Wenstrup, Brad', u'party': u'R', u'total': u'21350'}}, {u'@attributes': {u'cid': u'N00027891', u'pacs': u'5000', u'indivs': u'16000', u'state': u'New York', u'member_name': u'Maffei, Dan', u'party': u'D', u'total':u'21000'}}, {u'@attributes': {u'cid': u'N00029679', u'pacs': u'1000', u'indivs': u'18350', u'state': u'Louisiana', u'member_name': u'Fleming, John',u'party': u'R', u'total': u'19350'}}, {u'@attributes': {u'cid': u'N00029649', u'pacs': u'1000', u'indivs': u'18220', u'state': u'California', u'member_name':u'Speier, Jackie', u'party': u'D', u'total': u'19220'}}, {u'@attributes': {u'cid': u'N00024759', u'pacs': u'8390', u'indivs': u'10750', u'state':u'Alabama', u'member_name': u'Rogers, Mike D', u'party': u'R', u'total': u'19140'}}, {u'@attributes': {u'cid': u'N00033316', u'pacs': u'6000', u'indivs':u'12934', u'state': u'Texas', u'member_name': u'Castro, Joaquin', u'party': u'D', u'total': u'18934'}}, {u'@attributes': {u'cid': u'N00003132', u'pacs':u'2000', u'indivs': u'16600', u'state': u'Tennessee', u'member_name': u'Cooper, Jim', u'party': u'D', u'total': u'18600'}}, {u'@attributes': {u'cid':u'N00025175', u'pacs': u'12000', u'indivs': u'6550', u'state': u'Ohio', u'member_name': u'Turner, Michael R', u'party': u'R', u'total': u'18550'}},{u'@attributes': {u'cid': u'N00029258', u'pacs': u'11000', u'indivs': u'7200', u'state': u'California', u'member_name': u'Hunter, Duncan D', u'party': u'R', u'total': u'18200'}}, {u'@attributes': {u'cid': u'N00034453', u'pacs': u'8000', u'indivs': u'9550', u'state': u'Washington', u'member_name': u'Kilmer, Derek',u'party': u'D', u'total': u'17550'}}, {u'@attributes': {u'cid': u'N00030856', u'pacs': u'2000', u'indivs': u'14885', u'state': u'California', u'member_name':u'Garamendi, John', u'party': u'D', u'total': u'16885'}}, {u'@attributes': {u'cid': u'N00034224', u'pacs': u'1000', u'indivs': u'14850', u'state':u'California', u'member_name': u'Cook, Paul', u'party': u'R', u'total': u'15850'}}, {u'@attributes': {u'cid': u'N00032457', u'pacs': u'4890', u'indivs':u'10350', u'state': u'Georgia', u'member_name': u'Scott, Austin', u'party': u'R', u'total': u'15240'}}, {u'@attributes': {u'cid': u'N00031226', u'pacs':u'7000', u'indivs': u'8200', u'state': u'Indiana', u'member_name': u'Walorski, Jackie', u'party': u'R', u'total': u'15200'}}, {u'@attributes': {u'cid':u'N00007833', u'pacs': u'3500', u'indivs': u'9150', u'state': u'Washington', u'member_name': u'Smith, Adam', u'party': u'D', u'total': u'12650'}},{u'@attributes': {u'cid': u'N00006052', u'pacs': u'2000', u'indivs': u'9950', u'state': u'Texas', u'member_name': u'Thornberry, Mac', u'party': u'R',u'total': u'11950'}}, {u'@attributes': {u'cid': u'N00026041', u'pacs': u'5000', u'indivs': u'6850', u'state': u'Texas', u'member_name':u'Conaway, Mike',u'party': u'R', u'total': u'11850'}}, {u'@attributes': {u'cid': u'N00033541', u'pacs': u'8000', u'indivs': u'3800', u'state': u'Texas', u'member_name':u'Gallego, Pete', u'party': u'D', u'total': u'11800'}}, {u'@attributes': {u'cid': u'N00031998', u'pacs': u'2000', u'indivs': u'9704', u'state': u'NewYork', u'member_name': u'Gibson, Chris', u'party': u'R', u'total': u'11704'}}, {u'@attributes': {u'cid': u'N00029459', u'pacs': u'3000', u'indivs': u'8500', u'state': u'Virginia', u'member_name': u'Wittman, Rob', u'party': u'R', u'total': u'11500'}}, {u'@attributes': {u'cid': u'N00002299', u'pacs': u'2000', u'indivs':u'9100', u'state': u'North Carolina', u'member_name': u'Jones, Walter B Jr', u'party': u'R', u'total': u'11100'}}, {u'@attributes': {u'cid': u'N00027860',u'pacs': u'5500', u'indivs': u'5500', u'state': u'Illinois', u'member_name': u'Duckworth, Tammy', u'party': u'D', u'total': u'11000'}}, {u'@attributes':{u'cid': u'N00002356', u'pacs': u'2000', u'indivs': u'8000', u'state': u'North Carolina', u'member_name': u'McIntyre, Mike', u'party': u'D',u'total':u'10000'}}, {u'@attributes': {u'cid': u'N00027741', u'pacs': u'2000', u'indivs': u'7100', u'state': u'Iowa', u'member_name': u'Loebsack, David',u'party': u'D', u'total': u'9100'}}, {u'@attributes': {u'cid': u'N00024842', u'pacs': u'2500', u'indivs': u'6500', u'state': u'Connecticut', u'member_name':u'Courtney, Joe', u'party': u'D', u'total': u'9000'}}, {u'@attributes': {u'cid': u'N00029513', u'pacs': u'3500', u'indivs': u'5250', u'state':u'Indiana', u'member_name': u'Carson, Andre', u'party':u'D', u'total': u'8750'}}, {u'@attributes': {u'cid': u'N00031988', u'pacs': u'2000', u'indivs':u'6600', u'state': u'New Jersey', u'member_name': u'Runyan, Jon', u'party': u'R', u'total': u'8600'}}, {u'@attributes': {u'cid': u'N00009724', u'pacs':u'4000', u'indivs': u'4050', u'state': u'Rhode Island', u'member_name':u'Langevin, Jim', u'party': u'D', u'total': u'8050'}}, {u'@attributes': {u'cid': u'N00028091', u'pacs': u'0', u'indivs': u'7800', u'state': u'New Hampshire', u'member_name': u'Shea-Porter, Carol', u'party': u'D', u'total': u'7800'}}, {u'@attributes': {u'cid': u'N00000851', u'pacs': u'2000', u'indivs': u'5250', u'state': u'New Jersey', u'member_name': u'LoBiondo, Frank A', u'party': u'R', u'total': u'7250'}}, {u'@attributes': {u'cid': u'N00024809', u'pacs': u'3000', u'indivs': u'4000', u'state': u'South Carolina', u'member_name': u'Wilson, Joe',u'party': u'R', u'total': u'7000'}}, {u'@attributes': {u'cid': u'N00034884', u'pacs': u'3000', u'indivs': u'2550', u'state': u'Illinois', u'member_name': u'Enyart, William',u'party': u'D', u'total': u'5550'}}, {u'@attributes': {u'cid': u'N00027848', u'pacs': u'5000', u'indivs': u'0', u'state': u'Georgia', u'member_name': u'Johnson, Hank', u'party': u'D', u'total': u'5000'}}, {u'@attributes': {u'cid': u'N00009604', u'pacs': u'1000', u'indivs': u'3500', u'state': u'California', u'member_name': u'Davis, Susan A', u'party': u'D', u'total': u'4500'}}, {u'@attributes': {u'cid': u'N00000826', u'pacs': u'3000', u'indivs': u'1500', u'state':u'New Jersey', u'member_name': u'Andrews, Robert E', u'party': u'D', u'total': u'4500'}}, {u'@attributes': {u'cid': u'N00001619', u'pacs': u'1000', u'indivs': u'3250', u'state': u'Pennsylvania', u'member_name': u'Brady, Robert A', u'party': u'D',u'total': u'4250'}}, {u'@attributes': {u'cid': u'N00013846', u'pacs': u'2000', u'indivs': u'2000', u'state': u'Florida', u'member_name': u'Miller, Jeff', u'party': u'R', u'total': u'4000'}}, {u'@attributes': {u'cid': u'N00006882', u'pacs':u'3500', u'indivs': u'0', u'state': u'California', u'member_name': u'McKeon, Buck', u'party': u'R', u'total': u'3500'}}, {u'@attributes': {u'cid':u'N00031958', u'pacs': u'2000', u'indivs': u'1250', u'state': u'Mississippi', u'member_name': u'Palazzo, Steven', u'party': u'R', u'total': u'3250'}},{u'@attributes': {u'cid': u'N00028133', u'pacs': u'2500', u'indivs': u'750', u'state': u'Colorado', u'member_name': u'Lamborn, Douglas L', u'party': u'R',u'total': u'3250'}}, {u'@attributes': {u'cid': u'N00033532', u'pacs': u'0', u'indivs': u'2300', u'state': u'Oklahoma', u'member_name': u'Bridenstine, James',u'party': u'R', u'total': u'2300'}}, {u'@attributes': {u'cid': u'N00030910', u'pacs': u'2000', u'indivs': u'0', u'state': u'Alabama', u'member_name':u'Brooks, Mo', u'party': u'R', u'total': u'2000'}}, {u'@attributes': {u'cid': u'N00025292', u'pacs': u'2000', u'indivs': u'0', u'state': u'Utah',u'member_name': u'Bishop, Rob', u'party': u'R', u'total': u'2000'}}, {u'@attributes': {u'cid': u'N00032441', u'pacs': u'1000', u'indivs': u'750', u'state':u'Florida', u'member_name': u'Nugent, Richard', u'party': u'R', u'total': u'1750'}}, {u'@attributes': {u'cid': u'N00024866', u'pacs': u'1000', u'indivs':u'500', u'state': u'Guam', u'member_name': u'Bordallo, Madeleine Z', u'party': u'D', u'total': u'1500'}}, {u'@attributes': {u'cid': u'N00006423', u'pacs':u'1000', u'indivs': u'0', u'state': u'Arizona', u'member_name': u'Franks, Trent', u'party': u'R', u'total': u'1000'}}, {u'@attributes': {u'cid': u'N00009759', u'pacs': u'1000', u'indivs': u'0', u'state': u'Washington', u'member_name': u'Larsen, Rick', u'party': u'D', u'total': u'1000'}}] ``` \ No newline at end of file From a2167b4da6e48fe358c1a039fecc3f159b2a5258 Mon Sep 17 00:00:00 2001 From: Nathaniel Fruchter Date: Sat, 25 Feb 2017 15:02:11 -0500 Subject: [PATCH 3/5] Use requests for API calls; structure class to not use staticmethod for calls * Use requests and requests.get() instead of urllib * Change to class constructors and __init__ to specify options and API key * Lets user specify output format (not just JSON / python dict) --- crpapi.py | 155 +++++++++++++++++++++++++++--------------------------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/crpapi.py b/crpapi.py index bc6963c..47eadbe 100644 --- a/crpapi.py +++ b/crpapi.py @@ -1,18 +1,18 @@ """ Python library for interacting with the CRP API. - The CRP API (http://www.opensecrets.org/action/api_doc.php) provides campaign + The CRP API (https://www.opensecrets.org/api) provides campaign finance and other data from the Center for Responsive Politics. - See README.rst for methods and usage + See README.md for methods and usage """ -__author__ = "James Turk (jturk@sunlightfoundation.com)" +__author__ = "James Turk (jturk@sunlightfoundation.com); forked by Nathaniel Fruchter (fruchter@mit.edu)" __version__ = "0.1.0" __copyright__ = "Copyright (c) 2009 Sunlight Labs" __license__ = "BSD" -import urllib, urllib2 +import requests, requests.exceptions try: import json except ImportError: @@ -28,82 +28,83 @@ def __init__(self, d): # namespaces # -class CRP(object): +class CRPApi(object): - apikey = None - - @staticmethod - def _apicall(func, params): - if CRP.apikey is None: - raise CRPApiError('Missing CRP apikey') + SUPPORTED_OUTPUTS = set(['json', 'xml', 'doc']) + + def __init__(self, apikey, output='json'): + self.apikey = apikey + + if output not in self.SUPPORTED_OUTPUTS: + raise ValueError("output must be one of %s" % self.SUPPORTED_OUTPUTS) + else: + self.output = output + + def _apicall(self, func, params): + """Do an API call against the OpenSecrets.org API. + + :func = API call + see :https://www.opensecrets.org/api/admin/index.php?function=user_api_list + :params = parameters passed to API function call + """ - url = 'http://api.opensecrets.org/?method=%s&output=json&apikey=%s&%s' % \ - (func, CRP.apikey, urllib.urlencode(params)) + baseURL = 'http://www.opensecrets.org/api/' + + # Set output format + apicall = { + 'method': func, + 'apikey': self.apikey, + 'output': self.output + } + apicall.update(params) try: - response = urllib2.urlopen(url).read() - return json.loads(response)['response'] - except urllib2.HTTPError, e: - raise CRPApiError(e.read()) - except (ValueError, KeyError), e: - raise CRPApiError('Invalid Response') - - class getLegislators(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('getLegislators', kwargs)['legislator'] - return results - - class memPFDprofile(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('memPFDprofile', kwargs)['member_profile'] - return results - - class candSummary(object): - @staticmethod - def get(**kwargs): - result = CRP._apicall('candSummary', kwargs)['summary'] - return result['@attributes'] - - class candContrib(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('candContrib', kwargs)['contributors']['contributor'] - return results - - class candIndustry(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('candIndustry', kwargs)['industries']['industry'] - return results - - class candSector(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('candSector', kwargs)['sectors']['sector'] - return results - - class candIndByInd(object): - @staticmethod - def get(**kwargs): - result = CRP._apicall('CandIndByInd', kwargs)['candIndus'] - return result['@attributes'] - - class getOrgs(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('getOrgs', kwargs)['organization'] - return results + response = requests.get(baseURL, params=apicall) + if self.output == 'json': + return json.loads(response.content)['response'] + else: + return output + except requests.exceptions.RequestException as e: + raise e + except (ValueError, KeyError) as e: + raise CRPApiError('Unable to parse invalid response from the API') + + def getLegislators(self, **kwargs): + results = self._apicall('getLegislators', kwargs)['legislator'] + return results + + def memPFDprofile(self, **kwargs): + results = self._apicall('memPFDprofile', kwargs)['member_profile'] + return results + + def candSummary(self, **kwargs): + result = self._apicall('candSummary', kwargs)['summary'] + return result['@attributes'] + + def candContrib(self, **kwargs): + results = self._apicall('candContrib', kwargs)['contributors']['contributor'] + return results + + def candIndustry(self, **kwargs): + results = self._apicall('candIndustry', kwargs)['industries']['industry'] + return results + + def candSector(self, **kwargs): + results = self._apicall('candSector', kwargs)['sectors']['sector'] + return results + + def candIndByInd(self, **kwargs): + result = self._apicall('CandIndByInd', kwargs)['candIndus'] + return result['@attributes'] + + def getOrgs(self, **kwargs): + results = self._apicall('getOrgs', kwargs)['organization'] + return results - class orgSummary(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('orgSummary', kwargs)['organization'] - return results + def orgSummary(self, **kwargs): + results = self._apicall('orgSummary', kwargs)['organization'] + return results - class congCmteIndus(object): - @staticmethod - def get(**kwargs): - results = CRP._apicall('congCmteIndus', kwargs)['committee']['member'] - return results \ No newline at end of file + def congCmteIndus(self, **kwargs): + results = self._apicall('congCmteIndus', kwargs)['committee']['member'] + return results \ No newline at end of file From 66138b95d6aeb5af599a3ea737d56913b96d2f1b Mon Sep 17 00:00:00 2001 From: Nathaniel Fruchter Date: Sat, 25 Feb 2017 15:10:05 -0500 Subject: [PATCH 4/5] Add new independentExpend API call --- crpapi.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crpapi.py b/crpapi.py index 47eadbe..b9f1dc0 100644 --- a/crpapi.py +++ b/crpapi.py @@ -107,4 +107,8 @@ def orgSummary(self, **kwargs): def congCmteIndus(self, **kwargs): results = self._apicall('congCmteIndus', kwargs)['committee']['member'] - return results \ No newline at end of file + return results + + def independentExpend(self, **kwargs): + results = self._apicall('independentExpend', kwargs) + return results From 15d7d10b2158223d6e38a3fc45f6dde961338531 Mon Sep 17 00:00:00 2001 From: Nathaniel Fruchter Date: Sat, 25 Feb 2017 15:22:38 -0500 Subject: [PATCH 5/5] Add API call docstrings --- crpapi.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/crpapi.py b/crpapi.py index b9f1dc0..2fd1bbd 100644 --- a/crpapi.py +++ b/crpapi.py @@ -70,45 +70,126 @@ def _apicall(self, func, params): raise CRPApiError('Unable to parse invalid response from the API') def getLegislators(self, **kwargs): + """ + Provides a list of Congressional legislators and associated attributes for + specified subset (state, district or specific CID). + + parameters + :value two character state code, or 4 character district or specific CID + + """ results = self._apicall('getLegislators', kwargs)['legislator'] return results def memPFDprofile(self, **kwargs): + """ + Returns PFD (financial disclosure) information for a member of Congress + + parameters + :cid CRP candidate ID + :year Disclosure year (starting 2013) + """ + results = self._apicall('memPFDprofile', kwargs)['member_profile'] return results - def candSummary(self, **kwargs): + def candSummary(self, **kwargs): + """ + Method to access summary data for a candidate + + parameters + :cid CRP candidate ID + :cycle Blank for current, or 2012, 2014, 2016. + + """ result = self._apicall('candSummary', kwargs)['summary'] return result['@attributes'] def candContrib(self, **kwargs): + """ + Returns top contributors to specified candidate for a House or Senate seat or member of Congress. + These are 6 year numbers for Senators/Senate candidates; 2 years for Representatives/House candidates + + parameters + :cid CRP candidate ID + :cycle Blank for current, or 2012, 2014, 2016. + + """ results = self._apicall('candContrib', kwargs)['contributors']['contributor'] return results def candIndustry(self, **kwargs): + """ + Returns data on a candidate's Industry contributions to specified candidate for a House or Senate seat or member of Congress. + These are 6 year numbers for Senators/Senate candidates; 2 years for Representatives/House candidates + + parameters + :cid CRP candidate ID + :cycle Blank for current, or 2012, 2014, 2016. + """ results = self._apicall('candIndustry', kwargs)['industries']['industry'] return results def candSector(self, **kwargs): + """ + Provides sector total of specified politician's receipts + + parameters + :cid CRP candidate ID + :cycle Blank for current, or 2012, 2014, 2016. + """ results = self._apicall('candSector', kwargs)['sectors']['sector'] return results def candIndByInd(self, **kwargs): + """ + provides total contributed to specified candidate from specified industry for specified cycle + + parameters + :cid CRP candidate ID + :cycle Blank for current, or 2012, 2014, 2016. + :ind 3 character industry code + """ result = self._apicall('CandIndByInd', kwargs)['candIndus'] return result['@attributes'] def getOrgs(self, **kwargs): + """ + Search information about organization(s) + + parameters + :org name or partial name of organization requested + """ results = self._apicall('getOrgs', kwargs)['organization'] return results def orgSummary(self, **kwargs): + """ + Summary of information about an organization + + parameters + :id A specific CRP orgid + """ results = self._apicall('orgSummary', kwargs)['organization'] return results def congCmteIndus(self, **kwargs): + """ + Provides summary fundraising information for a specific committee, industry and congress number + + parameters + :cmte Committee ID in CQ format + :congno Congress session number (112, 113, 114, or blank for latest) + :indus 3 character industry code + """ results = self._apicall('congCmteIndus', kwargs)['committee']['member'] return results def independentExpend(self, **kwargs): + """ + Return the 50 latest independent expenditures, updated daily. + + No parameters. + """ results = self._apicall('independentExpend', kwargs) return results