Googleの検索結果をpecoりたい「Google Fuzzy Search」を作った
はじめに
peco, percol, fzf, skimとかいろんなfuzzy find
ツールがある中、 googleの検索結果だけfuzzy find
するツールがなかったので作ってみました。
Google Fuzzy Search とは
とってもシンプルなツールで 「標準入力から受けたjsonをインクリメンタルサーチして、選択したアイテムをブラウザで開くためのツールです。jsonはgooglerで用意したものを使います。」
百聞は一見にしかずということで動いているものをご覧ください。(拡大してご覧ください。)
実行しているコマンドはこれです。
cat fixtures/tokyo.json | gfzs
fixtures/tokyo.json
に 東京
をキーワードにgooglerで調べたものを保存しておいて、それを標準入力として渡して使ってます。 QUERY>
となっている部分に絞りたい単語 コロナ
を入れて検索結果を絞り、Enter
を押してブラウザで開いている様子です。
実際、使ってみたくなったでしょうか?
仮想環境でデモを試す
まずはトライアル!
仮想環境を作ることで、ローカルの環境を汚さずに試すことができます。
以下のコマンドを順番に入力して下さい。
python3 -m venv .venv
source .venv/bin/activate
pip install gfzs
# or
pipx install gfzs
gfzs init
gfzs demo
こんな風に表示されたら正しく動いてます。
閉じるときは、Ctrl-C
で閉じます。
気にったら pip install gfzs
or pipx install gfzs
で入れて使って貰えると幸いです。
googlerを使った例
googlerを使った例を試すには1つお約束事項があります。
googlerでは検索結果をデフォルトで10件までしか取得できませんが、オプションを渡す事で一応100件とか取得できるように作られています。
だがしかし...
これは動作確認の時、私がやらかしてしまった時のgooglerのレスポンスをご覧ください。
$ googler --json -n 1000 東京
[ERROR] Connection blocked due to unusual activity. THIS IS NOT A BUG, please do NOT report it as a bug unless you have specific information that may lead to the development of a workaround. You IP address is temporarily or permanently blocked by Google and requires reCAPTCHA-solving to use the service, which googler is not capable of. Possible causes include issuing too many queries in a short time frame, or operating from a shared / low reputation IP with a history of abuse. Please do NOT use googler for automated scraping.
[エラー]異常なアクティビティが原因で接続がブロックされました。これはバグではありません。回避策の開発につながる可能性のある特定の情報がない限り、バグとして報告しないでください。お客様のIPアドレスはGoogleによって一時的または永続的にブロックされており、サービスを使用するにはreCAPTCHAを解決する必要がありますが、Googlerではできません。考えられる原因には、短期間で発行するクエリが多すぎる、または悪用の履歴がある共有/レピュテーションの低いIPから操作することが含まれます。自動スクレイピングにグーグルを使用しないでください。
という感じでIPがブロックされました。「あぁ... もう一生使えないかも...」って思ったのですが、2〜3日おいたら使えるようになりました。内心良かったーって思いました。😅
という事で...
:::message warning
googlerがデフォルトで取得してくる件数をオプションでいじれなくした状態で使う事を激しく推奨します。
:::
私はこんな感じでaliasを貼って使ってます。
function gfzs_google_fuzzy_search(){
# 結果を取得しすぎてロボット判定されないようにgooglerの-nと--countオプションを渡せなくする
FLAG_N=0
FLAG_S=0
GFZS_SCORE=30
googler_input=()
for OPT in "$@"
do
case $OPT in
-n | --count)
FLAG_N=1
;;
-s | --score)
FLAG_S=1
GFZS_SCORE=$2
shift
;;
*)
googler_input+=($1)
;;
esac
if [ $# -ne 0 ]; then shift; fi
done
if [ "$FLAG_N" -eq 1 ]; then
echo "Can't use -n(--count) option"
else
local res
if [ "$FLAG_S" -eq 1 ]; then
res=$(googler --json $googler_input | gfzs -s $GFZS_SCORE)
else
res=$(googler --json $googler_input | gfzs)
fi
if [ "$res" != "" ]; then
echo $res
fi
fi
}
alias ggr=gfzs_google_fuzzy_search
# 自分の場合
function ggr(){
command=$1
case $command in
"abema")
shift
googler_input=($@)
googler_input+=(-w abema.tv)
gfzs_google_fuzzy_search $googler_input
;;
"hulu")
shift
googler_input=($@)
googler_input+=(-w hulu.jp)
gfzs_google_fuzzy_search $googler_input
;;
"amazon")
shift
googler_input=($@)
googler_input+=(-w amazon.co.jp)
gfzs_google_fuzzy_search $googler_input
;;
"github")
shift
googler_input=($@)
googler_input+=(-w github.com)
gfzs_google_fuzzy_search $googler_input
;;
"zenn")
shift
googler_input=($@)
googler_input+=(-w zenn.dev)
gfzs_google_fuzzy_search $googler_input
;;
"qiita")
shift
googler_input=($@)
googler_input+=(-w qiita.com)
gfzs_google_fuzzy_search $googler_input
;;
"gem")
shift
googler_input=($@)
googler_input+=(-w rubygems.org)
gfzs_google_fuzzy_search $googler_input
;;
"npm")
shift
googler_input=($@)
googler_input+=(-w npmjs.com)
gfzs_google_fuzzy_search $googler_input
;;
"pypi")
shift
googler_input=($@)
googler_input+=(-w pypi.org)
gfzs_google_fuzzy_search $googler_input
;;
"crates")
shift
googler_input=($@)
googler_input+=(-w crates.io)
gfzs_google_fuzzy_search $googler_input
;;
*)
gfzs_google_fuzzy_search $@
;;
esac
}
使う時はこんな感じです。
typoしてても大丈夫です。googlerが勝手にそこらへん良しなにしてくれます。
ggr -s 30 python machne lerning
Ctrl-C
を押して閉じてみましょう。
$ ggr python machne lerning
** Showing results for python machine learning; use -x, --exact for an exact search.
typoしてたから、「python machine learning
」で探してみたよって言ってますね。
素晴らしい!
コマンドに関して
使えるコマンドは gfzs -h
で確認できます。
ここまでで二つほど使ってないコマンドがあります。
gfzs edit
gfzs valid
edit
edit
コマンドは、初期化の際、作られた設定ファイル(~/.gfzrc
)を編集するために使われるコマンドです。EDITOR
という環境変数にエディタを開くためのコマンドを設定して下さい。
例)
export EDITOR=code # vscodeで開く場合
gfzs edit
詳しい設定に関してはこちらで確認して下さい。
valid
valid
コマンドは、~/.gfzrc
が有効な設定ファイルかどうかを調べるためのコマンドです。
# 有効な場合
$ gfzs valid
Config is valid.
無効な場合を試すために、gfzs edit
で設定ファイルを以下のように修正してみて下さい。
コピペ用
{
"view": {
"hoge": {},
"fuga": [],
"footer": {
"messageaaa": "QUERY>",
"color": {
"message": {
"text": 8,
"background": 0,
"style": "normalaaaaa"
},
"hline": {
"text": 7,
"background": 0,
"styleaaaaaaaa": "linkbbbbbbbb"
}
}
},
"header": {
"color": {
"hline": {
"text": 7,
"background": 0,
"style": "normal"
}
}
},
"search_result": {
"color": {
"index": {
"text": 6,
"background": 0,
"style": "normal"
},
"title": {
"text": 2,
"background": 0,
"style": "bold"
},
"url": {
"text": 3,
"background": 0,
"style": "link"
},
"abstract": {
"text": 7,
"background": 0,
"style": "normal"
},
"markup_partial": {
"text": 2,
"background": 5,
"style": "normal"
},
"markup_char": {
"text": 1,
"background": 0,
"style": "normal"
}
}
},
"paging": {
"color": {
"common": {
"text": 2,
"background": 0,
"style": "bold"
}
}
}
}
}
この状態でコマンドを試すと以下のように表示されどこがおかしい設定かあたりをつけれるようになってます。
$ gfzs valid
Config is invalid.
Error: Contains unsupported key. (key_path, value) = (view.hoge, {}).
Error: Contains unsupported key. (key_path, value) = (view.fuga, []).
Error: Contains unsupported key. (key_path, value) = (view.footer.messageaaa, QUERY>).
Error: Contains unsupported value. (key_path, value) = (view.footer.color.message.text, 8).
Error: Contains unsupported value. (key_path, value) = (view.footer.color.message.style, normalaaaaa).
Error: Contains unsupported key. (key_path, value) = (view.footer.color.hline.styleaaaaaaaa, linkbbbbbbbb).
設定がおかしい状態で、demo
コマンドを試してみましょう。
$ gfzs demo
Config is invalid.
Error: Contains unsupported key. (key_path, value) = (view.hoge, {}).
Error: Contains unsupported key. (key_path, value) = (view.fuga, []).
Error: Contains unsupported key. (key_path, value) = (view.footer.messageaaa, QUERY>).
Error: Contains unsupported value. (key_path, value) = (view.footer.color.message.text, 8).
Error: Contains unsupported value. (key_path, value) = (view.footer.color.message.style, normalaaaaa).
Error: Contains unsupported key. (key_path, value) = (view.footer.color.hline.styleaaaaaaaa, linkbbbbbbbb).
こんな風に設定がおかしいと起動しないようになってます。
実行時オプションに関して
キーワードでの絞りこみには、fuzzywuzzy を使って実装しており、このライブラリーが返してくるスコア〇〇以上の結果だけ画面に表示するための -s(--score)
オプション(デフォルト値は30)が用意されています。
実際に使ってみたらよくわかります。
スコアを上げすぎると全く検索に引っかからなくなります。
gfzs -s 90 demo
逆に下げすぎると全く絞れなくなります。
gfzs -s 5 demo
なんか欲しいオプションあったらIssueを英語で起案して下さい。
まとめ
Googleの規制が緩くなって、一気に100件くらい取得できるようになったら本当に面白いツールになるかなって思ってます。(望み薄)
簡単に使えるので使ってみて下さい。(^ ^)
Discussion