tailコマンドで、昨日(2020年6月24日)のスクリプトが止まったのでリカバリーする
止まるときもある
2020年6月24日の記事で10万行のURLリストと格闘しました。
kawahara-ci.hatenablog.com
ただ、インターネットは生もので運良く全て上手く行くわけはなく運が悪ければ通り止まります。
実際に止まりましてtail -f 出力ファイル
でも更新されなくなりました。
どうすれば良い?
止まっている行はps
で簡単にわかります。
12605 ttys001 0:00.75 curl -A "{$USER_AGENT}" --head http://にゃ~ん
この該当のURLを読み込みファイルでgrepします。
grep -n 'http://にゃ~ん' ./url.txt
43152:http://にゃ~ん
43152行目だとわかります。
次にCtrl-Cでスクリプトを止めます。
それから元のスクリプトを少々手直します。
ここで活躍するのがtail
コマンドです!
tail
コマンドはファイルの後ろから表示するコマンドで、デフォルトは最後の10行を表示します。
行数の指定も可能でtail -n 20 ファイル名
とすると最後の20行を表示します。(-20 と指定も可能)
今回の件はファイル全体の行数から止まった行数を引いた数だから100000 - 43152 = 56848
で、止まった行数も含みたいので、tail -n 56849 ファイル名
(確認のためにはtail -n 56849 ファイル名 |head
とするのが良い)と思うかもしれませんが、実はtail
コマンドには便利な技があります。
tail -n +43152 ファイル名 |head
としてみましょう、先程の計算結果での出力と同じ結果になりましたよね?
tail
コマンドでは+数値
でその行以降というやり方あります。
これでスクリプトを変更します。
#cat ./url.txt | while read line tail -n +43152 ./url.txt | while read line
変更したら、最後実行しましょう。
実行したけど実行が進まない場合は、43152行が無反応ってことなので、一行進めて43153行に変更しましょう。
これで再開できました、あとは放置するだけです。
余談ですが、止まったのは寝ているときだったので、5時間ぐらい無駄に過ぎました・・・。
止まったらAlertを投げる手もありますが、今回はリカバリー出来るだけでヨシ!とします。
意外と便利なcurlのwriteoutオプション(http_codeとurl_effectiveは便利過ぎる)
唐突にきた調査依頼
依頼主「ここにあるURLリストで正常にアクセスできると、URLが変わった物をリストアップしてほしい。」
私「はい、すぐに!お?10万件?スクリプトをサクッとやりますが、量が多いので実行に1日ぐらいかかります。」
できた物
#!/bin/bash USER_AGENT='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/601.1.39 (KHTML, like Gecko) Version/10.1.2 Safari/601.1.39' cat ./url.txt | while read old_url do code=`curl -A '"{$USER_AGENT}"' -s -o /dev/null -w '%{http_code}' ${old_url}` if [ `echo "${code}" | grep '30'` ]; then new_url=`curl -A '"{$USER_AGENT}"' -sL -o /dev/null -w '%{url_effective}' ${old_url}` printf '"%s","%s"\n' "${new_url}" "${old_url}" elif [ "${code}" = '200' ]; then printf '"%s",""\n' "${old_url}" else printf '"%s","error url"\n' "${old_url}" fi done
説明
url.txt
を読み込んで、whileループで回す。- curlのsilentオプションで、outputオプションは/dev/nullで捨てて、writeoutオプションのhttp_codeでHTTPステータスコードを取得する。
- HTTPステータスコードで300系ならば、再度curlのsilentオプションで、outputオプションは/dev/nullで捨てて、locationオプションを使って最終的にアクセスしたURLに遷移させ、writeoutオプションのurl_effectiveで遷移したURLを取得し、そのURLと元のURLを表示する。
- HTTPステータスコードで200ならば、URLをそのまま表示する。
便利なwriteoutオプション
curlのwriteoutオプションはときどき追加があります、そのためcurlのtool_writeout.c
ファイルは時々見ると新たな発見があったりします。
github.com
余談ですが、writeoutオプションには、みんなが大好きなjson
というのもあり、サイトを見るときに指定して意味なく情報を見るのが楽しいです。
実行コマンドです。
curl -s -o /dev/null -w '%{json}' https://www.google.co.jp/ | jq
実行結果です。
{ "url_effective": "https://www.google.co.jp/", "http_code": 200, "response_code": 200, "http_connect": 0, "time_total": 0.220751, "time_namelookup": 0.002085, "time_connect": 0.012867, "time_appconnect": 0.138509, "time_pretransfer": 0.138608, "time_starttransfer": 0.218738, "size_header": 938, "size_request": 80, "size_download": 12052, "size_upload": 0, "speed_download": 54781, "speed_upload": 0, "content_type": "text/html; charset=Shift_JIS", "num_connects": 1, "time_redirect": 0, "num_redirects": 0, "ssl_verify_result": 0, "proxy_ssl_verify_result": 0, "filename_effective": "/dev/null", "remote_ip": "2404:6800:4004:80d::2003", "remote_port": 443, "local_ip": "にゃ~ん", "local_port": にゃ~ん, "http_version": "1.1", "scheme": "HTTPS" }
あれ?Googleのサイトでcontent_type
が懐かしのShift_JIS
だ!?
"content_type": "text/html; charset=Shift_JIS"
こんなcontent_type
を返すのは変だな、よし!試しにUser Agentを付加してやってみよう!
curl -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/601.1.39 (KHTML, like Gecko) Version/10.1.2 Safari/601.1.3 9' -s -o /dev/null -w '%{json}' https://www.google.co.jp/ | jq
実行結果です。
{ "url_effective": "https://www.google.co.jp/", "http_code": 200, "response_code": 200, "http_connect": 0, "time_total": 0.324704, "time_namelookup": 0.004633, "time_connect": 0.015616, "time_appconnect": 0.168842, "time_pretransfer": 0.168961, "time_starttransfer": 0.280845, "size_header": 1017, "size_request": 186, "size_download": 188613, "size_upload": 0, "speed_download": 582138, "speed_upload": 0, "content_type": "text/html; charset=UTF-8", "num_connects": 1, "time_redirect": 0, "num_redirects": 0, "ssl_verify_result": 0, "proxy_ssl_verify_result": 0, "filename_effective": "/dev/null", "remote_ip": "2404:6800:4004:80b::2003", "remote_port": 443, "local_ip": "にゃ~ん", "local_port": にゃ~ん, "http_version": "1.1", "scheme": "HTTPS" }
変わった!content_type
がUTF-8
になりました。
"content_type": "text/html; charset=UTF-8"
これは私の推測ですが、Googleの日本サイトはガラケー全盛期に登場しているので、そのときの名残りかな?と思います。
こういう色々な発見があるのでcurlは楽しいです。
長いURLに対して Scrapy するときの覚書
結論
Scrapy で長いURLを対象にするときは、設定ファイルのsettings.py
にURLLENGTH_LIMIT
を書いてURLの最大長を記載する。
自分がやったときはURLの長さが3,800文字だったので、4,000文字に設定した。
# URL LENGTH URLLENGTH_LIMIT = 4000
ログレベルについて
あるサイトを対象にScrapyしてたとき、次のページを取らないというバグが発生する。
ログを眺めているとDEBUGの文字とともにURLが長いからリンクを無視と出ている。
[scrapy.spidermiddlewares.urllength] DEBUG: Ignoring link (url length > 2083): 対象URL
いや、気付けたから良いのですが、URLを無視するのはdebug
では無いと思っております。
私の考えですがdebug
は開発時に使うもので、本番リリースするときは全て取り除いてほしいので、今回の件はwarning
辺りに記載してほしいなと思いました。
warning
なんて見ない!という考え方もありますが、その場合はinfo
でもerror
でもかまいませんけど、今回の件ではdebug
では無いかなーと思います。
msmtp を使う
概要
過去記事やQiitaの記事で使用したmsmtp
は普通に便利なのでご紹介します。
過去記事 kawahara-ci.hatenablog.com
Qiitaの記事 qiita.com
ローカル開発環境でメール送信するという需要は少ないとは思いますが、知っていて損はないので記事を書きました。
これをDockerに展開することも可能です。
インストールして設定する
brew install msmtp
Windowsだと・・・ごめん、わからない。
インストールが終わったら設定します。
~/.msmtprc
に外部メールサーバーの設定をします。
みんなが大好きな Gmailの設定例を書きます。
host smtp.gmail.com port 587 user 使用するGmailアカウント password アプリパスワード from 使用するGmailアカウント tls on tls_starttls on tls_certcheck off auth on logfile ~/.msmtp.log
ここで重要なのはアプリパスワードです。
Gmailを外部メールサーバーとして使うためには、アプリパスワードを設定します。
アプリパスワードを使用するには2段階認証プロセスを有効にしないと使用できません。
まあ、エンジニアなら2段階認証プロセスを有効にしていると思うので、アプリパスワードの説明だけです。
アプリパスワードの設定はマイアカウントのセキュリティから設定します。
アプリパスワードを押下するとパスワード生成画面に遷移します。
アプリを選択、デバイスを選択の項目は、備忘録みたいなものなので、適当で良いです。
入力したら「生成」を押下します。
アプリパスワードが生成されました。(このアプリパスワードは破棄済み)
このアプリパスワードを先程の~/.msmtprc
に設定します。
使ってみる
過去記事やQiitaの記事を参考にどうぞ!
過去記事 kawahara-ci.hatenablog.com
Qiitaの記事 qiita.com
せっかくなのでPerlでもやってみましょう!
パイプでやればいけます。
下記サンプルでファイルを作りperl msmtp.pl
とか実行するとメールが送信されます。
#!/usr/bin/perl if (! open($mail, "| /usr/local/bin/msmtp -t")) { print "msmtp が無いです。¥n"; exit; } $mailtext = << "EOM"; From: sample\@sample.com To: sample\@sample.com Subject: test test EOM print $mail $mailtext; close $mail; exit;
なおPHPでもパイプで送信可能ですが、PHPならsendmail_pathを設定すればOKです。
使い終わったら
アプリパスワードが不要になったら削除しましょう。
ゴミ箱のアイコンを押下すると、確認ダイアログ無しで、速攻で削除されます。
Gmail アプリがダークモードに対応したのでCSSのprefers-color-schemeで試してみるが・・・
結論
Gmail アプリがダークモードに対応しました。
HTMLメールを受信するとどうなるか確認してみました。
結論から言うとダークモード判定に使うprefers-color-schemeは無視されます!!
Gmailアプリ iPhone版 バージョン 6.0.200412 で確認しました。
msmtpについてはこちらの記事をごらんください。
kawahara-ci.hatenablog.com
Media Queriesで試す
とりあえずダークモードとは関係ないけど、Media Queriesに反応するかということで、画面サイズで色が変わることを確認する。
HTMLメールをコマンドで送信します。
cat t1.txt | msmtp -t
t1.txt ファイルの中身です。
From: "test1" <sample@sample.com> To: sample@sample.com Subject: test1 Content-Type: text/html <html> <head> <meta http-equiv="content-type" charset="utf-8"> <style> @media (max-width: 768px) { .test1 { color: #f0f; } } @media (min-width: 769px) { .test1 { color: #0ff; } } </style> </head> <body> <h1 class="test1">テストメール</h1> </body> </html>
想定では #f0f で表示されると思います。
メールを開いてからダークモードとライトモードの切り替えをしてみます。
Media Queriesで試すのライトモード
Media Queriesで試すのダークモード
ライトモードもダークモードもmax-width: 768pxで指定された #f0f が表示されました。
ちなみにGmailアプリではダークモードのときメールの文面だけをライトモード(ライトテーマ)に変更して表示するモードがあります。(逆のパターンは無いです)
右メニューに「ライトテーマで表示」があります。
文面だけライトモードで表示されました。
prefers-color-schemで試す1
ダークモードの切り替えはprefers-color-schem
を使用します。
prefers-color-schem
を使用したHTMLファイルを添付してメールします。
その添付したファイルを読んでダークモードとライトモードの切り替えをしてみます。
t.html ファイルの中身です。
<html> <head> <meta http-equiv="content-type" charset="utf-8"> <style> @media (prefers-color-scheme: light) { .test2 { color: #f0f; } } @media (prefers-color-scheme: dark) { .test2 { color: #0ff; } } </style> </head> <body> <h1 class="test2">テストメール</h1> </body> </html>
想定ではライトモードでは #f0f で表示で、ダークモードでは #0ff で表示だと思います。
prefers-color-schemで試す1のライトモード
prefers-color-schemで試す1のダークモード
想定通りライトモードでは #f0f で表示で、ダークモードでは #0ff で表示されました。
prefers-color-schemで試す2
HTMLメールで色が変わることを確認する。
t.htmlファイルに送信先を追加してt2.txt ファイルを作成します。
そのHTMLメールをコマンドで送信します。
cat t2.txt | msmtp -t
t2.txt ファイルの中身です。
From: "test2" <sample@sample.com> To: sample@sample.com Subject: test2 Content-Type: text/html <html> <head> <meta http-equiv="content-type" charset="utf-8"> <style> @media (prefers-color-scheme: light) { .test2 { color: #f0f; } } @media (prefers-color-scheme: dark) { .test2 { color: #0ff; } } </style> </head> <body> <h1 class="test2">テストメール</h1> </body> </html>
想定ではライトモードでは #f0f で表示で、ダークモードでは #0ff で表示だと思いますが・・・。
メールを開いてからダークモードとライトモードの切り替えをしてみます。
prefers-color-schemで試す2のライトモード
prefers-color-schemで試す2のダークモード
ライトモードでは #000 で表示で、ダークモードでは #fff で表示されました。
残念ながらGmailアプリではprefers-color-schemeは無視されるようです。
無視されるのはGmailアプリでライトテーマ表示があるからと推測しております。
上記のメールをダークモードで起動して、Gmailアプリのライトテーマ表示をすると、こんな感じで表示されます。