LET’S FIX STUFF AND BUILD THINGS. MISTAKES ARE OK.
If your site configuration allows anonymous signup, you can use Views Bulk Operations to remove spam users. Optionally, Rules can automate the process.
Create a views page displaying users, table format. Some useful fields are Username (spam users often have predictable kinds of usernames), Created Date, and Last Access.
Add a VBO field with operation: “Delete User”. You can select enqueue to run this on cron, or leave it unchecked to delete users manually using the view page.
Filter the view to select spam users specifically. Some possible filters are:
Has never logged in (last access == “never”)
Roles == “empty” (i.e. definitely not an admin)
You can add an account age criteria if you’re cleaning up old users, e.g.:
Created date older than ___ (e.g. several months)
You can use exposed filters to search by access dates or account age.
Now you can visit this views page at intervals to delete old and unwanted users.
If you’re comfortable with the results and want to automate this, you can use Rules to execute the deletion on cron runs. Create a rule (for running on every cron run) or a component (to schedule the run intermittently).
Rule condition: “Cron maintenance tasks are performed.”
Action: “Load a user list with Views”; select your VBO view page.
Loop through results and delete each user returned by the view (“delete entity”)
If you're using a component, add a “reschedule” action to the component itself (say, for the following week) and run the component once or schedule the first run.
If you're not sure you won't catch genuine accounts in the views list, you can just visit the view periodically, set the pager count as high as you are wiling to scan through and delete all at once, and select all items on the page, then uncheck the box next to users you don't want to delete.