The best solution I've ever come to that didn't negatively impact my clients was generating a UUID on the server via an ajax call 100ms after page load. That UUID was stored in a cookie, and returned via AJAX and stuck it in a hidden field on the form. Server checks cookie != null and cookie == hidden field, and returned a 200 OK regardless of if it failed (used the response text for success or failure indication), a…
These days you could just throw together a selenium script and call it a day.
This kind of stuff is fine for stopping comment spam because there are so many other opportunities out there that the spammers move on to an easier target. If you need to protect against a targeted attack then it’s a lot more difficult.