1. akif999

    No comment

    akif999
Changes in title
-goqueryでweblio百科事典のコマンドラインビューアを作ってみた
+Go x goqueryでwebスクレイピング
Changes in body
Source | HTML | Preview
@@ -1,99 +1,140 @@
# BackGround
-よくお世話になっている[weblio英和和英辞典](http://ejje.weblio.jp)。
-調べるときはおもむろにブラウザのタブを追加して...となることが多い。
-macには辞書.appなるものも入っていて三本指タップで検索、とかできるけど、
-CLIが好きな筆者としては辞書もコマンドラインから叩きたい
-というわけで`Go × goqueryスクレイピング`なノリで作ってみた。
-
-※ 筆者は限りなくハードウェア寄りのソフトウェアエンジニアで、web系の知識に疎いため(趣味的なレベルということ)、そのあたりの解説がプアなのはご了承下さい
+筆者は普段あまりwebベースな技術とは接点がありません。
+しかしながら、webスクレイピングを活用できれば、いろいろおいしいなと思う今日この頃
+というわけで、Go向け公開されているgoqueryというライブラリを使用して、簡単なスクレイピングにチャレンジしてみました。
+
+# Target
+* スクレイピングでどんなことが実現できるかの一例をを、過程を踏まえて伝える
+
+# What I want to make
+Weblio百貨辞典をコマンドラインから利用できるツールを作りたい。
+英和、和英の機能をシンプルに利用したい。
# Demo
+
+以下のように、引数の言語(英語or日本語)を自動判定して、適したフォーマットで出力します。
+
```bash
+# 英和
$ ./webligo apple
単語 : apple
主な意味 : リンゴ
音節 : ap・ple
発音記号・読み方 : ˈæpl
$ ./webligo pen
単語 : pen
主な意味 : (昔の、ペン先 とペン軸 を含めて)ペン、鵞(が)ペン、文筆(の業)
音節 : pen
発音記号・読み方 : pén
-$ ./webligo hoge
-単語 : hoge
-主な意味 : とくに意味もないときに使う変数名
-音節 :
-発音記号・読み方 : hóʊdʒ
-$ ./webligo fuga
-単語 : fuga
-主な意味 : フーガ
-音節 :
-発音記号・読み方 :
+
+# 和英
$ ./webligo 鯖
日単語 : 鯖
英単語 : mackerel
$ ./webligo 鯵
日単語 : 鯵
英単語 : horse mackerel
-
```
-必要最低限な情報だけ出力するようにした。
-こういう単純化がしやすいからコマンドラインはいい
+実行時間は最大10Mbps環境で1sec程度なので、十分実用に耐えるくらいになっています
# SourceCode
+ソースコードは以下のようになりました。
+goqueryの細かな説明は趣旨ではないので割愛しますが、`goquery`の`Find()`というメソッドを使って、
+htmlのclassという属性から、そこに含まれるテキストを取得しています。
+
```go
package main
import (
"fmt"
"log"
"unicode/utf8"
"github.com/PuerkitoBio/goquery"
"gopkg.in/alecthomas/kingpin.v2"
)
-const (
- EnToJp = iota
- JpToEn
-)
-
var (
- searchWord = kingpin.Arg("searchWord", "searchWord string").Required().String()
+ word = kingpin.Arg("word", "target word").Required().String()
)
func main() {
kingpin.Parse()
-
- // if searchWord includes multibyte charactor, set mode to JpToEn
- mode := EnToJp
- if utf8.RuneCountInString(*searchWord) != len(*searchWord) {
- mode = JpToEn
- }
-
- doc, err := goquery.NewDocument("http://ejje.weblio.jp/content/" + *searchWord)
+
+ // 引数から、検索したい語句のページを取得する
+ doc, err := goquery.NewDocument("http://ejje.weblio.jp/content/" + *word)
if err != nil {
log.Fatal(err)
}
- if mode == EnToJp {
- fmt.Printf("単語 : %s
-", *searchWord)
+ // マルチバイト文字を含むならば日本語、含まないなら英語として、情報を取得して出力する
+ if isIncludeMultibyte(*word) {
+ fmt.Printf("日単語 : %s\n", *word)
+ fmt.Printf("英単語 : %s\n", doc.Find(".content-explanation").Text())
+ } else {
+ fmt.Printf("単語 : %s
+", *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())
- } else {
- fmt.Printf("日単語 : %s\n", *searchWord)
- fmt.Printf("英単語 : %s\n", doc.Find(".content-explanation").Text())
-
+ }
+}
+
+func isIncludeMultibyte(str string) bool {
+ if utf8.RuneCountInString(str) != len(str) {
+ return true
+ }
+ return false
+}
+```
+
+```go
+package main
+
+import "testing"
+
+func TestIsIncludeMultibyte(t *testing.T) {
+ tests := []struct {
+ input string
+ expected bool
+ }{
+ {
+ "apple",
+ false,
+ },
+ {
+ "umbrella",
+ false,
+ },
+ {
+ "----",
+ false,
+ },
+ {
+ "林檎",
+ true,
+ },
+ {
+ "かさ",
+ true,
+ },
+ {
+ "○",
+ 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)
+ }
+
}
}
```
-基本的には`Find()`でセレクタを利用して欲しい情報を取りに行くだけなので、とても簡単に描けた。
-プログラミング的には不満でも、packageの使いやすさには満足。
# Roundup
-* weblio自体がinputをとても柔軟に捉えてくれるので、リッチな使いごごち
-* アクセス速度に実行時間は依存するが、アクセス後の処理は一瞬で、実用的な仕上がり
-* `goquery`はwebの知識が無くとも、簡素なスクレイピングプログラムくらいはすぐに書け
+* webの知識に疎くともライブラリを適切に使えば、やりたいことを簡単に実現できた
+* 広く利用されているjqueryをベースとしているので、情報がたくさんあ
# Reference
* [weblio.jp](http://ejje.weblio.jp)
* [GoDoc goquery](https://godoc.org/github.com/PuerkitoBio/goquery)