20190929のGoに関する記事は3件です。

Golang - osパッケージについて

はじめに

Golangの標準パッケージであるosパッケージについて書いていきます

参考:スターティングGo言語

os

ファイルや環境変数の操作、プロセス情報の参照など、各OSに依存した機能群を内部に隠蔽した、プラットフォームに独立したAPIを提供します

プログラムの終了

os.Exitによって任意のタイミングでプログラムを停止できる

// os.Exitによってdeferが破棄される
func discardefer() {
    defer func() {
        fmt.Println("defer")
    }()
    os.Exit(1)
}

log.Fatal

エラーが発声した際に、エラーメッセージを表示してプログラムを終了する場合に使用する

// 指定したファイルが存在しないためエラーが発声
func nofile() {
    _, err := os.Open("foo.txt")
    if err != nil {
        log.Fatal(err)
    }
}

// 2019/09/28 15:32:57 open foo.txt: no such file or directory

コマンドライン引数

os.Argsは任意の数のコマンドライン引数が、string型のスライスで格納される

// os.Argsの要素数と内容を表示
func main() {
    fmt.Printf("length=%d\n", len(os.Args))
    for _, v := range os.Args {
        fmt.Println(v)
    }
}
▸ ./commandargs 123 456 789 
length=4
./commandargs
123
456
789

ファイル、ディレクトリ操作

func operationdirectory() {
    // ディレクトリ作成
    if err := os.Mkdir("hoge", 0777); err != nil {
        fmt.Println(err)
    }
    // ディレクトリ存在確認
    if _, err := os.Stat("hoge"); err != nil {
        fmt.Println(err)
    }
    // 複数ディレクトリ作成
    if err := os.MkdirAll("piyo/fuga", 0777); err != nil {
        fmt.Println(err)
    }
    // ファイル名変更
    if err := os.Rename("hoge", "hage"); err != nil {
        fmt.Println(err)
    }
    // ディレクトリ移動
    if err := os.Rename("piyo/fuga", "hage/fuga"); err != nil {
        fmt.Println(err)
    }
    // ディレクトリ権限変更
    if err := os.Chmod("piyo", 0775); err != nil {
        fmt.Println(err)
    }
    // ディレクトリ削除
    if err := os.Remove("piyo"); err != nil {
        fmt.Println(err)
    }
    // ディレクトリ削除(中のファイル、ディレクトリ含む)
    if err := os.RemoveAll("hage"); err != nil {
        fmt.Println(err)
    }
}

func operationfile() {
    // ファイル作成
    if _, err := os.Create("hoge.txt"); err != nil {
        fmt.Println(err)
    }
    // ファイル存在確認
    if _, err := os.Stat("hoge.txt"); err != nil {
        fmt.Println(err)
    }
    // ファイル名変更
    if err := os.Rename("hoge.txt", "fuga.txt"); err != nil {
        fmt.Println(err)
    }
    if err := os.Mkdir("hage", 0777); err != nil {
        fmt.Println(err)
    }
    if _, err := os.Create("hage/piyo.txt"); err != nil {
        fmt.Println(err)
    }
    // ファイル移動
    if err := os.Rename("hage/piyo.txt", "piyo.txt"); err != nil {
        fmt.Println(err)
    }
    // ファイル権限変更
    if err := os.Chmod("fuga.txt", 0664); err != nil {
        fmt.Println(err)
    }
    // ファイル書き込み
    writefile()
    // ファイル読み込み
    file, err := os.Open("fuga.txt")
    if err != nil {
        fmt.Println(err)
    }
    defer file.Close()
    buf := make([]byte, 1024)
    for {
        n, err := file.Read(buf)
        if n == 0 {
            break
        }
        if err != nil {
            break
        }
        fmt.Println(string(buf[:n]))
    }
    // ファイル削除
    if err := os.Remove("fuga.txt"); err != nil {
        fmt.Println(err)
    }
    if err := os.Remove("piyo.txt"); err != nil {
        fmt.Println(err)
    }
    if err := os.Remove("hage"); err != nil {
        fmt.Println(err)
    }
}

func writefile() {
    file, err := os.Create("fuga.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    file.Write(([]byte)("HelloWorld"))
}

ホスト名

func gethost() {
    host, err := os.Hostname()
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(host)
}

環境変数

func getenv() {
    // 環境変数の一覧
    for _, v := range os.Environ() {
        fmt.Println(v)
    }
    // 環境変数を設定
    os.Setenv("GO_TEST_ENV", "HelloWorld")
    // 名前を指定して取得
    fmt.Println(os.Getenv("GO_TEST_ENV"))
    // 名前を指定して削除(全て削除はClearEnv)
    os.Unsetenv("GO_TEST_ENV")
    fmt.Println(os.Getenv("GO_TEST_ENV"))
    // 存在チェックした上で参照
    if home, ok := os.LookupEnv("GO_TEST_ENV"); ok {
        fmt.Println(home)
    } else {
        fmt.Println("no $GO_TEST_ENV")
    }
}

プロセス

func getprocess() {
    fmt.Println(os.Getpid())  // プロセスID
    fmt.Println(os.Getppid()) // 親プロセスID
    fmt.Println(os.Getuid())  // ユーザーID
    fmt.Println(os.Geteuid()) // 実効ユーザーID
    fmt.Println(os.Getgid())  // グループID
    fmt.Println(os.Getegid()) // 実効グループID
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golang備忘録 Golangでdumpしたい。

はじめに

Golangを触り始めてよく使うプログラムの書き方を自分用に残すための備忘録。
どのような記述をしたらいいのか少しでもお役に立てればと思っています。
・これは随時、追加していきます。
また、いいコーディング方法があればご教授願います:bow:

プログラムの書き方

データを見る

phpでいうvar_dumpものがしたい時

sample.go
package main

import (
    "fmt"
)

type Person struct {
    family_name   string
    first_name string
}

func main(){
    Person := Person{family_name: "Yamada", first_name: "Taro"}
    fmt.Printf("%v\n", Person) // データの出力
    fmt.Printf("%+v\n", Person) // 内容にフィールド名も加えてデータの出力
    fmt.Printf("%#v\n", Person) // データをGoの構文で表現する
}
出力
1. {Yamada Taro} (%v)
2. {family_name:Yamada first_name:Taro} (%v+)
3. main.Person{family_name:"Yamada", first_name:"Taro"} (%v#)

2番、3番の形式で出力すると、データ構造がはっきりと分かり開発が捗りそう。

Coming Soon

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ニコニコのランキングからにじさんじ関連動画を簡単に集計する

計画の実行経緯

  1. 統計や数学的な知識が皆無な私でも何か分析し、グラフ化して気持ちよくなれないか数日ほど考えた結果、いつも見ているにじさんじ切り抜きあたりが題材に使えるかもしれないと閃きました。
  2. とりあえずタイトル通りの分析(笑)を目標に進めていくことに決めました。

環境

OS: macOS mojave 10.14.6
Go: go version go1.11.4 darwin/amd64

グラフ化によりわかること

何がわかるのでしょうか...。

ライバー別特定期間中にランキングに乗った関連動画の数の多さトップ10?

開発前に行った軽い考察

  • にじさんじメンバーの名前の取得

公式から取得します。

前に取得してもいいかrobots.txtの確認を行い、特にdisallowされてなかったので慎重に取得することに決定しました。

  • にじさんじメンバーの愛称の取得

現時点では自動化は不可能と判断しました。計画としては非公式WIKIからの取得案が存在しています。

  • ランキング情報の取得

RSS2.0形式で配布されているページランキングから取得します。

RSSで配布されているとはいえ、念の為robots.txtを確認しました。

  • タグの取得

可能ではある上に、タグでライバーの正式名称が登録されていることが多いので、愛称を取得する必要がなくなりますが、取得するRSSアイテムは100ほど存在し、それら一つ一つのURLをクローリングしていくのはいささか暴力的だと感じました(?)。というわけで現時点ではこの手段はしまっておくことにします。

ソースコードURL

nico-ranking-processing

英語ェ

ギリギリ300行超えてないことに加え、割と書き捨てな部分があるのでソースの分割はしませんでした。

実装で辛かった点・想定外だった点

go-chartでラベルが表示されない

wcharczuk/go-chart/tree/master/examples/bar_chart

ほぼサンプルのコード通りにコード書いたのにラベルが表示されませんでした。

ソースコードを見ても原因は特定できず、途方に暮れておりましたが、

色々探っているととあるSOFの記事に質問,回答にてふと気になるコードを見つけました。

        XAxis:    chart.StyleShow(),
        YAxis: chart.YAxis{
            Style: chart.StyleShow(),
            // TickStyle: chart.Style{
            //  TextRotationDegrees: 45.0,
            // },
            NameStyle: chart.Style{Show: true, TextRotationDegrees: 45.0},
        },

の部分です。XAxis:StyleShow()としています。

もしやと思いくみ入れてみるとxlabelが表示されました。

StyleShowやXAxisについては

bar_chart.goL29

style.goL19

等をみてなるほどとなりました。

go-chart日本語文字化け問題

化けます。fontを調整しても良かったのですが、macOSで調整しており、将来的にはサーバ(NixOS)で動作させようとしてるのでまた調整することに面倒臭さを感じてしまったのでライバー名はローマ字で生成することにしました。

では、そのローマ字はどうやって取得するのでしょうか?

もちろん、公式からです。

当初ローマ字文字列については各ライバーページから取得しようと思っておりましたが、

DOMをよく見なくても各ライバーページって最後がローマ字表記なんですよね(月ノ美兎)。

というわけで紹介ページから再度取得する処理を加えてことなきを得ました。

成果物

liver_cuts_top_10.png

9/28日に適当に取得したランキングCSVを元に生成してみました。

下の数字とか突然出現したCSVとか意味わかりませんね。

CSV

二種類あります。共にコマンドで生成できます。

liverNamesAndAlias.csv

ヘッダは

name,alias,romaji

となっており、それぞれ

name:ライバー名フル

alias:ライバー名フル+姓+名(一部未分割あり)

romaji:ライバー名ローマ字文字列

となっております。

romajiは別CSVに分割しようかと思いましたが、これ以上CSV増やすのかちょっと辛かったのでやめました。

作り直すときはDBで保存する予定です。

yyyy-DD-dd_hh : mm : ss.fff.csv

ヘッダは

title,link

となっており、それぞれ

title:順位:動画タイトル

link:動画url

となっております。

集計方法

指定したyyyy-DD-dd_hh : mm : ss.fff.csvのtitle全てをliverNamesAndAlias.csvのaliasと照合し、部分一致した場合カウントする。

例えば

2019-09-28_00:00:02.294.csv
2019-09-28_03:00:01.130.csv

という二つのファイルを読み込む場合、

ランキングが異なろうが、同じ動画が存在する場合に同じくカウントされてしまいます。

ランキング関係なしに集計してしまうのでここも修正が必要と感じます。

改善点

  • 関連するライバー全ての動画を対応づけすることができませんでした(精度が低い)。
  • csv運用は少し無理がありました。
  • 統計の基礎知識をもう少しつけるべきでした。
  • モンエナ飲みすぎて吐きそうになったのでもう少し控えるべきでした。
  • 杜撰な英語と日本語をどうにかしたかったです。

使用した標準外ライブラリ

github.com/PuerkitoBio/goquery
github.com/mmcdole/gofeed
github.com/urfave/cli
github.com/wcharczuk/go-chart

取得したWebページ等

Member – にじさんじ 公式サイト

エンターテイメントの動画ランキング(24時間) - ニコニコ動画

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む