自己顕示欲の開放治療所

erg, programming and something.

別名:Laughing and Grief 雑記

Latin and Greekは習ったこともない

真面目な記事の他、特定の方には不快と思われる事柄に関して言及を行うことがあります。ちょっと頑張りますが、Blog内で解決できなかった場合要望があれば別ページに技術記事は書き直します

Gravaterの画像を自分で描く

www.adventar.org

一日目だしハードルは無いに等しい。ということで、今までやりたかったがやっていなかったGravater*1を設定することにした。

好きなキャラクターの画像は心に良いが、そのまま引っ張ってくるのはあまりよろしくない。そこで神絵師*2だ。 神絵師なら版権絵も自分のテイストに落としこんでいい感じになるはず。

描く

描いた。Krita*3一太郎30周年記念ペンタブ*4を用いた。 ちなみにこれに一時間かけている。察せ。

f:id:hidden_alma:20161130165324p:plain:w350

平グモちゃん*5可愛い。可愛い平グモちゃんを描いたからには可愛い絵が爆誕しているはずだ。

上げる

先ずは上記サイトにて登録。メールが来るので承認ページへ。

上げた。達成感がある。段々恥ずかしくなってくるが耐える。

おわり

2日目は@karasuTXのはず。

*1:https://ja.gravatar.com/

*2:これは神絵師になるのが目的のカレンダー、らしい。

*3:https://krita.org/jp/

*4:Intuos pen&touch small

*5:https://www.liar.co.jp/hiragumotop.html

Golangのtemplateライブラリハマり

ちょこちょこやっているので追加するかも。

ブレース"{" "}"が{{}}の前後に書けないっていう。

LeTeX用のテンプレートを書こうとしてハマる。

stackoverflow.com

というわけで、

\title{{print "{"}}{{.Booktitle}}{{print "}"}}

のようにして解決した(解決していない)。

げっちゅな屋でスクレイピング2

以前のエントリで書いたのは月別の発売日を出力するものでしたが、今回は検索を行うものを書きました。基本は一緒で、URL、クエリ、matcherなどが変わりました。要は別サイトをスクレイピングした感じになりました。

詰まった所

  • クエリをEucJPにするのを忘れてしばらく時間を使った。
  • 発売日に特徴的なタグがついていない(諦めて該当箇所全部出すことにした)。

code

package main

import (
    "flag"
    "fmt"
    "net/http"
    "strings"

    "io/ioutil"
    "net/http/cookiejar"
    "net/url"

    "github.com/yhat/scrape"
    "golang.org/x/net/html"
    "golang.org/x/net/html/atom"
    "golang.org/x/text/encoding/japanese"
    "golang.org/x/text/transform"
)

var (
    keyword   string
    title     string
    brand     string
    person    string
    isbn      string
    jan       string
    age       string
    genre     string
    startDate string
    endDate   string
    sort      string
    sort2     string
    listCount string
    listType  string
    search    string
)

func eucjpToUtf8(str string) (string, error) {
    ret, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(str), japanese.EUCJP.NewDecoder()))
    if err != nil {
        return "", err
    }
    return string(ret), err
}

func utf8ToEucjp(str string) (string, error) {
    ret, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(str), japanese.EUCJP.NewEncoder()))
    if err != nil {
        return "", err
    }
    return string(ret), err
}

func main() {

    flag.StringVar(&keyword, "keyword", "", "search keyword")
    flag.StringVar(&keyword, "k", "", "search keyword short")

    flag.StringVar(&title, "title", "", "search title")
    flag.StringVar(&title, "t", "", "search title short")

    flag.StringVar(&brand, "brand", "", "search brand")
    flag.StringVar(&brand, "b", "", "search brand short")

    flag.StringVar(&person, "person", "", "search person")
    flag.StringVar(&person, "p", "", "search person short")

    flag.StringVar(&isbn, "isbn", "", "search isbn")
    flag.StringVar(&isbn, "i", "", "search isbn short")

    flag.StringVar(&jan, "jan", "", "search jan")
    flag.StringVar(&jan, "j", "", "search jan short")

    flag.StringVar(&age, "age", "", "age")
    flag.StringVar(&age, "a", "", "age short")
    flag.StringVar(&genre, "genre", "pc_soft", "genre")
    flag.StringVar(&genre, "g", "pc_soft", "genre default pc_soft")

    flag.StringVar(&startDate, "startdate", "", "start date")
    flag.StringVar(&startDate, "sd", "", "start date short")

    flag.StringVar(&endDate, "enddate", "", "end date")
    flag.StringVar(&endDate, "ed", "", "end date short")

    flag.StringVar(&listCount, "listcount", "100", "list")
    flag.StringVar(&listCount, "lc", "100", "list short default 100")

    flag.StringVar(&listType, "listtype", "list", "list type  default list")
    flag.StringVar(&listType, "lt", "list", "list type short")

    flag.StringVar(&sort, "sort", "release_date", "sort default release_date")

    flag.StringVar(&sort2, "sort2", "down", "sort2 default down")

    flag.StringVar(&search, "search", "search", "search default search")
    flag.StringVar(&search, "s", "search", "search short")

    flag.Parse()

    getchuURL := "http://www.getchu.com/php/nsearch.phtml"
    jar, _ := cookiejar.New(nil)
    var cookies []*http.Cookie
    cookie := &http.Cookie{
        Name:   "getchu_adalt_flag",
        Value:  "getchu.com",
        Path:   "/",
        Domain: "www.getchu.com",
    }
    cookies = append(cookies, cookie)
    u, _ := url.Parse(getchuURL)
    jar.SetCookies(u, cookies)
    client := &http.Client{
        Jar: jar,
    }

    brand, _ = utf8ToEucjp(brand)
    title, _ = utf8ToEucjp(title)
    keyword, _ = utf8ToEucjp(keyword)
    person, _ = utf8ToEucjp(person)

    values := url.Values{}
    values.Set("search_keyword", keyword)
    values.Add("search_title", title)
    values.Add("search_brand", brand)
    values.Add("search_person", person)
    values.Add("search_isbn", isbn)
    values.Add("search_jan", jan)
    values.Add("start_date", startDate)
    values.Add("end_date", endDate)

    values.Add("sort", sort)
    values.Add("sort2", sort2)

    values.Add("list_count", listCount)
    values.Add("list_type", listType)

    values.Add("age", age)
    values.Add("genre", genre)
    values.Add("search", search)
    valuesEncoded := values.Encode()

    req, _ := http.NewRequest("POST", getchuURL, strings.NewReader(valuesEncoded))
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    resp, err := client.Do(req)

    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    root, err := html.Parse(resp.Body)
    if err != nil {
        panic(err)
    }

    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

    matcherTitle := func(n *html.Node) bool {
        if n.DataAtom == atom.Div {
            return scrape.Attr(n, "class") == "content_block"
        }
        return false
    }

    titles := scrape.FindAll(root, matcherTitle)

    for i, title := range titles {
        title, err := eucjpToUtf8(scrape.Text(title))
        if err != nil {
            panic(err)
        }

        fmt.Printf("%d: %s\n", i, title)
    }

}


げっちゅな屋でスクレイピング

なに

まだとりあえずタイトルが引っぱれるだけですが。golangでscrapeライブラリを使っています。

先達がコチラhttp://akb428.hatenablog.com/?page=1437903964

追記(2016-11-10)

year、monthを引数にとってその年月の発売作品のタイトルを並べます。引数なしの場合、現在の月の発売作品を並べます。 respをCloseするようにしたのと、ブランド、発売日を表示するようにしました。

utf-8に変換してます Go言語で文字コード変換 - Qiita

code

package main

import (
    "flag"
    "fmt"
    "net/http"
    "strings"
    "time"

    "io/ioutil"
    "net/http/cookiejar"
    "net/url"

    "github.com/yhat/scrape"
    "golang.org/x/net/html"
    "golang.org/x/net/html/atom"
    "golang.org/x/text/encoding/japanese"
    "golang.org/x/text/transform"
)

const (
    stdLongYear = "2006"
    stdNumMonth = "1"
)

var (
    year  string
    month string
)

func eucjpToUtf8(str string) (string, error) {
    ret, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(str), japanese.EUCJP.NewDecoder()))
    if err != nil {
        return "", err
    }
    return string(ret), err
}

func main() {
    t := time.Now()

    flag.StringVar(&year, "year", t.Format(stdLongYear), "sell year")
    flag.StringVar(&month, "month", t.Format(stdNumMonth), "sell month")

    flag.Parse()

    getchuUrl := "http://www.getchu.com/all/price.html?genre=pc_soft&gage=adult"
    jar, _ := cookiejar.New(nil)
    var cookies []*http.Cookie
    cookie := &http.Cookie{
        Name:   "getchu_adalt_flag",
        Value:  "getchu.com",
        Path:   "/",
        Domain: "www.getchu.com",
    }
    cookies = append(cookies, cookie)
    u, _ := url.Parse(getchuUrl)
    jar.SetCookies(u, cookies)
    client := &http.Client{
        Jar: jar,
    }

    postData := strings.NewReader("&year=" + year + "&month=" + month)
    req, _ := http.NewRequest("POST", getchuUrl, postData)
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    resp, err := client.Do(req)

    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    root, err := html.Parse(resp.Body)
    if err != nil {
        panic(err)
    }

    matcherGame := func(n *html.Node) bool {
        if n.DataAtom == atom.A && n.Parent != nil && n.Parent.Parent != nil {
            return scrape.Attr(n.Parent, "align") == "left"
        }
        return false
    }

    matcherSellday := func(n *html.Node) bool {
        if n.DataAtom == atom.Td {
            return scrape.Attr(n, "class") == "black" && scrape.Attr(n, "align") == "center"
        }
        return false
    }

    matcherBrand := func(n *html.Node) bool {
        if n.DataAtom == atom.Td {
            return scrape.Attr(n, "class") == "black" && scrape.Attr(n, "align") == "left"
        }
        return false
    }

    games := scrape.FindAll(root, matcherGame)
    selldays := scrape.FindAll(root, matcherSellday)
    brands := scrape.FindAll(root, matcherBrand)

    selldayList := make(map[int]string)
    for i, sellday := range selldays {
        selldayList[i] = scrape.Text(sellday)
    }

    brandList := make(map[int]string)
    for i, brand := range brands {
        brandList[i], err = eucjpToUtf8(scrape.Text(brand))
        if err != nil {
            panic(err)
        }
    }

    for i, game := range games {
        //    sellday, err := eucjpToUtf8(scrape.Text(sellday))
        game, err := eucjpToUtf8(scrape.Text(game))
        if err != nil {
            panic(err)
        }

        fmt.Printf("%s: %s| %s\n", selldayList[i], game, brandList[i])
    }

}

LXD/LXCコンテナ内部にisoマウント

ローカルのコンテナにisoをマウントしたかった。ホスト、コンテナ共にUbuntu。LXDはversion 0.20。パスはデフォルトの場合です。

予めコンテナ側でcdromディレクトリを作ってから、ホスト側で

sudo mount -o loop hoge.iso /var/lib/lxd/containers/<コンテナ名>/rootfs/media/ubuntu/cdrom

で、後はコンテナ内から media/ubuntu/cdrom をみるとhoge.isoの中身が見られれば成功。

VPSでLXD+SoftEtherVPN(Server側)

こんな記事があったのでやろうとしてみた。

gihyo.jp

タイトルと違うって? そりゃ失敗したからね!

具体的にはlxcだけの操作になってるところを今のlxd/lxc環境でやるのはひっかかりが多くて、っていうのと tun 君が作れなかったり、つくれたと思ってもダメだったりしたので*1諦めました。

なら他のVPNサービスは?って調べたら

ever-day-jp: LXCとSoftEtherを利用してサーバー上にセキュアな作業システムを作る その2

がヒットしたのでやったらイケた。

今回はさくらのVPS(Ubuntu14.04)で建てました。速度とかはまあ家の回線がksなので全く違いがわからない程度です。

LXDの用意

LXD*2はUbuntu15.04ならaptで入りますが14.04ではビルドの必要がーー今回はありません。そう、Ubuntuならね。

% sudo apt-add-repository ppa:ubuntu-lxc/lxd-stable
% sudo apt update
% sudo apt install lxd

あ、「 apt-add-repository がないのだけれど」という方は

% sudo apt install software-properties-common

としてください。

LXDの起動

さて、LXDを入れたらまずコンテナイメージを入手しましょう、ということで

# lxd-images import lxc ubuntu trusty amd64 --alias trusty

で14.04のイメージを入手、

2015年9月1日のリリースで上のやり方は廃止されました*3Ubuntubusybox以外のときの方法がニュースのところに載っています。

Ubuntuなら

# lxd-images import ubuntu trusty amd64 --alias trusty

のようにすれば良いようです。Ubuntuは接続先がlinuxcontainers.orgからcloud-images.ubuntu.comに変わったみたいです。繋がらないと思ったら lxd-images sync などを試してみるとまた接続先が変わっていたりするかもしれません。

# lxc launch trusty container-vpn

でコンテナを作成、起動します。

コンテナの中に入るには

# lxc exec コンテナ名 /bin/bash

などとすれば入れますがrootで入ってしまうので、初めにsshを入れてしまうと後はsshで入って通常ユーザに。 コンテナのローカルなIPは

# lxc list

で見られます。なお、このようにして作られたコンテナの中には最初からubuntuというユーザがいるのでpasswdでパスワードを変えておきましょう。

そしていよいよSoftEtherVPNのビルドに移るのですが、なんかもう色々と面倒だな、と参考のブログ記事同様

sudo apt-add-repository ppa:dajhorn/softether

とするとあら簡単。ppaの登録は各々の責任で行ってください。

VPN Serverの設定

sudo vpncmd /server localhost /CMD HubCreate HUB名 /password: パスワード
sudo vpncmd /server localhost /CMD BridgeCreate HUB名 /DEVICE:eth0
sudo vpncmd /server localhost /CMD HubDelete DEFAULT
sudo vpncmd /server localhost /CMD VpnAzureSetEnable yes
sudo vpncmd /server localhost /CMD Flush
sudo vpncmd /server localhost /CMD VpnAzureGetStatus

というわけで対話セッションを省略した場合の簡易セットアップ。ほぼ参考記事のままですね。HUBを作り、デフォルトを削除し、VPNAzureの設定を有効にし、そのアドレスを確認しておくという流れです。VPNAzureがあればコンテナからホストに出る手間がないので楽ができる、というか僕はそれ以外のやり方ががが。

下書きしたのが随分前になってしまったので抜けや更新情報が多いかも。

骨伝導ヘッドフォン買いかえた

以前使っていたGoldendanceの赤いのがブッ壊れたので新しいのを購入。

骨伝導ヘッドホン耳フリーAS400(AfterShokz)

以前使っていたやつはアホみたいな音量にしないと実用に耐えなかったが、今回はくっついたアンプが補ってくれる。ただしアンプの位置が「絶対お前ここから壊れるだろ」って感じだが。amazonのレビューからあまり離れていない。 ただ、アンプ部分が動作時は一定の間隔で青に点滅するのでウザい。周りからウザがられないかも気になる。

でもこれ以上だとマイク付きだったり無線BlueToothだったりだからなぁ。