2018年7月21日 星期六

[VBA] 打開 IE 瀏覽器去操作和列印

辦公室之用,之前寫過如何用 VBA 控制 IE 去將網頁列印成 PDF。但後來遇到在 PDF 軟件上的問題,本應可以將存檔也自動化的步驟失效了,而自己對這工具的需求也減少了,就未有再檢視如何改進它。最近重新拾起辦公室內的一些VBA小工具,看見能發揮效果的感覺真不錯,所以,一於重新嘗試如何改進這個自動化的小工具,先整理之前的方法。

在基本的VBA功能以外,還有兩個 Library 需要先引入:打開 Reference - VBAProject,勾選引入 Microsoft Internet Controls 及 Microsoft HTML Object Library。 下面代碼中的 "ShellWindows" 會得到 Windows 下的 Shell 窗口對象,可以用来操控 Windows的文件夹和 IE 瀏覽器。 "InternetExplorer" 顧名思義可以控制Internet Explorer。 取得某個 IE 的控制後,會需要一點 HTML 語法 和 DOM 結構的認識,之後用 GetElementByID("") GetElementsByTagName("").Item(n)、 GetElementsByClassName("").Item(n) 之類的方法去取得HTML 當中的元素; 甚或如透過 .Style.display 、 .innerText 等屬性去改變網頁的顯示。

(直接印紙的話仍可以做到,只是要轉成 PDF 的話就要看 PDF 軟件的造化..... 可能下周試用 Sendkeys處理 Print Dialog?其實VBA又是否能做到其他語言中的Web Scraping方式呢,大概是未有Library的第 3 方支持?。 另外,因為保守地想給予足夠時間讀取網頁,所以也加入很多等待的時間。)

Sub IEautoprint
    
    Dim shellWins As ShellWindows
    Dim myIE As InternetExplorer
    
    Set shellWins = New ShellWindows
    Set mySheet = ThisWorkbook.Sheets("SecuritySheet")
    Set myIE = CreateObject("InternetExplorer.Application")
    StartRow = 2
    MaxRow = 65536
    
    '打開網址
    myIE.Navigate "http://website.com/fullpath"
    Application.Wait (Now + Time("0:00:01")) 

    ' Optional - 以 Title 標題去選擇視窗
    If shellWins.Count > 0 Then
        For i = shellWins.Count - 1 to 0 Step -1
            If (shellWins.Item(i).LocationName = "Window Title") Then
                Set myIE = shellWins.Item(i)
                myIE.Visible = True
                Exit For
            End If
        Next
    End If
    
    ' Loop Excel mySheet 中的 Input, 重覆:遞交HTML表單、改變頁面顯示、列印 等動作 
    For x = StartRow To MaxRow
        ' 填入HTML的表單及遞交
        Do While .ReadyState <> 4
        Loop ' 等待網頁載入完畢
        myIE.Document.Form(0).Elements("CTYPE").Value = mySheet.Cells(x,1).Value 'Html 表單中的元素
        myIE.Document.Form(0).Elements("CCODE").Value = mySheet.Cells(x,2).Value 'Html 表單中的元素 
        myIE.Document.Form(0).Submit 'Html 表單Submit
 
        ' 改變 HTML中的Style屬性去影響 Expand/Collapse 
        Do While .ReadyState <> 4
        Loop
        On Error Resume Next
        If Not (.Document.getElementbyID("hide105") Is Nothing) Then
            myIE.Document.getElementbyID("hide101").Style.display = "None"
            myIE.Document.getElementbyID("hide105").Style.display = "Block"
        End If
        
        ' 列印
        myIE.ExecWB 6, 2   'ExecWB指令, OLECMDID_PRINT=6, OLECMDEXECOPT_DONTPROMPTUSER=2
        Application.Wait (Now + TimeValue("0:00:02")) ' 等待特定的時間讓檔案建立
        
        Do While .Busy Or .ReadyState <> 4
        Loop
        
        ' 新一格沒有內容時完結 => Done~!!
        If mySheet.Cells(x+1, 1).Value = "" Then
            GoTo LastLine            
        End If
    Next
' 完結時的處理LineDone:
    MsgBox "Done"
    Set shellWins = Nothing
    Set myIE = Nothing
End Sub


ShellWindowshttps://msdn.microsoft.com/en-us/library/windows/desktop/bb773974(v=vs.85).aspx
InternetExplorerhttps://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa752084(v=vs.85)
ExecWB 的 IOleCommandTarget interfacehttps://docs.microsoft.com/en-us/windows/desktop/api/docobj/ne-docobj-olecmdid
OLECMDIDhttps://docs.microsoft.com/en-us/windows/desktop/api/docobj/ne-docobj-olecmdid

2018年7月6日 星期五

Coursera - Applied Data Science with Python 學習筆記 05 - Social Network Analysis

到了這系列課程的最後一門課-社會網絡分析 (Social Network Analysis) ,原本以為是研究 FB、Twitter 等平台的文字資料;原來是運用圖論中的節點和線邊構成的『圖』去代表社會網絡中的人和關係。純圖論的一些經典實施問題包括:7橋問題(path)、最短路徑問題(distance)、4色問題(labeling)。圖論伸廷到今天的社會網絡分析,研究的方向可能是社群的結構、資訊如何流通等等,社交平台做成的網絡是這個方向的一大推動力,正如 Facebook 提供讓開發者使用的 Graph API 就是以 物件-關係 來處理資訊。Python中有 NetworkX 套件特別用來處理這些Social Network Analysis 問題的工具。

Week1 是圖論上的基礎,和一些特別的圖例如 bipartite graph, 它的L-Bipartite graph (weighted) projection。解釋過什麼是Graph、Node、Edge、Degree等基本詞彙後,網絡和圖的稱呼會交替出現。

要引用一張圖,可以有以下方法:
https://networkx.github.io/documentation/networkx-1.10/reference/readwrite.html
import networkx as nx
import numpy as np
import pandas as pd
%matplotlib notebook

G1 = nx.Graph()
G1.add_edges_from([('A', 'B'),
                   ('A', 'C'),
                   ('A', 'D'),
                   ('A', 'E'),
                   ('B', 'D'),
                   ('B', 'E'),
                   ('D', 'E'),
                   ('C', 'F'),
                   ('C', 'K'),
                   ('F', 'H'),
                   ('F', 'K'),
                   ('F', 'J'),
                   ('J', 'K')])

G2 = nx.read_edgelist('G_self_edgelist.txt', delimiter=',', data=[('Weight', int)])

G_df = pd.read_csv('G_self_edgelist.txt', delimiter=',', 
                   header=None, names=['n1', 'n2', 'weight'])
G3 = nx.from_pandas_dataframe(G_df, 'n1', 'n2', edge_attr='weight')

nx.info(G)
G.nodes(data=True)
G.edges(data=True)
nx.draw_networkx(G)

Week 2

「群聚分析」研究的是,網絡中的點互相連結形成群聚的程度。典型由多人形成的群聚,會是圖中一部分由所有點互相連結的完全子圖。而最簡單的一個群聚是由互相認識的三個人形成的「Triadic Closure」,對更複雜的圖的幾種群聚系數,量度的設計是由這形式推展出來的。

首先是圖中某個頂點的「局部群聚系數」-Local Clustering Coefficient,它的大概主意是去計算:與某頂點相連的近鄰們,能夠互相連結成配對的比例。即以下兩者之比:
$v$的近鄰間實際形成的邊數:$|(X,Y)| s.t. X,Y \in N(v)$
$v$的近鄰間最大可能形成的邊數:$\frac{d_v(d_v - 1)}{2}$

當考慮整個圖的整體群聚程度-「全局群聚系數」時,有兩種方法,一個是所有點的局部群聚系數平均起來-「Average Local Clustering Coefficient」。另一個稱為 「Transitivity」 的量度方法是數算圖中由三點形成的「閉三角組」和「開三角組」的比例:
Transitivity = 3 * number triangle / number of opera triad
而兩套方法的分別是對 Transitivity 對 高Degree 的點有較大比重。
nx.average_clustering(G)
nx.transitivity(G)