グルーピングしたキーワードの複合語をカウントし共通キーワードを抽出する

先日、久々にグーグルサジェストをキーワード + a-zで回すシェルスクリプトを動かしてみました。動きました。で、それで得た複合語をカウントするPHPのスクリプトも作成していたのですが、それも動きました。もっとプログラミングをしたいのですが、そんな暇はありません。が、それでも動かさなければならない理由がありました。

やりたいのはグルーピングしたキーワードの複合語を収集し、複合語をカウントしすることで共通キーワードを抽出するということです。これだけではよくわからないと思うので簡単に説明したいと思います。

まずは、プログラミング言語名というグループで複合語をグーグルサジェストで取得します。選んだのは「php」「javascript」「python」「perl」です。いずれも複合語にa-zは指定せず単体(ex. php)で検索した場合の複合語です。

php
php 配列
phpstorm
php for
php 配列 追加
php substr
php 正規表現
phpmyadmin
php empty
php研究所

javascript
javascript 入門
javascript 配列
javascript push
javascript substr
javascript foreach
javascript for
javascript replace
javascript 正規表現
javascript if

python
python 入門
python for
python print
python 正規表現
python インストール
python if
python グラフ
python 配列
python 四捨五入

perl
perl 正規表現
perl int
perl mkdir
perl switch
perl exists
perl 比較演算子
perl split
perl 配列
perl 入門

どのプログラミング言語名にも共通した単体の複合語があります。「配列」「正規表現」ですね。「入門」というキーワードもphp以外に共通しています。プログラミングを学ぶ上で、これらのキーワードが重要になってきたり、コンテンツを提供するうえでこれらのキーワードの情報を求めている人が多いんだなというのはわかりました。さらにいうと、今後も新しいプログラミング言語はでてくると思います。そのときにこの共通の単体複合語が要になってきます。つまり、

新しいプログラミング言語 + 配列
新しいプログラミング言語 + 正規表現
新しいプログラミング言語 + 入門

なんかですね。今回は簡単な例なので、想像のつく範囲なのですが1キーワードで何十何百というキーワードを取得することになります。これを機械的に処理するだけで、新しい発見があるというのは素敵なことなんじゃないかというのが、冒頭にも挙げた「それでも動かさなければならない理由」になります。

で、動かしてみて気づいたことは、複合語を半角スペースでぶった切ってカウントしているので3ワードの複合語の場合、意味が通じない(通じにくくなる)ことです。例えば、

メインキーワード 乃木坂 46

だと「メインキーワード」「乃木坂」「46」でカウントしてしまいます。「乃木坂」はわかるのですが「46」というキーワードが宙に浮いたような感じになります。まあ、このプログラムで正確な答えを求めているわけではないので現状で十分なのですが、実際に動かしてみないと見えてこないものがあるなと。

コアサーバーのサブドメインでどれを使うのがいいか?

私は無料有料含め、複数のレンタルサーバーを利用しているのですが、中でも一番利用しているのがコアサーバーです。コアサーバーには無料でサブドメインがついているのですが、どのドメインのサブドメインを作成しようか迷います。今の時代、別にどのドメインを選んだところでSEOには響かなそうなのですが、それはさておいても複数のドメインがあるので、結局迷うことになります。

というわけで、2つの指標からドメインを選定したいと思います。2つの指標は、

1. jpドメインであること

2. Googleの検索結果にあまりないこと

それではいってみましょう。

1. jpドメインであること

コアサーバーでは、以下のドメインからサブドメインを取得することができます。

coresv.com
coresv.net
bex.jp
geo.jp
awe.jp
gob.jp
ebb.jp
bulog.jp
weblog.am
weblog.tc
weblog.vc
sphere.sc
cms.am

jpドメインの中から選ぶということなので、以下の6ドメインに絞り込むことができました。

bex.jp
geo.jp
awe.jp
gob.jp
ebb.jp
bulog.jp

coresv.com、coresv.netはcom、netと汎用的なドメインなので重宝しそうですが、見る人が見るとコアサーバーかなと一発で分かります。あとweblogはブログの運用で使えそうですが、聞いたことない.amなんかのトップレベルドメインは躊躇してしまいます。別にいいかなと思っても長い目で見るとjpドメインになってしまいます。

2. Googleの検索結果にあまりないこと

どうせ選ぶのであればグーグルの検索結果にあまりないドメインを選びたくなります。あまりにも少ないとスパム判定されているのかな?と疑ってしまいますが、今の時代そこまでグーグルもバカじゃないと思います。サブドメインは公平に評価してくれていると思います。

bex.jp: 約 31,900 件
geo.jp: 約 179,000 件
awe.jp: 約 10,700 件
gob.jp: 約 16,300 件
ebb.jp: 約 17,800 件
bulog.jp: 約 15,000 件

geo.jpは一桁多いですね。ということで却下。残るは僅差なのでどれをとってもよさそうですが、欲が出てきました。ドメインの意味です。ぱっと見は意味などなさそうですが、調べてみると何らかの意味はありそうです。geoもついでに調べてみます。

bex

BEX (broadband exchange)
https://ejje.weblio.jp/content/bex

bexは会社名だったり短縮文字で使いやすかったりします。何とかエクスチェンジとか。なんとかエクスペリエンスとか。

geo

株式会社ゲオ(英称:GEO CORPORATION)は、愛知県名古屋市中区に本社を置くレンタルビデオ・リユースショップのチェーンストア。https://ja.wikipedia.org/wiki/%E3%82%B2%E3%82%AA

どっちみち太刀打ちできないですね。却下です。

awe

畏(おそ)れ、畏怖(いふ)、畏敬
https://ejje.weblio.jp/content/awe

畏(おそ)れ?これから果敢に攻めようとしてるんだよ!

gob

唾[痰]を吐く
https://eow.alc.co.jp/search?q=gob

唾を吐いてもいいことないです。

ebb

引き潮、減退、衰退(期)
https://ejje.weblio.jp/content/ebb

引き潮とか釣りをやってた頃気にしたキーワード。減退とか衰退とか絡んでくると却下ですね。

bulog

食糧庁(Badan Urusan Logistik)
https://njjn.weblio.jp/content/Bulog

検索結果にはドメインが出てきます。当て字なのでそんな感じになりますね。

ほぼweblioなのですが、あんまりいいイメージないですね。無難なのはbexとbulogでしょうか。ドメインの意味があまりにも残念な結果なのでcoresv.comとcoresv.netも候補にしたいと思います。

coresv.com: 約 30,300 件
coresv.net: 約 7,300 件

おっと、いずれも選択候補です。coresv.netは1万を切ります。というわけでbex.jp、bulog.jp、coresv.com、coresv.netを適宜(まあ気分ですが)選んでいきたいと思います。コアサーバーを10年くらい使ってますが、ここまでサブドメインを考えたことなかったかな。

Bashでグーグル検索、グーグルサジェストをスクレイピング

Google Suggest

function google_suggest_search()
{
  local _QUERY=$(urlencode_utf8 "$1")
  local _URL='http://www.google.co.jp/complete/search'

  curl -s "${_URL}?output=toolbar&q=${_QUERY}" | nkf -w | \
  perl -pe "s/<\/CompleteSuggestion>/<\/CompleteSuggestion>\n/g" | \
  grep 'suggestion data' | grep 'num_queries int' | \
  sed "s|.*<suggestion data=\"\([^\"]*\)\"/><num_queries int=\"\([^\"]*\)\"/>.*|\1,\2|g"
  sleep $(($RANDOM % 5 + 3))

  return 0
}
function google_suggest()
{
  local MSG="Usage: google_suggest [keyword]"
  if [ ! "$1" ]||[ "-h" == "$1" ]; then echo $MSG; return 1; fi
  local _QUERY="$1"
  local _FILE_NAME=$(echo "$1" | sed 's/[ | ]/_/g')
  echo -n "" >${_FILE_NAME}.csv

  for i in {a..z} {0..9} あ い う え お か き く け こ さ し す せ そ た ち つ て と な に ぬ ね の は ひ ふ へ ほ ま み む め も や ゆ よ ら り る れ ろ わ を ん
  do
    google_suggest_search "${_QUERY} $i" | tee -a ${_FILE_NAME}.csv
    google_suggest_search "$i ${_QUERY}" | tee -a ${_FILE_NAME}.csv
  done
  sort -u ${_FILE_NAME}.csv >${_FILE_NAME}.$$
  mv -f ${_FILE_NAME}.$$ ${_FILE_NAME}.csv

  return 0
}

google.co.jp

function google_rank_search()
{
  local _QUERY="$1"
  local _URL="$1"

  curl -s -A 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1' \
       "https://www.google.co.jp/search?q=${_QUERY}&start={0,10,20}" | nkf -w >cache.html

  cat cache.html | perl -pe "s/<h3 class=\"r\">/\n<h3 class=\"r\">/g" | grep '<h3 class="r">' | \
  sed -e 's|<a [^>]*>||g' -e 's|</a>||g' -e 's|<em>||g' -e 's|</em>||g' -e 's|<b>||g' -e 's|</b>||g' | \
  sed -e 's|<span class=bc>||g' -e 's| &rsaquo;[^>]*</span>||g' | \
  sed 's|.*<h3 class="r">\([^>]*\)</h3>.*<cite>\([^>]*\)</cite>.*|\1,\2|g' | tee ${_QUERY}.csv
  cat ${_QUERY}.csv | grep "${_URL}" >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    echo "${_QUERY},NA"
  fi
}

function google_result_stats()
{
  local _QUERY=$(urlencode_utf8 "$1")

  curl -s -A 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1' \
       "https://www.google.co.jp/search?q=${_QUERY}" | nkf -w >cache.html

  cat cache.html | grep '<div id=resultStats>' | \
  sed -e "s|.*約 ||g" -e "s| 件.*||g" -e "s|.*<div id=resultStats>||g"
#  sed "s|.*<div id=resultStats>約 \([^ ]*\) 件<nobr>  (0.12 秒)&nbsp;</nobr></div>.*|\1|g"
}

utf-8でエンコードするPerlのワンライナー

function urlencode_utf8()
{
  perl -MEncode -MURI::Escape -e "print uri_escape(encode('utf8', decode('utf8', "@ARGV[0]")));" "$1"
}