问题描述:
我正在寻找一种方法仅访问两个特定标题标签之间的 li
元素(例如从第2个 h3
到第 3 个 h3
,或从第 3 个 h3
到下一个 h4
),以便根据标题中提到的标准创建列在 https://de.wikipedia.org/wiki/1._Januar 上列出的历史事件表。
对我而言,主要问题是 - 除了 h1
标题之外,较低级别的字幕没有 className
或 id
。
HTML示例:
<div class="mw-parser-output">
[...]
</h3>
<ul>
<li><a href="/wiki/153_v._Chr." title="153 v. Chr.">153 v. Chr.</a>: Die <a href="/wiki/Consulat" title="Consulat">Konsuln</a> der <a href="/wiki/R%C3%B6mische_Republik" title="Römische Republik">römischen Republik</a> beginnen ihre Amtszeit erstmals
am 1. Januar statt am 1. März; daher ist der 1. Januar heute der Jahresanfang.</li>
<li><span style="visibility:hidden;">0</span><a href="/wiki/45_v._Chr." title="45 v. Chr.">45 v. Chr.</a>: <a href="/wiki/Kalenderreform_des_Gaius_Iulius_Caesar" title="Kalenderreform des Gaius Iulius Caesar">Caesars Reform</a> des <a href="/wiki/R%C3%B6mischer_Kalender"
title="Römischer Kalender">römischen Kalenders</a> endet. Dieser wird ab 2. Januar 709 <a href="/wiki/Ab_urbe_condita_(Chronologie)" title="Ab urbe condita (Chronologie)">a. u. c.</a> durch den <a href="/wiki/Julianischer_Kalender" title="Julianischer Kalender">julianischen Kalender</a> ersetzt.</li>
<li><span style="visibility:hidden;">0</span><a href="/wiki/32_v._Chr." title="32 v. Chr.">32 v. Chr.</a>: <a href="/wiki/Augustus" title="Augustus">Oktavian</a> lässt sich vom <a href="/wiki/R%C3%B6mischer_Senat" title="Römischer Senat">Senat</a> zum
„Führer Italiens“ (<i><a href="/wiki/Dux_(Titel)" title="Dux (Titel)">dux Italiae</a></i>) ausrufen. Er erklärt <a href="/wiki/Kleopatra_VII." title="Kleopatra VII.">Kleopatra</a> und damit <i><a href="/wiki/De_jure/de_facto" title="De jure/de facto">de facto</a></i> auch <a href="/wiki/Marcus_Antonius" title="Marcus Antonius">Marcus Antonius</a> den Krieg.</li>
</ul>
[...]
</ul>
<h4><span id="Inkrafttreten_von_Gesetzen_und_Staatsvertr.C3.A4gen"></span><span class="mw-headline" id="Inkrafttreten_von_Gesetzen_und_Staatsverträgen">Inkrafttreten von Gesetzen und Staatsverträgen</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span>
<a href="/w/index.php?title=1._Januar&veaction=edit&section=3" class="mw-editsection-visualeditor" title="Abschnitt bearbeiten: Inkrafttreten von Gesetzen und Staatsverträgen">Bearbeiten</a><span class="mw-editsection-divider"> | </span>
<a href="/w/index.php?title=1._Januar&action=edit&section=3" title="Abschnitt bearbeiten: Inkrafttreten von Gesetzen und Staatsverträgen">Quelltext bearbeiten</a><span class="mw-editsection-bracket">]</span></span>
</h4>
<p><i>Der 1. Januar wird oft für das Inkrafttreten von Gesetzen und Staatsverträgen verwendet. Das gilt unter anderem für:</i>
</p>
<ul>
<li><a href="/wiki/1812" title="1812">1812</a>: das <i><a href="/wiki/Allgemeines_b%C3%BCrgerliches_Gesetzbuch" title="Allgemeines bürgerliches Gesetzbuch">Allgemeine bürgerliche Gesetzbuch</a></i> <i>(ABGB)</i> in den <a href="/wiki/Habsburgermonarchie#Erblande"
title="Habsburgermonarchie">habsburgischen Erblanden</a>.</li>
</ul>
[...]
</h4>
<p><i>Folgende Staaten erhalten am 1. Januar ihre Unabhängigkeit:</i>
</p>
<ul>
[...]
</ul>
<h3><span class="mw-headline" id="Wirtschaft">Wirtschaft</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=1._Januar&veaction=edit&section=6" class="mw-editsection-visualeditor" title="Abschnitt bearbeiten: Wirtschaft">Bearbeiten</a>
<span class="mw-editsection-divider"> | </span><a href="/w/index.php?title=1._Januar&action=edit&section=6" title="Abschnitt bearbeiten: Wirtschaft">Quelltext bearbeiten</a><span class="mw-editsection-bracket">]</span></span>
</h3>
<h4><span class="mw-headline" id="Wichtige_Ereignisse_in_der_Weltwirtschaft">Wichtige Ereignisse in der Weltwirtschaft</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=1._Januar&veaction=edit&section=7"
class="mw-editsection-visualeditor" title="Abschnitt bearbeiten: Wichtige Ereignisse in der Weltwirtschaft">Bearbeiten</a><span class="mw-editsection-divider"> | </span><a href="/w/index.php?title=1._Januar&action=edit&section=7" title="Abschnitt bearbeiten: Wichtige Ereignisse in der Weltwirtschaft">Quelltext bearbeiten</a>
<span class="mw-editsection-bracket">]</span>
</span>
</h4>
<ul>
<li><a href="/wiki/1780" title="1780">1780</a>: In <a href="/wiki/Geschichte_Bratislavas" title="Geschichte Bratislavas">Preßburg</a> erscheint die erste ungarische Zeitung <i>Magyar hírmondó</i> („Ungarischer Kurier“).</li>
到目前为止,我仅使用以下代码成功访问了所有未包含在目录表中的li
元素(超过1000个!):
实验性代码示例:
Sub HistoricalEvents_Test()
Dim http As Object, html As New MSHTML.HTMLDocument
Dim oLiList As MSHTML.IHTMLDOMChildrenCollection
Dim data As String
Dim r As Integer
Dim oWord As Object, oWordDoc As Object
Dim wordApp As New Word.Application
Dim iFirstRow As Integer, iLastRow As Integer
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "https://de.wikipedia.org/wiki/1._Januar", False
http.send
html.body.innerHTML = http.responseText
Dim lLiResultList As Long
Dim lLiResultLoop As Long
Set oLiList = html.querySelectorAll("#toc ~ ul li")
For lLiResultLoop = 0 To oLiList.Length - 1
Dim oLiChild As Object
Set oLiChild = oIlList.Item(lLilResultLoop)
data = oLiChild.innerText 'data = data & vbCrLf & oLiChild.innerText
Range("B" & lLiResultLoop +1).Value = data
data = vbNullString
Next lLiResultLoop
Dim j As Long
Dim Ws As Worksheet
Dim rngDB As Range
Set Ws = ActiveSheet
Set oWord = CreateObject("Word.Application")
Set oWordDoc = oWord.Documents.Open("D:\Jahrestage Geschichte.docx")
iFirstRow = 1 ' "Ws.Cells(1, 2).End(xlDown).Row" used to work fine but suddenly gives same as iLastRow!
'Debug.Print iFirstRow
iLastRow = Ws.Cells(ActiveSheet.Rows.Count, "B").End(xlUp).Row
'Debug.Print iLastRow
oWord.Visible = True
With wordApp
With Ws
Set rngDB = Ws.Range(.Cells(iFirstRow, 2), .Cells(iLastRow, 2))
End With
rngDB.Cut
oWord.Selection.PasteSpecial DataType:=wdPasteText
oWord.Selection.TypeParagraph
oWord.Selection = ""
End With
oWordDoc.Close savechanges:=True
wordApp.Quit 'it doesn't :(
End Sub
总体构思/最终项目描述
最终项目应该为每个月准备一个工作表,每个工作表都包含一个表格,其中每一行对应该月的每一天,列则对应相应的(子)标题的不同类别。代码中的Word输出只是一个初步的副产品,只有在解决主要问题时才会完成它。
进一步说明
这是我在SO上的第一次贡献。当涉及到vba和网络爬虫(或任何编码、脚本或编程方面)时,我是一个绝对的初学者,但我被它吸引住了,并且用我的整个寒假时间来弄清楚上述代码。即使没有像SO的高手分享给像我这样的新手无价的知识,我也无法完成那个可怜的脚本。我尝试过各种方法,但总是卡在某些地方,VBA触发运行时错误,Excel经常崩溃。特别是,我无法成功实现nextSibling/previousSibling方法或nodeName选择器,我认为这可能是解决问题的一种有希望的方法。所以,任何帮助或提示都将不胜感激!
有效的解决方案:
由于对我的问题的反馈,我终于设法找到了一个解决方案,虽然可能不是最优雅的方式。唯一剩下的问题是奇怪的是,最后一列的li元素被复制了。所以如果有人知道如何处理这个问题......
Sub SliceHtmlByHeaderTypes4()
Dim http As Object, html As MSHTML.HTMLDocument
Dim sh As Worksheet
Set sh = ThisWorkbook.ActiveSheet
Set http = CreateObject("MSXML2.XMLHTTP"): Set html = New MSHTML.HTMLDocument
http.Open "GET", "https://de.wikipedia.org/wiki/1._Januar", False
http.send
html.body.innerHTML = http.responseText
Dim hNodeList As Object
Dim startPos As Long, endPos As Long
Dim s As Integer, e As Integer
Set hNodeList = html.querySelectorAll("#toc ~ h2, #toc ~ h3, #toc ~ h4")
Debug.Print hNodeList.Length
Do While s < hNodeList.Length - 1
http.Open "GET", "https://de.wikipedia.org/wiki/1._Januar", False
http.send
html.body.innerHTML = http.responseText
Set hNodeList = html.querySelectorAll("#toc ~ h2, #toc ~ h3, #toc ~ h4")
startPos = InStr(html.body.outerHTML, hNodeList.Item(s).outerHTML)
endPos = InStr(html.body.outerHTML, hNodeList.Item(s + 1).outerHTML)
If startPos > 0 And endPos > 0 And endPos > startPos Then
Dim strS As String
strS = Mid$(html.body.outerHTML, startPos, endPos - startPos + 1)
Else
MsgBox "Problem slicing string"
Stop
Exit Sub
End If
Dim liList As Object
html.body.innerHTML = strS
Set liList = html.getElementsByTagName("li")
If liList.Length > 0 Then
Dim i As Integer
Dim liText As String
Dim lc As Integer
Dim liRange As Range
lc = (Cells(2, Columns.Count).End(xlToLeft).Column) + 1
Set liRange = sh.Range(Cells(2, lc), Cells(2, lc))
For i = 0 To liList.Length - 1
On Error Resume Next
liText = liList.Item(i).innerText
liRange.Value = liRange.Value & liText & vbNewLine
liText = vbNullString
Next i
strS = vbNullString
startPos = 0
endPos = 0
hNodeList = ""
i = 0
End If
s = s + 1
Loop
End Sub
html.querySelectorAll("#toc ~ ul")
。 - QHarrhtml.querySelectorAll("#toc ~ ul")
完美地运行了。顺便说一下,非常感谢你,这种使用“~”的方法对我来说是全新的。多么方便啊! - slintezgeu