Once I was inspired by @ThomasG77's idea, so now I am suggesting another approach using the QGIS's domestic class QgsNominatimGeocoder with Nominatim geocoder under the hood. It is an open-source solution, otherwise one can use the QgsGoogleMapsGeocoder class, where an apiKey must be specified.
I see several advantages over a nice solution from @Matt: (1) no need to install/use not built-in Python packages e.g. requests (however, it is included in QGIS) (2) no need to deal with proxies and certificates, in requests package it is usually needed by setting verify and proxies parameters (3) no need "to play" with the url. Perhaps there is one disadvantage: this solution is only suitable for QGIS 3.18 and later versions.
Let's assume there is a point layer called 'random_points_test' with its attribute table, see image below.

Proceed with Plugins > Python Console > Show Editor (see documentation) and paste the script below
# imports
from statistics import mean
from qgis.core import (
QgsNominatimGeocoder,
QgsGeocoderContext,
QgsCoordinateTransformContext,
)
def geoms_to_coords(geoms: list) -> str:
"""
Convert a list with geometries into a string with a single coordinates pair.
Parameters:
==========
:param geoms: a list with geometries of 'QgsGeometry: Point (X Y)' type
Returns:
==========
:return: a string with YX-coordinates
"""
# convert a list with geometries into a list with sets of x,y coordinates
geoms_coordinates = [(geom.asPoint().x(), geom.asPoint().y()) for geom in geoms]
# get a mean value of all x and y inside a set
x_avg, y_avg = [mean(coords) for coords in zip(*geoms_coordinates)]
# represent mean x and y as a string with 6 digits after comma
coords = f"{format(y_avg, '.6f')}, {format(x_avg, '.6f')}"
return coords
def geocoding_the_address(address: str, country: str) -> str:
"""
Geocode an address into coordinates with Nominatim Geocoder.
Parameters:
==========
:param address: an address to geocode
:param country: a code of a country
Returns:
==========
:return: a string with coordinates or 'No result'
"""
# call the Nominatim Geocoder with a country code parameter
geocoder = QgsNominatimGeocoder(countryCodes=country)
# call the context to encapsulate the context of a geocoding operation
context = QgsGeocoderContext(QgsCoordinateTransformContext())
# set a method for geocoding a string with an address
output = geocoder.geocodeString(address, context)
# check if the output of geocoding is not empty,
# otherwise output 'No result'
if len(output):
# a list with geometries of each valid output
output_geoms = [out.geometry() for out in output if out.isValid()]
# achieve a single coordinate pair
output_coords = geoms_to_coords(output_geoms)
return output_coords
else:
return "No result"
def address_to_coords(
layer_name: str, input_field: str, output_field: str, country: str = None
):
"""
Geocode a field with an address into a field string with coordinates of the address.
Parameters:
==========
:param layer_name: the name of a layer
:param input_field: the input field with an address
:param output_field: the output field for coordinates
:param (optional) country: to restrict results to one or more countries.
It must be in ISO 3166-1alpha2 code and comma-separated.
"""
# get layer by name
layer = QgsProject.instance().mapLayersByName(layer_name)[0]
# get all fields of the layer
fields = layer.fields()
# get names of all fields of the layer
fields_names = layer.fields().names()
# check if the input field is in all fields of the layer
if input_field in fields_names:
# get index of the input field
idx_in = fields.indexFromName(input_field)
layer.startEditing()
# check if the output field already exists,
# otherwise create it (of a string type)
if not output_field in fields_names:
new_field = QgsField(output_field, QVariant.String)
layer.dataProvider().addAttributes([new_field])
layer.updateFields()
for feature in layer.getFeatures():
# get address value of the input field for each feature
address = feature.attribute(idx_in)
# check if the address value exists
if address:
# appropriate the output field with a new value
feature[output_field] = geocoding_the_address(address, country)
else:
# appropriate the output field with 'No result'
feature[output_field] = "No result"
layer.updateFeature(feature)
layer.commitChanges()
print('Done!')
executing the function
address_to_coords('random_points_test', "address", "WSP_X_Y", 'pl')
In the code above, please do not forget to apply several changes in the last line: address_to_coords('random_points_test', "address", "WSP_X_Y", 'pl') before running it.
Press Run script
and get the output that will look like:

References: