通过 TIKA REST 上传 Word 文件以提取文本

Upload Word File to extract Text via TIKA REST

我正在尝试通过他们的 REST API 调用 Apache-TIKA。我已经能够通过 CURL

成功上传 PDF 文档和 return 文档的文本

curl -X PUT --data-binary @<filename>.pdf http://localhost:9998/tika --header "Content-type: application/pdf"

像这样翻译成 INDY:

function GetPDFText(const FileName: String): String;
var
  IdHTTP:  TIdHTTP;
  Params: TIdMultiPartFormDataStream;
begin
  IdHTTP := TIdTTP.Create;
  try
    Params := TIdMultiPartFormDataStream.Create;
    try
      Params.Add('file', FileName, 'application/pdf')
      Result := IdHTTP.PUT('http://localhost:9998/tika', Params);
    finally
      Params.Free;
    end;    
  finally
    IdHTTP.Free;
  end;
end;

现在我要上传word文档(.docx) 我假设我需要做的就是在将文件添加到 Params 时更改内容类型,但这似乎没有产生任何结果,尽管我没有收到任何错误报告。我能够让以下 CURL 命令正常工作

CURL -T <myDOCXfile>.docx http://localhost:9998/tika --header "Content-type: application/vnd.openxmlformats-officedocument.wordprocessingml.document"

如何将我的 HTTP 调用从 CURL -X PUT 修改为 CURL -T?

您的实施中至少存在两个问题:

  1. 您从 CURL -X PUTTIdHTTP 的翻译是错误的。
  2. 您没有指定 Accept HTTP header 来检索特定格式的提取文本。

如何将 curl -X PUT 翻译成 Indy?

首先,让我们弄清楚 curl -X PUT --data-binary @<filename> <url>curl -T <filename> <url> 是一样的,当:

  • <url>的方案是HTTPHTTPS
  • <url>不以/
  • 结尾

因此,在您的情况下,使用其中一种并不重要。另见 curl documentation.

其次,TIdMultiPartFormDataStream 是为与 POST 动词一起使用而设计的,但是没有什么可以阻止您将它传递给 TIdHTTP.Put,因为它是间接从 TStream 派生的。甚至还有一个专用的 invariant of TIdHTTP.Post 方法接受 TIdMultiPartFormDataStream:

function Post(AURL: string; ASource: TIdMultiPartFormDataStream): string; overload;

要将文件上传到服务,只需使用 TIdHTTP.Put 方法,将 TFileStream 作为参数,同时在 HTTP header.[=47= 中提供上传文件的正确内容类型]

最后,您尝试从文档中提取纯文本,但没有指定服务应 return 的内容类型。这是通过 Accept HTTP header 完成的。 TIdHTTP 的默认实例已将 属性 IdHTTP.Request.Accept 初始化为 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'(这可能因 Indy 版本而异)。因此默认情况下 Tika 将 return HTML 格式化文本。要获得纯文本,您应该将其更改为 'text/plain; charset=utf-8'.

固定实施:

uses IdGlobal, IdHTTP;

function GetDocumentText(const FileName, ContentType: string): string;
var
  IdHTTP: TIdHTTP;
  Stream: TIdReadFileExclusiveStream;
begin
  IdHTTP := TIdHTTP.Create;
  try
    IdHTTP.Request.Accept := 'text/plain; charset=utf-8';
    IdHTTP.Request.ContentType := ContentType;
    Stream := TIdReadFileExclusiveStream.Create(FileName);
    try
      Result := IdHTTP.Put('http://localhost:9998/tika', Stream);
    finally
      Stream.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

function GetPDFText(const FileName: string): string;
const
  PDFContentType = 'application/pdf';
begin
  Result := GetDocumentText(FileName, PDFContentType);
end;

function GetDOCXText(const FileName: string): string;
const
  DOCXContentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
begin
  Result := GetDocumentText(FileName, DOCXContentType);
end;

根据Tika's documentation,它还支持发布 多部分表单数据。如果你坚持使用这种方法,那么你应该将目标资源更改为 /tika/form 并在你的实现中切换到 Post 方法:

function GetDocumentText(const FileName, ContentType: string): string;
var
  IdHTTP: TIdHTTP;
  FormData: TIdMultiPartFormDataStream;
begin
  IdHTTP := TIdHTTP.Create;
  try
    IdHTTP.Request.Accept := 'text/plain; charset=utf-8';
    FormData := TIdMultiPartFormDataStream.Create;
    try
      FormData.AddFile('file', FileName, ContentType); { older Indy versions: FormData.Add(...) }
      Result := IdHTTP.Post('http://localhost:9998/tika/form', FormData);
    finally
      FormData.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

为什么有问题的原始实现适用于 PDF 文件?

当您通过 TIdHTTP Post 多部分表单数据时,Indy 自动将请求的内容类型设置为 'multipart/form-data; boundary=...whatever...'。当您 Put(除非您在执行请求之前 set it manually)数据时,情况并非如此,因此 TIdHttp.Request.ContentType 保持空白。现在我只能猜测,当 Tika 看到空内容类型时,它会回退到一些默认类型,可能是 PDF,并且它仍然能够以某种方式从多部分请求中读取文档。