golang : csv.Reader の "wrong number of fields in line" を無視する
Read()
を実行する前に FieldsPerRecord
を -1 に設定する。
reader := csv.NewReader(f) reader.Comma = '\t' reader.FieldsPerRecord = -1 // これ for { record, err := reader.Read() if err == io.EOF { break } if err != nil { return err } // 処理...
csv - The Go Programming Language の Reader の FieldsPerRecord の説明を参照。
golang : 固定長文字列出力フォーマット
%(文字数).(文字数)s
のような形で、最大精度と最小精度を指定する。.
の左側の数字の前に -
を付けると左詰め、付けないと右詰め。
// 例えば50文字(左詰め)で固定。 fixedLengthString = fmt.Sprintf("%-50.50s", s)
gcloud : ERROR: (gcloud.auth.git-helper) Invalid input line format: [path=].
gcloud source repos clone (リポジトリ名) --project=(プロジェクト名)
で Google Cloud Platform 上のソースコードをクローンしようとしたときに発生。
ERROR: (gcloud.auth.git-helper) Invalid input line format: [path=]. fatal: remote error:
解決方法
git config --system --unset credential.helper
の実行で解決。
ただし
error: could not lock config file C:\Program Files\Git\mingw64/etc/gitconfig: Permission denied
と初回実行時には出ていたので、該当のフォルダ(C:\Program Files\Git\mingw64/)を右クリック → プロパティ → セキュリティでアクセス許可を編集する必要があった。
参考
Robobrowser + α によるスクレイピングの忘備録
Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド-』を読んでしばらく Robobrowser を使ってみようと思うので、その忘備録。
基本
browser = RoboBrowser( parser='html.parser', # Cookie が使用できないと表示されてログインできない問題を回避するため、通常のブラウザの User-Agent を使う。 user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:45.0) Gecho/20100101 Firefox/45.0)' ) broswer.open(スクレイピング対象のページのURL) # 取得したページの中身の確認。デバッグ時以外は不要。 # print(broswer.parsed)
user_agent の指定はサイトによっては不要。少なくとも Amazon.co.jp については必要(設定しない状態で open すると、取得できる html で Cookie を有効にして下さい、という旨のメッセージが入っていることがわかる)。
以降のコード例は基本的に上記の続きで broswer が Robobrowser インスタンスを表すものとする。
CSSセレクターを使った要素の取得
select
関数で CSSセレクターを使用可能。条件に一致する要素の配列が取得できる。
条件を指定して要素を取得する関数としては find_all
関数も利用できるので、好みで。find_all
の方が柔軟かもしれない。
実際に使用したことのある一部の例のみ記載。
探したい要素 | 書き方 | 例 |
---|---|---|
特定のクラスを持つ要素 | 要素.クラス | a.active |
特定の要素の子孫 | 要素 要素 | body h1 |
特定の要素の直接の子 | 要素 > 要素 | body > h1 |
特定のID属性 | #ID | #main |
属性が特定の値 | 要素[属性=“値”] | a[href=“/sample/index.html”] |
属性が特定の値で始まる | 要素[属性^=“値”] | span[id^=“itemPrice_” ] |
属性が特定の値で終わる | 要素[属性$=“値”] | img[src$=“.jpg” ] |
以下の例では g-item-details というクラスを持った div 要素を取得し、取得した各要素に更に select
を実行して必要な値を取得している
for item_info_element in browser.select('div.g-item-details'): title = item_info_element.select('a[id^="itemName_"]') assert len(title) == 1 # text でテキストを取得。 title = title[0].text.strip() # href 属性をキーにリンク先を取得 # 要 from urllib.parse import urljoin url = urljoin(browser.url, title[0]['href']) # URL の ref= 以降は不要。 url = item.url[:item.url.find('ref=')] price = item_info_element.select('span[id^="itemPrice_"]') # 必要な処理を続ける
特定のテキストを持ったリンク
get_link
関数の第一引数でテキストを指定する。取得したリンクを開くには follow_link
関数を使用する。
# この例ではリンク先(href の値)が特定の URL パターンに一致することも確認している sign_in_link = browser.get_link('サインイン', href=re.compile(r'https://www\.amazon\.co\.jp/ap/signin\?')) # assert sing_in_link is not None # browser.follow_link(sign_in_link)
フォーム
action をキーに get_form
関数を使って取得。
name 要素をキーに各入力欄にアクセスして値を設定し、submit_form
関数で実行
browser.follow_link(sign_in_link) form = browser.get_form(action='https://www.amazon.co.jp/ap/signin') if form is None: raise Exception('Failed to get signin link.') form['email'] = '.....@gmail.com' form['password'] = 'secret, of course!' browser.submit_form(form, headers={ 'Referer': browser.url, 'Accept-Language': 'ja,en-US;q=0.7;q=0.3' })
Amazon では Referer と Accept-Language の設定が必要。必要ないサイトもある。この辺りの必要性は実際に確かめるしか無い?
関数のリトライ設定
Retrying パッケージを使用して、関数に @retry デコレータを使用する
@retry(stop_max_attempt_number=3, wait_exponential_multiplier=1000) def signin() -> RoboBrowser: # 処理に失敗した場合は raise Exception('失敗の理由') などで例外を発生させる
golang : eval (数式の evaluation)を行う
go/token パッケージ、go/types パッケージ、go/constant パッケージを使用します。
import ( "fmt" "go/token" "go/types" "go/constant" ) fs := token.NewFileSet() tv, err := types.Eval(fs, nil, token.NoPos, "1 + 2 * 3 % 4") if err != nil { fmt.Println(err) return } val, ok := constant.Int64Val(tv.Value) if !ok { fmt.Println("Failed to get Int64Val") return } fmt.Println(val) // 結果は 3。
(Go 言語で プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問 をトライ中に 2問目を解くために方法を探しただけで、中身はあまりよくわかっていません。)
Angular2 : [ts] Property 'map' does not exist on type 'Observable<Response>'
http.get(url).map(...) を試みたところ発生。
[ts] Property 'map' does not exist on type 'Observable<Response>'
import rxjs/add/operator/map
を追加することで解決。
import {Observable} from 'rxjs/Observable'; import 'rxjs/add/operator/map';
catch には import 'rxjs/add/operator/catch';
が必要になる。
一括でインポートするには import 'rxjs/Rx';
。
golang : template の range で index を使う
以下の様なデータを template.Execute のデータに渡したとすると
type data struct { Values []string OtherValues []string }
テンプレートで
<ul> {{range $i, $v := .Values}} <li>{{index $.OtherValues $i}} のようにするとインデックスでアクセスできる( OtherValues[i]の値)。{{$v}} はもちろん Values[i]</li> {{end}} </ul>
のようにすれば、Values にループをかけている最中にインデックスを使って他の配列やスライスの特定の値にアクセスできる
template - The Go Programming Language に書いている通り、テンプレート中の {{index スライスや配列の変数 インデックス値}}
がソースコード中のスライスや配列の変数[インデックス値]
に対応する。
index Returns the result of indexing its first argument by the following arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each indexed item must be a map, slice, or array.
また、$
が Execution に渡されたデータを指すので、range 中にデータの他の変数にアクセスするには $.変数名
となる。