Search code examples
pythonsqlitebeautifulsoupgeopy

Unbound local error does not occur consistently


I am trying to add data to my SQlite3 table which runs on a function that takes two arguments to find a city and a neighbourhood def scrapecafes(city, area) Strangely, this works well with some of the arguments I am entering but not with others. For example if I run scrapecafes(melbourne, thornbury) the code works fine, but if I run scrapecafes(melbourne, carlton I get the following error: UnboundLocalError: local variable 'lat' referenced before assignment

I know the function definitely works, but I can't figure out why I am getting the UnboundLocalError for some arguments but not for others. Here is the code:

import folium
from bs4 import BeautifulSoup
import requests
from requests import get
import sqlite3
import geopandas
import geopy
from geopy.geocoders import Nominatim
from geopy.extra.rate_limiter import RateLimiter

#cafeNames
def scrapecafes(city, area):

    #url = 'https://www.broadsheet.com.au/melbourne/guides/best-cafes-thornbury' #go to the website
    url = f"https://www.broadsheet.com.au/{city}/guides/best-cafes-{area}"
    response = requests.get(url, timeout=5)

    soup_cafe_names = BeautifulSoup(response.content, "html.parser")
    type(soup_cafe_names)

    cafeNames = soup_cafe_names.findAll('h2', attrs={"class":"venue-title", }) #scrape the elements
    cafeNamesClean = [cafe.text.strip() for cafe in cafeNames] #clean the elements
    #cafeNameTuple = [(cafe,) for cafe in cafeNamesCleans

    #print(cafeNamesClean)

    #addresses
    soup_cafe_addresses = BeautifulSoup(response.content, "html.parser")
    type(soup_cafe_addresses)

    cafeAddresses = soup_cafe_addresses.findAll( attrs={"class":"address-content" })
    cafeAddressesClean = [address.text for address in cafeAddresses]
    #cafeAddressesTuple = [(address,) for address in cafeAddressesClean]

    #print(cafeAddressesClean)

    ##geocode addresses
    locator = Nominatim(user_agent="myGeocoder")
    geocode = RateLimiter(locator.geocode, min_delay_seconds=1)

    try:
        location = []
        for item in cafeAddressesClean:
            location.append(locator.geocode(item))

            lat = [loc.latitude for loc in location]
            long = [loc.longitude for loc in location]
    except:
        pass


    #zip up for table
    fortable = list(zip(cafeNamesClean, cafeAddressesClean, lat, long))
    print(fortable)
    
##connect to database
    try:
        sqliteConnection = sqlite3.connect('25july_database.db')
        cursor = sqliteConnection.cursor()
        print("Database created and Successfully Connected to 25july_database")

        sqlite_select_Query = "select sqlite_version();"
        cursor.execute(sqlite_select_Query)
        record = cursor.fetchall()
        print("SQLite Database Version is: ", record)
        cursor.close()

    except sqlite3.Error as error:
        print("Error while connecting to sqlite", error)

    #create table
    try:
        sqlite_create_table_query = ''' CREATE TABLE IF NOT EXISTS test555 (
                                        name TEXT NOT NULL,
                                        address TEXT NOT NULL,
                                        latitude FLOAT NOT NULL,
                                        longitude FLOAT NOT NULL
                                        );'''

        cursor = sqliteConnection.cursor()
        print("Successfully Connected to SQLite")
        cursor.execute(sqlite_create_table_query)
        sqliteConnection.commit()
        print("SQLite table created")

    except sqlite3.Error as error:
        print("Error while creating a sqlite table", error)

##enter data into table
    try:
        sqlite_insert_name_param = """INSERT INTO test555
                            (name, address, latitude, longitude)
                            VALUES (?,?,?,?);"""

        cursor.executemany(sqlite_insert_name_param, fortable)

        sqliteConnection.commit()
        print("Total", cursor.rowcount, "Records inserted successfully into table")
        sqliteConnection.commit()

        cursor.close()

    except sqlite3.Error as error:
        print("Failed to insert data into sqlite table", error)

    finally:
        if (sqliteConnection):
            sqliteConnection.close()
            print("The SQLite connection is closed")

Solution

  • The problem is geopy doesn't have co-ordinates for Carlton. Hence, you should change your table schema and insert null in those cases.

    When geopy doesn't have data, it returns None and when try to call something on None it throws exception. You have to put the try/except block inside the for loop.

    from bs4 import BeautifulSoup
    import requests
    from requests import get
    import sqlite3
    import geopandas
    import geopy
    from geopy.geocoders import Nominatim
    from geopy.extra.rate_limiter import RateLimiter
    
    #cafeNames
    def scrapecafes(city, area):
    
        #url = 'https://www.broadsheet.com.au/melbourne/guides/best-cafes-thornbury' #go to the website
        url = f"https://www.broadsheet.com.au/{city}/guides/best-cafes-{area}"
        response = requests.get(url, timeout=5)
    
        soup_cafe_names = BeautifulSoup(response.content, "html.parser")
    
        cafeNames = soup_cafe_names.findAll('h2', attrs={"class":"venue-title", }) #scrape the elements
        cafeNamesClean = [cafe.text.strip() for cafe in cafeNames] #clean the elements
        #cafeNameTuple = [(cafe,) for cafe in cafeNamesCleans
    
        #addresses
        soup_cafe_addresses = BeautifulSoup(response.content, "html.parser")
    
        cafeAddresses = soup_cafe_addresses.findAll( attrs={"class":"address-content" })
        cafeAddressesClean = [address.text for address in cafeAddresses]
        #cafeAddressesTuple = [(address,) for address in cafeAddressesClean]
    
        ##geocode addresses
        locator = Nominatim(user_agent="myGeocoder")
        geocode = RateLimiter(locator.geocode, min_delay_seconds=1)
        lat = []
        long = []
        
        for item in cafeAddressesClean:
            try:
                location = locator.geocode(item.strip().replace(',',''))
                lat.append(location.latitude)
                long.append(location.longitude)
            except:
                lat.append(None)
                long.append(None)
    
        #zip up for table
        fortable = list(zip(cafeNamesClean, cafeAddressesClean, lat, long))
        print(fortable)
        
    ##connect to database
        try:
            sqliteConnection = sqlite3.connect('25july_database.db')
            cursor = sqliteConnection.cursor()
            print("Database created and Successfully Connected to 25july_database")
    
            sqlite_select_Query = "select sqlite_version();"
            cursor.execute(sqlite_select_Query)
            record = cursor.fetchall()
            print("SQLite Database Version is: ", record)
            cursor.close()
    
        except sqlite3.Error as error:
            print("Error while connecting to sqlite", error)
    
        #create table
        try:
            sqlite_create_table_query = ''' CREATE TABLE IF NOT EXISTS test (
                                            name TEXT NOT NULL,
                                            address TEXT NOT NULL,
                                            latitude FLOAT,
                                            longitude FLOAT
                                            );'''
    
            cursor = sqliteConnection.cursor()
            print("Successfully Connected to SQLite")
            cursor.execute(sqlite_create_table_query)
            sqliteConnection.commit()
            print("SQLite table created")
    
        except sqlite3.Error as error:
            print("Error while creating a sqlite table", error)
    
    ##enter data into table
        try:
            sqlite_insert_name_param = """INSERT INTO test
                                (name, address, latitude, longitude)
                                VALUES (?,?,?,?);"""
    
            cursor.executemany(sqlite_insert_name_param, fortable)
    
            sqliteConnection.commit()
            print("Total", cursor.rowcount, "Records inserted successfully into table")
            sqliteConnection.commit()
    
            cursor.close()
    
        except sqlite3.Error as error:
            print("Failed to insert data into sqlite table", error)
    
        finally:
            if (sqliteConnection):
                sqliteConnection.close()
                print("The SQLite connection is closed")
    
    scrapecafes('melbourne', 'carlton')