def generate_report(data):

    """ Process the property data from the web page, build summary dictionary containing:

     * 'property_name' - Name of property
     * 'property_type' - Type of property e.g. 'Apartment'
     * 'room_type' - Type or number of bedrooms
     * 'room_number' - Number of bedrooms
     * 'bathrooms' - Number of bathrooms
     * 'general_amenities' - List of general amenities
     * 'family_amenities' - List of family amenities
     * 'safety_feats' - List of safety amenities

    :param data: dict
        Web page data, derived from 'bootstrapData' JSON string
    :return: dict
        Summarised property information (see above)
    """

    listing = data['bootstrapData']['listing']

    # Initialise summary data dictionary. Some values have been assigned default values of 'Not found'
    # in the event that the data is not present in the web page data

    summary_data = {
        'property_name': listing['name'],
        'property_type': 'Not found',
        'rooms': 'Not found',
        'bathrooms': 'Not found',
        'general_amenities': [],
        'family_amenities': [],
        'safety_feats': []
    }

    # Iterate through 'Space' section to build room details

    for detail in listing['space_interface']:

        if detail.get('label') == 'Property type:' and detail['value']:
            summary_data['property_type'] = detail['value']

        if detail.get('label') == 'Bedrooms:' and detail['value']:
            summary_data['rooms'] = detail['value']

        if detail.get('label') == 'Bathrooms:' and detail['value']:
            summary_data['bathrooms'] = detail['value']

    # Iterate through amenities to build list of amenities grouped by category

    for amenity in listing['listing_amenities']:
        if amenity['is_present']:

            if amenity['category'] == 'family':
                summary_data['family_amenities'].append(amenity['name'])

            elif amenity['category'] == 'general' and amenity['is_safety_feature']:
                summary_data['safety_feats'].append(amenity['name'])

            else:
                summary_data['general_amenities'].append(amenity['name'])

    return summary_data