使用 cron 在 Mac OS X 上进行屏幕捕获

使用 cron 在 Mac OS X 上进行屏幕捕获

为了分析我自己的计算机使用情况,而不是监视任何人(尽管我曾想过),我想让 cron 每分钟捕获一次当前屏幕。

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

在 crontab 中将执行并进行屏幕截图。但是,它完全是黑色的,因为它没有以我的身份运行。知道如何允许 cron 作业捕获我的屏幕吗?

更新:我say whoami在同一个 cron 命令中添加了 a,它确认它以我的用户身份运行(不涉及 sudo 或其他用户)。我以自己的身份从终端访问 crontab。

因此,它以我的身份运行,但未附加到我的窗口系统。有什么想法吗?

答案1

如果你看一下屏幕截图手册页的末尾,你会看到这样写着:

要在通过 ssh 登录时捕获屏幕内容,您必须启动
与 loginwindow 相同的 mach bootstrap 层次结构中的屏幕截图:

PID=loginwindow的pid
sudo launchctl bsexec $PID 屏幕截图 [选项]

因此我认为你可以在 cron 调用的 shell 脚本中做类似这样的事情:

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

当然,你需要将你的用户 ID 设置为不需要 sudo 密码。
即你需要使用 visudo 命令在 /etc/sudoers 中设置

你的用户 ID ALL=(全部) NOPASSWD: 全部

答案2

如果您不想让您的用户帐户拥有 sudo 权限(因为您担心安全问题),您可以使用 applescript 来解决这个问题。在我的例子中,我间接使用 screencapture 作为另一个程序的一部分,因此我将其转换为此处的示例,以直接使用 screencapture,就像 OP 所做的那样。

这是每天上午 8:11 执行的 cron 任务:

11 8 * * * /opt/myprogram/daily_cron.sh > daily_cron_output.txt 2>&1'

每日计划命令:

osascript -e 'tell app "Terminal"
    do script "/usr/sbin/screencapture /somedir/screen.png > daily_output.txt 2>&1 && exit"
end tell'

> daily_output.txt 2>&1如果您不希望从调用的程序中得到任何输出(如屏幕捕获),则可以省略该位。&& exit完成后,会显示关闭终端窗口。如果运行后终端未关闭exit,请检查首选项->设置->配置文件->Shell 并检查When the shell exits设置。

终端 shell 退出设置

第一次通过 cron 执行程序时,可能会弹出一个窗口要求您提供权限,您必须接受。因此,请在您坐在那里时第一次运行 cron 作业。

答案3

如果您要使用sudo设置cron另一个帐户,则可以将-u开关与 一起使用sudo

例子:

sudo -u Your_user crontab -e

否则只需登录该帐户并使用crontab -e

答案4

另外,我也用 Java 做同样的工作。它在开机时启动,我在一天结束时查看图像。

/**
 * 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;
    }
}

相关内容