web-dev-qa-db-ja.com

Mac OSXでの画面キャプチャにcronを使用する

自分のコンピューターの使用状況を分析するために、誰かをスパイするのではなく(頭に浮かんだのですが)、cronに現在の画面を毎分キャプチャさせたいと思います。

 * * * * * /bin/bash -c "/usr/sbin/screencapture /somedir/screen.png"

crontabで実行され、画面キャプチャが取得されます。しかし、私と同じように動いていないので、真っ黒です。 cronジョブが私の画面をキャプチャできるようにする方法はありますか?

更新:同じcronコマンドにsay whoamiを追加しました。これにより、ユーザーとして実行されていることが確認されます(Sudoや他のユーザーは関与していません)。私は自分自身としてターミナルからcrontabにアクセスします。

したがって、それは私として実行されますが、私のウィンドウシステムには接続されていません。何か案は?

7
physicsmichael

スクリーンキャプチャのマンページの最後を見ると、次のように書かれていることがわかります。

 ssh経由でログインしているときに画面コンテンツをキャプチャするには、
 screencaptureを同じマッハで起動する必要がありますbootstrap loginwindow:
 
 PID = pid of loginwindow 
 Sudo launchctl bsexec $ PID screencapture [options] 

したがって、cronが呼び出すシェルスクリプトで次のようなことを行うことができると思います。

#/ bin/sh 
 loginwindowpid = `ps axo pid、comm | grep '[l] oginwindow' | sed -n's#* \([^] * \)。* $#\ 1#p '`
 Sudo launchctl bsexec $ loginwindowpid screencapture /somedir/screen.png

もちろん、Sudoのパスワードを必要としないようにユーザーIDを設定する必要があります。
つまり、visudoコマンドを使用して/ etc/sudoersに設定します

 youruserid ALL =(ALL)NOPASSWD:ALL 
10
todbot

余談ですが、同じジョブにJavaを使用します。起動時に開始し、1日の終わりに画像を確認します。

/**
 * Code modified from code given in http://whileonefork.blogspot.co.uk/2011/02/Java-multi-monitor-screenshots.html following a SE question at  
 * http://stackoverflow.com/questions/10042086/screen-capture-in-Java-not-capturing-whole-screen and then modified by a code review at http://codereview.stackexchange.com/questions/10783/Java-screengrab
 */
package com.tmc.personal;

import Java.awt.AWTException;
import Java.awt.GraphicsDevice;
import Java.awt.GraphicsEnvironment;
import Java.awt.Rectangle;
import Java.awt.Robot;
import Java.awt.image.BufferedImage;
import Java.io.File;
import Java.io.IOException;
import Java.text.DateFormat;
import Java.text.SimpleDateFormat;
import Java.util.Date;
import Java.util.TimeZone;
import Java.util.concurrent.TimeUnit;

import javax.imageio.ImageIO;

class ScreenCapture {

    static int minsBetweenScreenshots = 5;

    public static void main(String args[]) {
        int indexOfPicture = 1000;// should be only used for naming file...
        while (true) {
            takeScreenshot("ScreenCapture" + indexOfPicture++);
            try {
                TimeUnit.MINUTES.sleep(minsBetweenScreenshots);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //from http://www.coderanch.com/t/409980/Java/java/append-file-timestamp
    private  final static String getDateTime()
    {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd_hh:mm:ss");
        df.setTimeZone(TimeZone.getTimeZone("PST"));
        return df.format(new Date());
    }

    public static void takeScreenshot(String filename) {
        Rectangle allScreenBounds = getAllScreenBounds();
        Robot robot;
        try {
            robot = new Robot();
            BufferedImage screenShot = robot.createScreenCapture(allScreenBounds);
            ImageIO.write(screenShot, "jpg", new File(filename + getDateTime()+ ".jpg"));
        } catch (AWTException e) {
            System.err.println("Something went wrong starting the robot");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Something went wrong writing files");
            e.printStackTrace();
        }
    }

    /**
     * Okay so all we have to do here is find the screen with the lowest x, the
     * screen with the lowest y, the screen with the higtest value of X+ width
     * and the screen with the highest value of Y+height
     * 
     * @return A rectangle that covers the all screens that might be nearby...
     */
    private static Rectangle getAllScreenBounds() {
        Rectangle allScreenBounds = new Rectangle();
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice[] screens = ge.getScreenDevices();

        int farx = 0;
        int fary = 0;
        for (GraphicsDevice screen : screens) {
            Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();
            // finding the one corner
            if (allScreenBounds.x > screenBounds.x) {
                allScreenBounds.x = screenBounds.x;
            }
            if (allScreenBounds.y > screenBounds.y) {
                allScreenBounds.y = screenBounds.y;
            }
            // finding the other corner
            if (farx < (screenBounds.x + screenBounds.width)) {
                farx = screenBounds.x + screenBounds.width;
            }
            if (fary < (screenBounds.y + screenBounds.height)) {
                fary = screenBounds.y + screenBounds.height;
            }
            allScreenBounds.width = farx - allScreenBounds.x;
            allScreenBounds.height = fary - allScreenBounds.y;
        }
        return allScreenBounds;
    }
}
0
Joe

Sudoを使用して別のアカウントのcronを設定する場合は、Sudoと一緒に-uスイッチを使用できます。

例:

Sudo -u Your_user crontab -e

それ以外の場合は、そのアカウントにログインしてcrontab -eを使用してください。

0
John T