Google Apps ScriptでGmailからデータを取得して仕事を楽にした
Pythonをやり始めたはずなのに、GASを触っています。
概要:希望者のメルアドリストを作る
ある新商品があって、お客様にお届けするタイミングで、希望者に使い方メールを送ってよりよく活用してもらおう。
という企画がある。ボカして書いているので「そもそも希望者だけでなく全員に送れば」とかその手の指摘はおいておきますぞ。
プログラマに頼んでシステム化するほどではないのですが、人間がやるとめんどくさい。
状況はこんな感じ。
通常の処理フロー
- お客さんのリクエストメールをチェックし、希望の有無を目視確認
- 希望者がいれば、お客様名をシステムで検索し、ID番号をコピーし、希望者リストのエクセルにコピー
- 2で作った希望者リストのID表を元にし、別部署の処理済リストを確認。商品の送付日をチェックし、お客様ID別に送付開始日をチェック
- 送付開始日ごとに「●月●日に送るメアドリスト」みたいなのを作り、メール送信ツールに入れる
たまり続ける希望者リストには、お客さんと連絡がつかずそのままになるものもある。
でも、ある日突然、連絡がついて送信がスタートするかもしれない。つまり、毎日リストを目視でチェックし続けないといけない。地獄のような仕事である。
唯一の救いはメール
複数の社内ツールを使いながら処理するのですが、それらのデータを連動させるシステムを作るのは大変。お試し企画なので、時間も手間ももったいない。
唯一の救いは、各システムの処理時にメールをかませていること。(イケてる会社たちが使っている slack なんてものは誰も使っていない。)
ということで、Gmailからデータをぶっこ抜いてスプレッドシートに情報をまとめられるようにした。
GASでできるようにしたことのビフォーアフター
BEFORE:
お客さんからのリクエストメールをチェックし、希望の有無を目視確認
AFTER:
GASが定期的にリクエストメールをチェックし、希望の有無をGASで抜き出しスプレッドシートの「希望の有無」欄に転記
BEFORE:
希望者がいれば、お客様名をシステムで検索し、ID番号をコピーし、希望者リストのエクセルにコピー。2で作った希望者リストのID表を元にし、別部署の処理済リストを確認。商品の送付日をチェックし、お客様ID別に送付開始日をチェック
AFTER:
別部署が処理完了時に社内システムでメールで「処理済みです」的なメールを流していることに目をつけ、自分にも流してもらうことに。
このメールにお客さんへの商品到着日、メールアドレスが記載されていた。GASでそこからデータを取得。
これも定期的に実行するようにした。
以上。
てな具合です。これで作業が超楽ちんになった。
感想:正規表現とreplaceに迷った
正規表現の理解が難しかったけどその理解は進んだな、と。ただ使いこなしは全然。むずかしいけど超絶便利であることはよくわかった。
あと、replaceの処理が最初の1つしか変わらず「なぜ全部変わらないんだ!」と悶絶していた。これはすぐ忘れそうだけど。
そんなわけでメールからの情報取得で楽になりそうな作業は軒並みGASで自動化しています。
これは良い!!
ここでJavaScriptに興味を持ちまして、今はGoogleの拡張機能を作ってみたいな、なんて思い始めています。
Google Apps Scriptsはじめました
matplotlibでヒストグラム描画遅すぎるしグラフも変と思ったらラベル行のせいだった
仕事でヒストグラムを作成したい機会がやってきたので、これはPythonや!と意気揚々とデータを読み込んでみたところ、エラーが起きたりなんだかんだとしていてわかったことをメモしておこう。
matplotlibでヒストグラムを作ろうとしたけど、描画がくっそ遅い
ていうか終わらない。
10列×2000行 ⇒ NaNとかいうエラー(空白セルがダメぽ?)
2列×2000行 ⇒ 空白を全部消したけど終わらない
2列×10行 ⇒ 表示した
2列×10行くらいのデータならサクッとヒストグラムにしてくれる。
私がやりたかったのは最低でも1000以上あるデータの図示。
全然終わらないの。そんならExcelでやるわ、みたいな。
で、気付いたんですけど、なんかヒストグラムの表示自体もおかしい。
あれ?もしかして・・・というわけでラベル行を削除。すると、2列×2000行でもサクッと表示してくれました。数値だけ読み込んでくれたらいいのに・・・
と思いましたがまあいいか。
matplotlibを使うときはラベル行は消せ
これが今回の教訓。ちなみにやりたいの単純なカウントではなく複数条件を絡ませたヒストグラムの表示。
よーし、やるぞー!
メルカリで特定商品の売れてる価格帯を調べてヒストグラムとして表示を試みるも規約違反ぽい
スクレイピングもしたいけれど、Numpyとかも使ってみたい。
そんなことを思いながら時計がほしいなーっと思ってるとメルカリがでてきた。というわけでメルカリからデータを取ってくるというのを作ってみよう。
と思っていて作っていたところ、メルカリでは規約によってロボットとかでのアクセスは禁止しているそうな。なんかアプリみたいなのは作れないけど、以下のことはやった。
- キーワードを入れて検索結果から売り切れ済みのページへ
- コードのうち、値段に該当する箇所のみ抽出
- ¥マークとか 「, 」とかを削除
- 文字列データ扱いなのを数値データに変換
- Numpyと matplotlibでヒストグラムとして表示
みたいな風にやった。
本当はここからもっとも売れやすい時期とか、売れている価格帯とか、クリスマスの前後での4℃のアクセサリの出品数の変化とか知りたかったんだけどなあ。
サイト上にウンコを意味する言葉があったら、ブラウザ上でウンコの絵文字を浮遊させるPython
自分のパソコンでポチポチ動かすPythonも良いけれど、Chrome上とかで動く様子を作ってみたいなと。
他に考えているものはあるのだけど、一気にやろうとすると難しすぎて挫折しそうなのでまずはこれ。
ウンコブラウザ構想
サイト上にウンコを意味する言葉があったら、ブラウザ上でウンコの絵文字を浮遊させる
実用性はない。
調べてもよくわからないのが、ブラウザ上でウンコを踊らせること。Pythonでブラウザを動かすとかは出てくるけども。
Chromeなら拡張機能でやれば?というところでしょうが、拡張はJavaScriptみたいだし、私がやりたいのはPythonなのだ。JavaScriptは勉強してないからよくわからない。
ゆくゆくは、アプリ化して「ウンコブラウザ」みたいにして「ウンコ系ワードがあったら文字をウンコにして飛ばします」ってしたいんだ。Pythonで。
ウンコブラウザの進化系。実用的なもの
- Amazonのレビューからヤラセ判定プログラムを動かして、あったらドクロマークを表示する
- 商品一覧ページでヤラセレビュー率が高い商品にはドクロマークを載せる
みたいなのが欲しい。
Amazonがやる気になれば対応できそうなのにやらない(売れなくなるので)ので、自分でやっちゃおうじゃないかと。
Pythonでプログラミングをやろうと思った理由と継続のコツ
Pythonを勉強しはじめて約2ヶ月時点での記録。
Pythonでプログラミングをやろうと思った理由
忘れそうなのでメモしておく。
大学の頃(1999年頃)から興味はあり、プログラミング言語みたいな講義を受講したものの、最初の課題ですぐに挫折。以後、VisualBasicみたいなのをやろうとしたこともあった。本を読んでみては挫折。
みたいなのは出てきてもその先が続かない。
今思えばそもそも何がやりたいのかも明確ではなかったし「ハッカーみたいなのかっこいい」という中2病的思想だけが動機だったので、挫折しても仕方ない気がする。
Pythonに手をだした理由
で、約20年経った今、なぜPythonでまたプログラミングをやろうとしているのか。
仕事やプライベートでブログの記事を書くときに、ネットとか手元にある膨大なデータをラクに分類できないか、と考えていた。Excelの関数とかである程度はできたけどネット上からデータを取ってきて分析する、とか調べていると「Pythonでスクレイピング」みたいなのがいっぱいでてきた。
Pythonってよく聞くけど何だ?と調べると
みたいなのが出てきた。
AIやら機械学習には興味はあったし、やりたいことにマッチしてそうだな、ということはわかった。
いつもはココでやめてしまうのだけど、ひとまずやってみようとProgeteというオンライン講座みたいなのでPythonを触ってみた。「なんかイケそうだな」と思ったけど、全部の講座を受講するには月額で1,000円くらいかかった。(気がする)
オンライン講座についてもっと調べると、Udemyっては一度だけの買切りで講座がいつまでも見放題なことがわかった。定価が12,000円とか高かったけど、ちょうどセールをやっていて1,200円で申し込めた。
継続のコツ「金をかける」
過去の自分の性格からして、何が必要なのかはなんとなくわかっていた。
「継続して取り組むには先行投資することが必須」と。つまりは金をかけること。
ランニングするならイケてるランニングシューズを購入して「せっかくかっこいい靴買ったし走ろう」「スマートウォッチみたいなのを買ってランニングデータを取ろう」とお金をかけて気分を高めて継続してた。
というわけで、Pythonを継続するためにUdemyで2つほど講座を申し込んで見始めた。
Udemyを見始めてすぐ、「お勉強」に飽きて。
Udemyで申し込んで見始めたのはコレ。
https://www.udemy.com/python-beginner/
「Python 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイルを学び、実践的なアプリ開発の準備をする」と、なんかスゴそうでしょ?選んだのはレビューがいっぱい付いていたから。
最初に案内されていたPycharmとAnacondaをインストールして途中までみた。途中まで・・・といっても300近く項目があるうちの30項目ぽっち。なぜここで止まっているのか。
「お勉強」ばかりだと飽きるのですよ。というわけで、講座をみてなんとなくわかった気になったので、やりたいことを勝手にやり始めた。
Pythonでやってみたこと
次は、ウェブサイトのスクレイピングに手を出した。
- Googleの検索結果のタイトル抽出。
- URLを巡回してデータを取得。
- 取得したデータから特定のタグのみを抽出。
みたいなのを次々にやった。
ちゃんと動いて、結果がしっかり見える。
すぐに結果がよくわかるのが良い。
お勉強と実践のサイクルで飽きるのを防止+パワーアップ
お勉強→飽きる→なんか動くのを作る→もっと効率的に作れないか→お勉強→ほほう→やってみる→壁に当たる→お勉強しておこう→あ、あっちに使えるかも
みたいな感じでサイクルを回してる。
今のところは楽しい。
やっぱ動かしてみてすぐに結果がわかるってのが良いな。
存在しないURLをrequests.getで取得しようとしてエラー
問題:存在しないURLをrequests.getするとエラー
指定のページ内のソースからリンク先をピックアップして、
リダイレクト先をチェックしようとすると、謎エラーが発生。
エラー内容
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno 11001] getaddrinfo failed
self, "Failed to establish a new connection: %s" % e)
urllib3.exceptions.NewConnectionError: <urllib3.connection.VerifiedHTTPSConnection object at 0x00000241E7A1D240>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='y!', port=443): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x00000241E7A1D240>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='y!', port=443): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x00000241E7A1D240>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))
などなど盛りだくさん。
どうやら
みたいな変なURLに引っかかっているらしい。
というわけでテストする。
url = 'https://Y!'
res =requests.get(url)
で同じ感じのエラーになる。
解決策:try~exceptで無視する
status_codeで判別しようとしたけど、それもエラー。
他の対処方法を調べたけどよくわからないので、この手のエラーは無視して先に進むようにしよう。
闇に葬るようで気持ちが悪いけど根本的な解決策みたいなのがわからないのだ。
無視するということで調べると、try ~ exceptというのが使えそう。
url = 'https://Y!'
try :
res = requests.get(url)
except:
print('ng')
else:
print('hoka')
こんな感じにすればいけた。