65.9K
CodeProject 正在变化。 阅读更多。
Home

一个使用 Autoit 脚本从 MSWord 文档中提取数据并将其发送到 Internet 应用程序的示例

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2016 年 3 月 7 日

CPOL

3分钟阅读

viewsIcon

19862

downloadIcon

158

一个从 MSWord 文档中抓取信息并通过 Ajax 技术发送到 Internet 的程序

引言

这是一个使用 Autoit[1] 访问 MSWord 文档并提取一些数据的示例,但它也旨在展示 COM (Component Object Model) 对象的使用,特别是使用 MSWord 的 COM 对象 MSXML2.XMLHTTP (WinHttpRequest 对象),它实现了 Ajax 协议。

Autoit 有一个 MS Word COM 对象库,其中包含一些函数,因此我在这里使用了本机方法和属性,因为该库不包含我需要的函数,因此可以更好地理解 Autoit 如何使用 COM 对象。

本文包含以下主题

  • 如何以对象的形式访问 MSWord 文档
  • 如何提取数据
  • 如何准备和发送数据

访问 MSWord 文档

我们需要实例化一个 MSWord COM 对象:这可以通过多种方式完成

  • 如果我们想要一个新文档,可以使用 ObjCreate("Word.Application")
  • 对于已打开的文档,可以使用 ObjGet("", "Word.Application")
  • 对于特定文档,可以使用 ObjGet("fileName", "Word.Application") 或简写 ObjGet("MSWordfileName")

如果 MSWord 未激活,则第二种模式会失败,并在变量 @error 中返回一个不同于 0 的值。 在下面的脚本片段中,所有方法都被使用; 请注意创建新文档的选择,它假定剪贴板包含数据。

Global $oWord = ObjGet("", "Word.Application")
If @error <> 0 Or $oWord.Documents.Count = 0 Then
   ; This is the case in which MSWord or is not present (@error <> 0)
   ; or has not documents ($oWord.Documents.Count = 0)
   $form = "File,Document,,30,,Documents (*.doc\59*.docx)|All (*.*);" _
			& "C,Enter for a New Document"
   $parms = formGen("Word File",$form,-1,"",100,100)	; create a form for call a filename
   If $parms.Item("fg_button") = "Cancel" Then Exit
   If $parms.Item("Document") <> "" Then
	  $oDoc = ObjGet($parms.Item("Document"))	; open the MSWord document
   Else
	  $oAppl = ObjCreate("Word.Application")
	  $oAppl.Visible = True
	  $oDoc = $oAppl.Documents.add	; creates  an empty document
	  $range = $oDoc.Range 			; Set range start/end at the end to the document
	  $range.Collapse($WdCollapseEnd)
	  $range.paste					; paste the clipboard
   EndIf
   $oDoc.Application.Visible = 1
Else
   ; This is the case in which MSWord is present and has one or more documents open
   Local $nDocs = $oWord.Documents.Count
   $nDoc = 1
   If $nDocs <> 01 Then
	  Local $docs = ""
	  For $i = 1 to $nDocs
		 consoleWrite($oWord.Documents($i).Name  & @CRLF)
		 $docs &= "|" & $i & "=" & $oWord.Documents($i).Name
	  Next
	  $form = "CMB,Document,,20,," & StringMid($docs,2)
	  $parms = formGen("Word Files",$form,-1,"",100,100)	; _
               create a form to choose which document to process
	  If $parms.Item("fg_button") = "Cancel" Then Exit
	  $nDoc = $parms.Item("Document")
   EndIf
   $oDoc = $oWord.Documents($nDoc)
EndIf

在脚本中,用于请求文档名称的简单表单由我的实用程序 formGen 创建,您可以在我的 网站 上找到它。

数据捕获

MSWord 的对象模型提供了一组复杂的对象,其中每个对象都可以包含对象、方法和属性的集合; 这些集合可以引用整个文档、文档的一部分或选择[2]

在本脚本中,我们主要关注 ParagraphsHyperlinks 集合; 特别是,该文档包含一个结构化格式的作业列表(见下文),其中包含一个 Internet 链接

FRANCE: 1 PostDoc position in HISTORY
Ref. 46_16 - City: Orleans - Deadline: 12/02/2016 »

对象 Paragraph 的属性 text 是数据的容器,这些数据通过使用正则表达式[3] (RE) 提取。

For $paragraphCount = 1 To $nParag
   $parag = StringReplace($oParag($paragraphCount).Range.Text,chr(11),"")	; clear VT
   $aExtract = StringRegExp($parag, '^(.+): (.+)(Ref\..*) - City: (.+) - _
               Deadline: (\d\d/\d\d/\d\d\d\d)', $STR_REGEXPARRAYGLOBALMATCH)
   If isArray($aExtract) Then
	  $itemCount += 1
	  $aExtract[4] = StringRegExpReplace($aExtract[4], '(\d{2})/(\d{2})/(\d{4})', '$3/$2/$1')	; _
                     date from dd/mm/yyyy to yyy/mm/dd
	  $data = ""
	  For $i = 0 To UBound($aExtract) - 1
		 $data &= "&" & $aFields[$i] & "=" & encode64($aExtract[$i])
	  Next
	  $aCategory = StringRegExp($aExtract[1], '.*in (.*)', $STR_REGEXPARRAYGLOBALMATCH)	; Category
	  If isArray($aCategory) Then $data &= "&Category=" & encode64($aCategory[0])	; _
             extracts the study field
	  For $hLink In $oParag($paragraphCount).Range.Hyperlinks
		  $link = $hLink.Address
	  Next
	  $data &= "&Link=" & encode64($link)
	  ConsoleWrite(StringMid($data,2) & @CRLF)
	  $res = ajax($url,StringMid($data,2))
	  If $res <> 1 Then ConsoleWrite("--> " & $res & @CRLF)
   EndIf
Next

您可以在 Autoit Help 中找到正则表达式语法的文档,这里仅对如何在脚本中使用 RE 进行一些说明:如果文本与 RE 匹配,则 StringRegExp 函数提取由一对括号分隔的内容匹配的数据。 每个提取的标记都有一个名称 $1, $2, ...,这允许 StringRegExpReplace 函数重新塑造日期。

对于段落中包含的链接,脚本访问段落的 Hyperlinks 集合并获取 Address 属性。

发送数据

提取的数据必须以 name<sub>1</sub>=value<sub>1</sub>&name<sub>2</sub>=value<sub>2</sub>... 的形式准备,并且数据可以包含 HTTP 协议中使用的字符,例如 =&,因此数据必须进行编码,例如以 base64 格式编码,其中只有 =+/ 是协议中使用的字符[4]

Global $base64 = StringSplit("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/","",2)
$base64[62] = "%2B"	; +
$base64[63] = "%2F"	; /
...
	$aFields = StringSplit("Nation|Title|Notes|Town|Deadline","|",2)
...
	For $i = 0 To UBound($aExtract) - 1
		$data &= "&" & $aFields[$i] & "=" & encode64($aExtract[$i])
	Next
...
Func encode64($in)
   $bin = 0
   $out = ""
   For $i = 1 to StringLen($in)
	  $bin = BitShift($bin,-8)
	  $bin += Asc(StringMid($in,$i,1))
	  If Mod($i,3) = 0 Then
		 $out &= encode6($bin)
		 $bin = 0
	  EndIf
   Next
   If Mod(StringLen($in),3) <> 0 Then $out &= encode6($bin,Mod(StringLen($in),3))
   return $out
EndFunc
Func encode6($bin,$l=3)
   If $l <> 3 Then $bin =  BitShift($bin,-8*(3-$l))
   $out = ""
   For $i=3 To 3-$l Step -1
	  $cod6 = BitShift($bin,$i*6)
	  $bin -= BitShift($cod6,-$i*6)
	 $out &= $base64[$cod6]
   Next
   return $out
EndFunc

如果接收者是一个 PHP 脚本,则此代码段会恢复数据:foreach ($_REQUEST as $key => $value) $$key = base64_decode($value);

我使用 COM 对象 MSXML2.XMLHTTP 以同步模式发送数据:$ajax.open("POST", $url, true)

Global $ajax = ObjCreate("MSXML2.XMLHTTP")
...
Func ajax($url,$data)
   $ajax.open("POST", $url, true)	; synchronous !
   $ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
   $ajax.send($data)
   Local $hTimer = TimerInit() ; Begin the timer and store in a variable.
   While TimerDiff($hTimer) < 10000
      If $ajax.readyState == 4 Then
		 If $ajax.status = 200 Then return $ajax.responseText
	  EndIf
	  Sleep(10)
   WEnd
   return "Timeout!"
EndFunc

注释

  1. ^AutoIt 是一种免费的类 BASIC 脚本语言,是 PowerShell 的替代品,最初设计用于自动化与 Windows GUI 的交互。 AutoIt 可以在 Windows 上解释或编译运行。
    它附带许多库,这些库能够实现访问 COM 对象和创建图形界面等功能。
  2. ^文档可以有多个范围,但只有一个选择。
  3. ^此站点 https://regex101.com/ 对于测试正则表达式非常有用。
  4. ^代码开销为 33%,我没有使用 = 字符,如果需要编码的数据长度不能被 3 整除,则用于填充; 如果要连接两组数据,则填充是必需的。
© . All rights reserved.