You seem to be using dynamic binding which means that
str would be evaluated once your lambda function is executed at which time the variable
str is no longer in scope.
You should turn on lexical binding to have your hook function converted into a closure during the invocation of
my-eww-url so that once your hook function will be invoked
str will be bound to the same variable it was when
my-eww-url was invoked. You can turn on lexical binding by putting
;;; -*- lexical-binding: t; -*- in the first line of your file.
Note that with lexical binding your approach for removing the hook again in
my-eww-searh-readable will no longer work as the closure created in
my-eww-searh-readable will differ from the one previously created in
my-eww-url. In your situation using
(remove-hook 'eww-after-render-hook (first eww-after-render-hook)) instead should suffice.
If for some reason you cannot or do not want to use lexical binding you can have the variable
str evaluated when adding (and removing) the hook function by using backquotes with commas as follows:
(defun my-eww-searh-readable (str)
"Once-off call to `my-eww-searh-readable' after EWW is done rendering."
(remove-hook 'eww-after-render-hook `(lambda () (my-eww-searh-readable ,str)))))
(defun my-eww-url (url str)
"Open URL in `eww' with `eww-readable' enabled and search str."
(add-hook 'eww-after-render-hook `(lambda () (my-eww-searh-readable ,str)))
For more background also refer to (elisp)Variable Scoping and to the answer to
Scope in lambda.