19

拡張子が .pdf の出力ファイルを指定せずに、PhantomJS で PDF エクスポート機能をトリガーする方法はありますか? stdoutPDF出力に使用したいと思います。

4

4 に答える 4

20

一時ファイルを必要とせずに、stdout に直接出力できます。

page.render('/dev/stdout', { format: 'pdf' });

これが追加されたときの履歴については、こちらを参照してください。

標準入力から HTML を取得し、PDF を標準出力に出力する場合は、こちらを参照してください。

于 2013-06-24T18:30:14.897 に答える
19

非常に長い回答でごめんなさい。私は人生でこの方法を数十回参照する必要があると感じているので、「それらすべてを支配するための1つの答え」を書きます。まず、ファイル、ファイル記述子、(名前付き)パイプ、および出力リダイレクトについて少し説明してから、質問に答えます。


この単純なC99プログラムについて考えてみましょう。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{

  if (argc < 2) {
    printf("Usage: %s file_name\n", argv[0]);
    return 1;
  }

  FILE* file = fopen(argv[1], "w");
  if (!file) {
    printf("No such file: %s\n", argv[1]);
    return 2;
  }

  fprintf(file, "some text...");

  fclose(file); 

  return 0;
}

非常に簡単です。引数(ファイル名)を取り、それにテキストを出力します。これ以上簡単なことはありません。


clang write_to_file.c -o write_to_file.oまたはでコンパイルしgcc write_to_file.c -o write_to_file.oます。

次に、を実行します./write_to_file.o some_file(に出力されsome_fileます)。次に、を実行しcat some_fileます。結果は、予想通り、some text...

それでは、もっと凝ったものにしましょう。ターミナル(./write_to_file.o /dev/stdout) > some_fileに入力します。プログラムに(通常のファイルではなく)標準出力に書き込むように要求し、それstdoutsome_file(を使用して)にリダイレクトします> some_file。これを実現するために、次のいずれかを使用できます。

  • (./write_to_file.o /dev/stdout) > some_file、これは「使用stdout」を意味します

  • (./write_to_file.o /dev/stderr) 2> some_file、これは「を使用しstderr、を使用してリダイレクトする2>」ことを意味します

  • (./write_to_file.o /dev/fd/2) 2> some_file、これは上記と同じです。stderrデフォルトでUnixプロセスに割り当てられる3番目のファイル記述子です(stdinおよびの後stdout

  • (./write_to_file.o /dev/fd/5) 5> some_file、これは「6番目のファイル記述子を使用してリダイレクトする」ことを意味しsome_fileます

明確でない場合は、実際のファイルの代わりにUnixパイプを使用しています(結局のところ、すべてがUnixのファイルです)。このパイプを使用して、あらゆる種類の凝ったことを行うことができます。ファイルに書き込むか、名前付きパイプに書き込んで、異なるプロセス間で共有します。


それでは、名前付きパイプを作成しましょう。

mkfifo my_pipe

ここで入力ls -lすると、次のように表示されます。

total 32
prw-r--r--  1 pooriaazimi  staff     0 Jul 15 09:12 my_pipe
-rw-r--r--  1 pooriaazimi  staff   336 Jul 15 08:29 write_to_file.c
-rwxr-xr-x  1 pooriaazimi  staff  8832 Jul 15 08:34 write_to_file.o

2行目の先頭のpに注意してください。それはmy_pipe(名前付き)パイプであることを意味します。

次に、パイプで何をしたいかを指定しましょう。

gzip -c < my_pipe > out.gz &

つまりgzip、私が中に入れmy_pipeて結果をに書き込んだものですout.gz&最後に、はシェルにこのコマンドをバックグラウンドで実行するように要求します。次のようなものが表示[1] 10449され、コントロールがターミナルに戻ります。

次に、Cプログラムの出力をこのパイプにリダイレクトするだけです。

(./write_to_file.o /dev/fd/5) 5> my_pipe

または

./write_to_file.o my_pipe

あなたが得るでしょう

[1]+  Done                    gzip -c < my_pipe > out.gz

これは、gzipコマンドが終了したことを意味します。

今、別のことをしなさいls -l

total 40
prw-r--r--  1 pooriaazimi  staff     0 Jul 15 09:14 my_pipe
-rw-r--r--  1 pooriaazimi  staff    32 Jul 15 09:14 out.gz
-rw-r--r--  1 pooriaazimi  staff   336 Jul 15 08:29 write_to_file.c
-rwxr-xr-x  1 pooriaazimi  staff  8832 Jul 15 08:34 write_to_file.o

gzipテキストの編集に成功しました。

実行gzip -d out.gzして、このgzipedファイルを解凍します。削除され、新しいファイル(out)が作成されます。cat out私たちを取得します:

some text...

それが私たちが期待したことです。

rm my_pipeパイプを!で取り外すことを忘れないでください。


PhantomJSに戻ります。

render.coffeeこれは、URLとファイル名の2つの引数を取る単純なPhantomJSスクリプト( CoffeeScriptで記述)です。URLをロードしてレンダリングし、指定されたファイル名に書き込みます。

system = require 'system'

renderUrlToFile = (url, file, callback) ->
  page = require('webpage').create()
  page.viewportSize = { width: 1024, height : 800 }
  page.settings.userAgent = 'Phantom.js bot'

  page.open url, (status) ->
    if status isnt 'success'
      console.log "Unable to render '#{url}'"
    else
      page.render file

    delete page
    callback url, file


url         = system.args[1]
file_name   = system.args[2]

console.log "Will render to #{file_name}"
renderUrlToFile "http://#{url}", file_name, (url, file) ->
  console.log "Rendered '#{url}' to '#{file}'"
  phantom.exit()

次に、ターミナルに入力phantomjs render.coffee news.ycombinator.com hn.pngして、HackerNewsのフロントページをファイルにレンダリングしますhn.png。期待どおりに動作します。ですphantomjs render.coffee news.ycombinator.com hn.pdf

以前にCプログラムで行ったことを繰り返しましょう。

(phantomjs render.coffee news.ycombinator.com /dev/fd/5) 5> hn.pdf

それは動作しません...:(なぜですか?なぜなら、PhantomJSのマニュアルに記載されているように:

render(fileName)

Webページを画像バッファにレンダリングし、指定されたファイルとして保存します。

現在、出力形式はファイル拡張子に基づいて自動的に設定されます。サポートされている形式は、PNG、JPEG、およびPDFです。

失敗するのは、単に、などで終わら/dev/fd/2ないからです。/dev/stdout.PNG

しかし、恐れることはありません。名前付きパイプが役に立ちます。

別の名前付きパイプを作成しますが、今回は拡張子を使用します.pdf

mkfifo my_pipe.pdf

さて、それを単にcatそのインアウトに伝えてくださいhn.pdf

cat < my_pipe.pdf > hn.pdf &

次に、以下を実行します。

phantomjs render.coffee news.ycombinator.com my_pipe.pdf 

そして、美しいものを見よhn.pdf

明らかに、出力を実行するだけでなく、より洗練された何かを実行したいのですcatが、今、何をすべきかが明確になっていると確信しています:)


TL; DR:

  1. 「.pdf」ファイル拡張子を使用して名前付きパイプを作成します(したがって、PhantomJSをだましてPDFファイルだと思い込ませます)。

    mkfifo my_pipe.pdf
    
  2. 次のように、ファイルの内容でやりたいことは何でもします。

    cat < my_pipe.pdf > hn.pdf
    

    catこれは単にhn.pdf

  3. PhantomJSで、このファイル/パイプにレンダリングします。

  4. 後で、パイプを削除する必要があります。

    rm my_pipe.pdf
    
于 2012-07-15T05:19:35.220 に答える
14

Niko が指摘したrenderBase64()ように、Web ページをイメージ バッファにレンダリングし、結果を base64 でエンコードされた文字列として返すために使用できます。
ただし、現時点では、これは PNG、JPEG、および GIF でのみ機能します。

phantomjs スクリプトから stdout に何かを書き込むには、ファイルシステム API を使用するだけです。

画像には次のようなものを使用します:

var base64image = page.renderBase64('PNG');
var fs = require("fs");
fs.write("/dev/stdout", base64image, "w");

renderBase64()のPDF形式がphanthomjsの将来のバージョンに含まれるかどうかはわかりませんが、回避策として、これらの行に沿った何かがうまくいくかもしれません:

page.render(output);
var fs = require("fs");
var pdf = fs.read(output);
fs.write("/dev/stdout", pdf, "w");
fs.remove(output);

outputPDFファイルへのパスはどこにありますか。

于 2012-07-16T15:58:16.747 に答える
2

それがあなたの問題に対処するかどうかはわかりませんが、renderBase64()PhantomJS 1.6 に追加された新しいメソッドを確認することもできます: https://github.com/ariya/phantomjs/blob/master/src/webpage.cpp#L623

残念ながら、この機能はまだ wiki に記載されていません :/

于 2012-07-15T09:07:24.607 に答える