メモ帳で職場のスクリーンセーバーを無効化する
職場のパソコンというものは、通常何らかのセキュリティが講じられています。例えば小職が前にいた会社では、5分おきに強制的にスクリーンセーバーがかかってしまい、ちょっと目を離した隙にPCがロックされる面倒が発生していました。理由があってのセキュリティではあるのは間違いないですが、それも度が過ぎると非効率の根源です。開発環境を自由に入れられない職場ですが、C#のコンパイラはWindows標準でついてくることが分かりましたので、暇つぶしにスクリーンセーバーを起動させないexeを調べながら作ってみました。
コンパイルのやりかた
C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /target:winexe C:\temp\ScreenSaverKiller.cs
ScreenSaverKiller.cs
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; namespace WindowsApplication1 { public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.Label label1; private System.Windows.Forms.Timer timer1; private System.Windows.Forms.Button button1; private System.ComponentModel.IContainer components; public Form1() { InitializeComponent(); } protected override void Dispose(bool disposing) { if (disposing) { if (components != null) { components.Dispose(); } } base.Dispose(disposing); } #region Windows Form Designer private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.label1 = new System.Windows.Forms.Label(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.button1 = new System.Windows.Forms.Button(); this.SuspendLayout(); this.label1.Font = new System.Drawing.Font("MS UI Gothic", 36F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(128))); this.label1.Location = new System.Drawing.Point(16, 16); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(384, 64); this.label1.TabIndex = 0; this.label1.Text = "label1"; this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.timer1.Enabled = true; this.timer1.Interval = 10; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); this.button1.Location = new System.Drawing.Point(109, 96); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(192, 32); this.button1.TabIndex = 1; this.button1.Text = "Move cursor to the center"; this.button1.Click += new System.EventHandler(this.button1_Click); this.AutoScaleBaseSize = new System.Drawing.Size(5, 12); this.ClientSize = new System.Drawing.Size(410, 144); this.Controls.Add(this.button1); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Name = "Form1"; this.Text = "ScreenSaverKiller"; this.ResumeLayout(false); } #endregion [STAThread] static void Main() { Application.Run(new Form1()); } private void timer1_Tick(object sender, System.EventArgs e) { Point pos = Cursor.Position; //Cursor.Position = new Point(pos.X + 1, pos.Y + 1); label1.Text = Control.MousePosition.ToString(); PreventScreenSaverFromStarting(); } private void button1_Click(object sender, System.EventArgs e) { int centerX = Screen.PrimaryScreen.Bounds.Right / 2; int centerY = Screen.PrimaryScreen.Bounds.Bottom / 2; Cursor.Position = new Point(centerX, centerY); } private void PreventScreenSaverFromStarting() { INPUT input = new INPUT(); input.type = INPUT_MOUSE; input.mi = new MOUSEINPUT(); input.mi.dwExtraInfo = IntPtr.Zero; input.mi.dx = 0; input.mi.dy = 0; input.mi.time = 0; input.mi.mouseData = 0; input.mi.dwFlags = 0x0001; //Move (Relative) int cbSize = Marshal.SizeOf(typeof(INPUT)); uint r = SendInput(1, ref input, cbSize); } #region Win32 API [StructLayout(LayoutKind.Sequential)] struct MOUSEINPUT { public int dx; public int dy; public uint mouseData; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } const int INPUT_MOUSE = 0; [StructLayout(LayoutKind.Sequential)] struct KEYBDINPUT { ushort wVk; ushort wScan; uint dwFlags; uint time; IntPtr dwExtraInfo; } [StructLayout(LayoutKind.Sequential)] struct HARDWAREINPUT { uint uMsg; ushort wParamL; ushort wParamH; } [StructLayout(LayoutKind.Explicit)] struct INPUT { [FieldOffset(0)] public int type; [FieldOffset(4)] public MOUSEINPUT mi; [FieldOffset(4)] public KEYBDINPUT ki; [FieldOffset(4)] public HARDWAREINPUT hi; } [DllImport("user32.dll", SetLastError = true)] static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize); [FlagsAttribute] public enum EXECUTION_STATE : uint { ES_SYSTEM_REQUIRED = 0x00000001, ES_DISPLAY_REQUIRED = 0x00000002, ES_CONTINUOUS = 0x80000000, } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags); #endregion } }
メモ帳でソースコード(ScreenSaverKiller.cs)をコピペし、適当な場所に保存。そしてコマンドプロンプトでcscを使ってコンパイルすれば、exeファイルが出来上がります。コンパイルが通らなかったらすみません。私の環境では一応動いてます。これで5分おきにマウスを動かさなくても良いですね!
node.js+Puppeteerによる動的ページのスクレイピング
最近のかっこいいWebとかだと、どういう仕組みかは分からないけど動的にデータが作られていて、htmlソースを見てもスクレイピングできないことがよくある。
西友のお墨付きブランドのページも、なかなか洗練されている(DeNAが作ったらしい?)。だけど商品情報をスクレイピングしようとしても、ソースコードには何も書いてないから、僕が得意な普通のVBAではうまくいかない。
西友 - プライベートブランド みなさまのお墨付き | SEIYU
あれこれ悩んで数か月、ようやく解決方法が見つかった。Puppeteerという、node.jsで動かせるChromeのヘッドレスブラウザを使うといい。これはすごくて、スクレイピング以外にもスクリーンショットなども取れる。
対象ページから抽出したいタグは、普通のChromeでInspectを選ぶことで見られると思う。node.jsはよく分からなかったけど、見よう見まねでDQNコードを作って一応動いている。非同期のところが癖があって難しかった。
はじめの一歩だから、多分すっごく汚いコードなんだろうけど、何個か作りながらnode.jsのこととかちゃんと理解できたらいいなと思う。
node.jsの最新バージョン(async対応)と、puppeteerが必要
node script.jsで実行
script.js
const fs = require('fs'); const assert = require('assert'); const puppeteer = require('puppeteer'); const len = 1500; const sequential = new Array(len) .fill(1) .map((n, i) => n + i); console.log(sequential.join(',')); loop(sequential); async function loop(v) { for (let n of v) { await hoge(n); } } async function hoge(n){ const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('http://●●.●●●●●.●●.jp/#item_' + n); console.log('http://●●.●●●●●.●●.jp/#item_' + n) //await page.screenshot({path: 'example.png'}); const Names = await page.evaluate(() => { var array = []; var el = document.querySelector('div.bdr') var node = el.querySelectorAll("p.name, p.price, p.area, div.dsc, div.rating"); for(item of node){ array.push(item.innerText); } return array; }); browser.close(); //assert(fs.existsSync('example.png')); fs.appendFile('writetest.txt', n + ',' + replaceElement(Names) + '\n', function (err) { //console.log(err); }); } function replaceElement(array) { for(var i=0; i<array.length; i++){ array[i] = array[i].replace(/\r?\n/g,""); } return array; }
俺の語彙数は推定8,000語だって
WeblioとTest your vocabの両方で試してみた。
Test you vocabだと7,810語。Weblioの方は何度やってもLevel 13~14(7001語~8000語 :特待生)で止まるから、結果は概ね正しいのだろう。Guessで回答しているのもあるし。これはネイティブの小学生低学年レベルといわれている。
ということは5年前に取った英検一級は殆どまぐれだったということになる(はっきりいって語彙パートは勘で5割くらい取れてしまう試験だった)。MBA留学していてこの語彙数はちょっと少ないよな。これまでずっと単語はないがしろにしてきたけど、本を読むのに時間がかかるとか知的な文章が書けなかったりして、最近すごい弊害を感じている。
年末までにボキャビルを少し頑張ってみようと思う。
VBAで手っ取り早くWebスクレイピング
某企業のインターンシップでプライベートブランドの研究をしたことがあり、前々からWebスクレイピングに興味があったので、例によってExcelのVBAで簡単なコードを書いて、セブンプレミアムの一覧表を作りました。セブンのWebページはURLが定型化(0~9999までのID)されており、普通にFor文をぶん回すという荒業で対応できます。要するにセブンのページに1万回アクセスするのがマクロの趣旨です。IDが不規則な場合には、まず商品一覧からID表をスクレイピングして、それをもとにもう一回内容を取りに行くという二段階になります。
1万回といった大量のアクセスを迷惑行為ととらえるかどうか。例えば2010年の岡崎図書館事件では、サーバーダウンが発生し作成者が逮捕され物議をかもしました(そののち起訴猶予処分)。私の見解としては、1万回程度のアクセスの単発実行であれば、スクリプトの作りにもよるが今どきのサーバーが落ちる可能性は薄いと考えています。クローリングという行為自体はグーグルやアマゾンのような大企業から、有象無象の個々人まで好き勝手にやっている現状であり、インターネットの自由空間では問題が無いと思います。しかしもしサーバーをダウンさせてしまうことになれば、たとえ法的な処罰を受けなくとも、誰かに迷惑をかけることになってしまいます。従って、以下ソースの利用は自己判断・自己責任で行ってください。以下のソースは、セブンに迷惑がかからないように、URLの一部をマスキングしています。
Excel VBAはどの会社でも使えるから最強の実行環境だと思います。でもソースも汚いし、VBAを沢山書いたからといってプログラマとしての成長にはつながりません。私はこれまで、あくまで事務職の立場から、以下にコピペ等で速く情報を処理できるかを考えてVBAを書いてきました。会社ではそういう態度を続けていくとして、プライベートではもう少し良い言語を学びたいものです。
セブンHDツールプレミアム.xlsm
Sub testIE2() Dim ws As Worksheet Dim i, j As Long Dim countURI, countNextClm As Integer Dim objIE As InternetExplorer 'IEオブジェクトを準備 Set objIE = CreateObject("Internetexplorer.Application") '新しいIEオブジェクトを作成してセット Dim el As IHTMLElement Dim htmlDoc As HTMLDocument 'HTMLドキュメントオブジェクトを準備 Dim colTitle, colTh, colTd, colData, colImg As IHTMLElementCollection 'IHTMLエレメントコレクションを準備 Set ws = ThisWorkbook.Worksheets("Sheet1") ws.Cells.Clear objIE.Visible = False 'IEを表示 countURI = 1 i = 1 For countURI = 0 To 9999 Debug.Print countURI objIE.navigate "https://********.jp/*******/search/detail?id=" & countURI 'IEでURLを開く Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE '読み込み待ち DoEvents Loop Set htmlDoc = objIE.document 'objIEで読み込まれているHTMLドキュメントをセット Set colTitle = htmlDoc.getElementsByClassName("headLine1 headLine1-line") Set colTh = htmlDoc.getElementsByClassName("itemDetail_td") Set colTd = htmlDoc.getElementsByClassName("tag color01") Set colData = htmlDoc.getElementsByClassName("itemDetail_leadsTxt") Set colImg = htmlDoc.getElementsByClassName("itemDetail_img") If colTh.Length = 0 Then GoTo Continue End If ws.Cells(i, 1).Value = countURI ws.Cells(i, 2).Value = colTd(0).innerText ws.Cells(i, 3).Value = colTitle(0).innerText ws.Cells(i, 4).Value = colImg(0).src ws.Cells(i, 5).Value = colData(0).innerText countNextClm = 6 For Each el In colTh ws.Cells(i, countNextClm).Value = "'" & el.innerText countNextClm = countNextClm + 1 Next el i = i + 1 Continue: Next End Sub
VBAでキー操作を送信する
※金融機関における重要書面確認は顧客の責任です。この記事に書いてあることは真似せず、必ず自分の目で確認してください!!
久々にSBI証券にログインしたら「重要なお知らせ」が溜まっていました。全部確認しないと取引できませんが、いかんせん200件近くあり、手で確認していたのでは日が暮れます。こんなものはどうせ読まないのでパソコンにやらせてしまうことにしました。
手段としてはいろいろ考えられます。比較的しっかりとしたものであればobjIEを使うのが良いのだと思うのですが、数分で作る使い捨てマクロには向きません。今回はSendKeysを使って実現することにしました。やや頼りない感じもしますが、IE以外の様々なアプリを操作することができるので、覚えておいて損はないのでしょう。
なおSendKeysの実行後、なぜかNumLockがオフになってしまいます。なんでなんでしょうね。
www.youtube.com
参考Office TANAKA - Excel VBAステートメント[SendKeysステートメント]
Sub Sample() Dim i As Integer Application.Wait [Now() + "0:00:05"] For i = 1 To 100 SendKeys "+{Tab 2}" SendKeys "{Enter}" Application.Wait [Now() + "0:00:02"] SendKeys "{Tab 5}" SendKeys "{Enter}" Application.Wait [Now() + "0:00:02"] Next i End Sub
VBSによるファイルダウンローダーの実現
企業内のPCでは往々にして自由なソフトウェアのインストールが禁じられています。その結果、例えばダウンローダーが入れられないため、URLは分かっているファイルを一括ダウンロードする術が無いということがあります(手作業で右クリック⇒保存をしていると日が暮れる数のファイル)。そこで当ブログでは、Windows機であれば環境問わず実行可能なスクリプト(VBS)で簡易的なダウンローダーの作成を行いました。ファイルの大量ダウンロードとかいう新入社員にありがちな糞な仕事を任せられたら、これでちゃっちゃと終わらせてしまいましょう。
使い方
(1)以下のソースファイル(myDownloader.vbs)と同じ階層に、boxという名前のフォルダとmyDownloadList.txtを作成する。
(2)myDownloadList.txt内に、ダウンロードしたいファイルのURLを1行ごとに列挙する。
(3)myDownloader.vbs を実行。するとbox内にファイルがダウンロードされて溜まっていく。
やっつけで調べながら作ったので、ソースが汚いのはご容赦ください。
暇があれば関数化して見やすく改良します。誰かしてください。
myDownloader.vbs
Dim objFSO Dim objFile Set objFSO = WScript.CreateObject("Scripting.FileSystemObject") If Err.Number = 0 Then Set objFile = objFSO.OpenTextFile("myDownloadList.txt") If Err.Number = 0 Then Do While objFile.AtEndOfStream <> True cReqURL = objFile.ReadLine Set objFileSystem = WScript.CreateObject("Scripting.FileSystemObject") Set objShell = WScript.CreateObject("WScript.Shell") Set objXmlHttp = WScript.CreateObject("MSXML2.XmlHttp") cFileName = objFileSystem.getFileName(cReqURL) cReqPath = objFileSystem.getParentFolderName(cReqURL) & "/" objXmlHttp.Open "GET", cReqPath & cFileName, False objXmlHttp.SetRequestHeader "Pragma", "no-cache" objXmlHttp.SetRequestHeader "Cache-Control", "no-cache" objXmlHttp.SetRequestHeader "If-Modified-Since", "Thu, 01 Jan 1970 00:00:00 GMT" objXmlHttp.Send intStatus = objXmlHttp.status If (intStatus <> 200) Then WScript.Echo "FAILED" & vbCrLf & vbCrLf & "HTTP status code is" & intStatus & vbCrLf & cFileName WScript.Quit End If Set objStream = WScript.CreateObject("ADODB.Stream") objStream.Open objStream.Type = 1 objStream.Write objXmlHttp.responseBody objStream.SaveToFile objShell.CurrentDirectory & "\box\" & cFileName, 2 objStream.Close Set objFileSystem = Nothing Set objStream = Nothing Set objXmlHttp = Nothing Loop objFile.Close Else WScript.Echo "File couldn't be opened: " & Err.Description End If Else WScript.Echo "Error: " & Err.Description End If Set objFile = Nothing Set objFSO = Nothing WScript.Echo "Successfully done." WScript.Quit
普通自動二輪教習 2-5, 2-6
2016/5/3
【2-5】前半は実車で1・2コースをまわり、後半はシミュレーター室に移動してケース教習。シミュレーターに乗って、交差点で危険なシチュエーションを疑似体験する。例えばトラックの陰に乗用車が隠れていて、あやうく激突してしまうシーンなど、シミュレーターとはいえヒヤッとした。二輪教習は路上に出ないだけに貴重な体験になったと思う。
【2-6】第二段階は思いのほかやることが無く、今回もひたすら1・2コースの走り込み。苦手としていた平均台も最近は割と走りとおせるようになって、多少自信がついてきている。あとは右左折前のライン取りなどの細かい部分はまだまだ弱いと指摘。最後に波状路を体験するが、いきなり立ち乗りでコース一周を指示され、のろのろとそのまま波状路へ。体験しただけでハイおしまいだったので、正直何か身についた感じはしませんでした。