この記事はGo4 Advent Calendar 2017の14日目の記事です。
BackGround
筆者は普段あまりwebベースな技術とは接点がありません。
しかしながら、webスクレイピングを活用できれば、いろいろおいしいなと思う今日この頃。
というわけで、Go向け公開されているgoqueryというライブラリを使用して、簡単なスクレイピングにチャレンジしてみました。
Target
- スクレイピングでどんなことが実現できるかの一例を、過程を踏まえて伝えます
- goqueryの詳しい情報が欲しい方は、ReferenceのGoDocをご覧ください
What I want to make
Weblio百貨辞典をコマンドラインから利用できるツールを作りたい。
英和、和英の機能をシンプルに利用したい。
Demo
以下のように、引数の言語(英語or日本語)を自動判定して、適したフォーマットで出力します。
# 英和
$ ./webligo apple
単語 : apple
主な意味 : リンゴ
音節 : ap・ple
発音記号・読み方 : ˈæpl
$ ./webligo pen
単語 : pen
主な意味 : (昔の、ペン先 とペン軸 を含めて)ペン、鵞(が)ペン、文筆(の業)
音節 : pen
発音記号・読み方 : pén
# 和英
$ ./webligo 鯖
日単語 : 鯖
英単語 : mackerel
$ ./webligo 鯵
日単語 : 鯵
英単語 : horse mackerel
# weblioに存在しない文字列
$ ./webligo wwwwwwwwwwwww
単語 : wwwwwwwwwwwww
主な意味 :
音節 :
発音記号・読み方 :
実行時間は最大10Mbps環境で1sec程度なので、十分実用に耐えるくらいになっています。
SourceCode
ソースコードは以下のようになりました。
goqueryの細かな説明は趣旨ではないので割愛しますが、goquery
のFind()
というメソッドを使って、
htmlのclassという属性から、そこに含まれるテキストを取得しています。
- ソースコードはGithubへ公開しています
package main
import (
"fmt"
"log"
"unicode/utf8"
"github.com/PuerkitoBio/goquery"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
word = kingpin.Arg("word", "target word").Required().String()
)
func main() {
kingpin.Parse()
doc, err := goquery.NewDocument("http://ejje.weblio.jp/content/" + *word)
if err != nil {
log.Fatal(err)
}
if isIncludeMultibyte(*word) {
fmt.Printf("日単語 : %s\n", *word)
fmt.Printf("英単語 : %s\n", doc.Find(".content-explanation").Text())
} else {
fmt.Printf("単語 : %s\n", *word)
fmt.Printf("主な意味 : %s\n", doc.Find(".content-explanation").Text())
fmt.Printf("音節 : %s\n", doc.Find(".syllableEjje").Text())
fmt.Printf("発音記号・読み方 : %s\n", doc.Find(".phoneticEjjeDesc").Text())
}
}
func isIncludeMultibyte(str string) bool {
return utf8.RuneCountInString(str) != len(str)
}
package main
import "testing"
func TestIsIncludeMultibyte(t *testing.T) {
tests := []struct {
input string
expected bool
}{
{
"apple",
false,
},
{
"umbrella",
false,
},
{
"----",
false,
},
{
"林檎",
true,
},
{
"かさ",
true,
},
{
"○",
true,
},
{
"Goラング",
true,
},
}
for i, test := range tests {
got := isIncludeMultibyte(test.input)
if got != test.expected {
t.Errorf("tests[%d] got %v, want %v", i, got, test.expected)
}
}
}
Roundup
- webの知識に疎くともライブラリを適切に使えば、やりたいことを簡単に実現できた
- 広く利用されているjqueryをベースとしているので、情報がたくさんある