import requests from neo4j import GraphDatabase from dotenv import load_dotenv import os # Load environment variables from .env file load_dotenv() # Retrieve API key and Neo4j connection details from environment variables CONGRESS_API_KEY = os.getenv('CONGRESS_API_KEY') if not CONGRESS_API_KEY: raise ValueError("API key not found in .env file") NEO4J_URI = os.getenv('NEO4J_URI') NEO4J_USER = os.getenv('NEO4J_USER') NEO4J_PASSWORD = os.getenv('NEO4J_PASSWORD') if not NEO4J_URI or not NEO4J_USER or not NEO4J_PASSWORD: raise ValueError("Neo4j connection details not found in .env file") BASE_URL_MEMBERSHIP = 'https://api.congress.gov/v3/member' BASE_URL_COSPONSORED_LEGISLATION = 'https://api.congress.gov/v3/member/{}/cosponsored-legislation' # Function to get all person nodes with bioguideId from Neo4j def get_person_nodes(driver): with driver.session() as session: result = session.run("MATCH (p:Person) RETURN p.bioguideId") return [record['p.bioguideId'] for record in result] # Function to fetch cosponsored legislation for a given bioguideId def fetch_cosponsored_legislation(bioguideId, api_key): url = BASE_URL_COSPONSORED_LEGISLATION.format(bioguideId) params = { 'api_key': api_key, 'limit': 250 # Maximum limit allowed is 250 } response = requests.get(url, params=params) if response.status_code == 200: return response.json().get('legislations', []) else: print(f"Failed to retrieve cosponsored legislation for {bioguideId}: {response.status_code}") return [] # Function to create or update a person node in Neo4j using MERGE def merge_person_node(driver, bioguideId): with driver.session() as session: query = """ MERGE (p:Person {bioguideId: $bioguideId}) RETURN p.bioguideId """ result = session.run(query, bioguideId=bioguideId) return result.single()[0] # Function to create a legislation node in Neo4j and return its label def create_legislation_node(driver, legislation): with driver.session() as session: number = legislation.get('number') properties = {str(key): value for key, value in legislation.items() if value is not None and value != ""} query = f""" MERGE (l:Legislation {{id: $id}}) SET l += $properties RETURN labels(l) """ result = session.run(query, id=legislation.get('id'), properties=properties) return result.single()[0] # Function to create a cosponsored relationship between a person and legislation node in Neo4j def create_cosponsored_relationship(driver, bioguideId, number): with driver.session() as session: query = """ MATCH (p:Person {bioguideId: $bioguideId}) MATCH (l) WHERE id(l) IN [id(n) WHERE n:Legislation AND n.id = $number] MERGE (p)-[:COSPONSORED]->(l) """ session.run(query, bioguideId=bioguideId, number=legislation.get('id')) # Function to process each person node and fetch cosponsored legislation def process_person_nodes(driver): person_nodes = get_person_nodes(driver) for bioguideId in person_nodes: print(f"Processing member with bioguideId: {bioguideId}") # Ensure the person node exists in Neo4j merge_person_node(driver, bioguideId) # Fetch cosponsored legislation legislations = fetch_cosponsored_legislation(bioguideId, CONGRESS_API_KEY) for legislation in legislations: print(f"Processing legislation: {legislation.get('number')}") # Create or update the legislation node create_legislation_node(driver, legislation) # Create a cosponsored relationship from the person to the legislation create_cosponsored_relationship(driver, bioguideId, legislation) # Main execution block if __name__ == "__main__": driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) try: process_person_nodes(driver) finally: driver.close()