This will swap all Specular BSDf nodes to Principled BSDF nodes. However there the specular color parameter isn't available on the Principled BSDfBSDF so you may experience loss of data there.
import bpy
for mat in bpy.data.materials:
if not mat.use_nodes:
continue
nodes = mat.node_tree.nodes
specular = next((n for n in nodes if isinstance(n, bpy.types.ShaderNodeEeveeSpecular)), None)
output = next((n for n in nodes if isinstance(n, bpy.types.ShaderNodeOutputMaterial)), None)
if specular is None or output is None:
continue
principled = nodes.new("ShaderNodeBsdfPrincipled")
principled.inputs[0].default_value = specular.inputs[0].default_value # Color
principled.inputs[9].default_value = specular.inputs[2].default_value # Roughness
principled.inputs[19].default_value = specular.inputs[3].default_value # Emission color
principled.inputs[21].default_value = 1 - specular.inputs[4].default_value # Alpha
principled.inputs[14].default_value = specular.inputs[6].default_value # Clearcoat
principled.inputs[15].default_value = specular.inputs[7].default_value # Clearcoat roughness
principled.location = (specular.location[0] - 100, specular.location[1])
mat.node_tree.links.new(principled.outputs[0], output.inputs[0])
nodes.remove(specular)