Веб-очистка с использованием XHR от siriusxm.com
Мне нужно вытащить исполняемого в настоящее время исполнителя и песню с http://www.siriusxm.com/siriusxmhits1. Я могу заставить это работать при переходе на веб-сайт с помощью Internet Explorer, но это занимает слишком много времени, поэтому я попытался использовать WINHTTP.WinHTTPRequest.5.1
а также MSXML2.serverXMLHTTP
но ни та, ни другая не извлекают конкретные данные, которые я ищу. Я думаю, что я близко, но что-то упустил.
Ниже приведен фрагмент HTML:
<div id="on-the-air-content" style="display: block;">
<div class="module-content theme-color-content-bg clearfix">
<div id="onair-pdt" style="display: block;">
<img alt="" src="//www.siriusxm.com/albumart/Live/2000/chainsmokers_58C328AC_t.jpg">
<p class="onair-pdt-artist">Chainsmokers/Coldplay</p>
<p class="onair-pdt-song">Something Just Like This</p>
</div>
...
</div>
...
</div>
Вот мой текущий код:
Sub GetData()
Dim getArtist As Object
Dim getSong As Object
Set xmHtml = New HTMLDocument
With CreateObject("WINHTTP.WinHTTPRequest.5.1")
.Open "GET", "http://www.siriusxm.com/siriusxmhits1", False
.send
xmHtml.body.innerHTML = .responseText
End With
Set getArtist = xmHtml.getElementById("onair-pdt").getElementsByTagName("p")(0)
MsgBox (getArtist.innerText)
Set getSong = xmHtml.getElementById("onair-pdt").getElementsByTagName("p")(1)
MsgBox (getSong.innerText)
End Sub
Если я активирую Internet Explorer, он будет работать с использованием следующего кода, но это займет слишком много времени для того, что мне нужно сделать:
Sub GetData()
Dim DivID As HTMLObjectElement
Dim getArtist As Variant
Dim getSong As Variant
URL = "http://www.siriusxm.com/siriusxmhits1"
With IExplore
.Navigate URL
.Visible = False
Do While .readyState <> 4: DoEvents: Loop
Set doc = .document
Set DivID = doc.getElementById("onair-pdt")
getArtist = DivID.getElementsByClassName("onair-pdt-artist")(0).innerText
getSong = doc.getElementsByClassName("onair-pdt-song")(0).innerText
End With
End Sub
1 ответ
На веб-сайте http://www.siriusxm.com/ есть своего рода API. Я переместился на страницу по ссылке http://www.siriusxm.com/hits1 в Chrome, затем открыл окно "Инструменты разработчика" (F12), вкладка "Сеть" и исследовал XHR в списке. Информация о текущей песне может быть получена, например, в следующих шагах:
Сделайте XHR по URL http://www.siriusxm.com/sxm_date_feed.tzi чтобы получить текущую метку времени.
Сделать XHR, используя текущую временную метку в последних номерах URL http://www.siriusxm.com/metadata/pdt/en-us/json/channels/siriushits1/timestamp/04-29-02:02:55
Parse получил ответ JSON.
Получить название песни как
JSON.channelMetadataResponse.metaData.currentEvent.song.name
, художники какJSON.channelMetadataResponse.metaData.currentEvent.artists.name
, так далее.
Ниже приведен пример, показывающий структуру ответа JSON, я использую онлайн-инструмент http://jsonviewer.stack.hu/:
Вы можете использовать приведенный ниже код VBA для получения информации, как описано выше. Импортируйте модуль JSON.bas в проект VBA для обработки JSON.
Option Explicit
Sub Test_siriusxm_com()
Dim s As String
Dim d As Date
Dim sUrl As String
Dim vJSON As Variant
Dim sState As String
Dim sArtists As String
Dim sComposer As String
Dim sAlbum As String
Dim sSong As String
' Retrieve timestamp
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "http://www.siriusxm.com/sxm_date_feed.tzi", False
.send
s = .responseText
End With
' Parse timestamp to Date type
d = CDate(DateSerial(Mid(s, 5, 4), Mid(s, 3, 2), Mid(s, 1, 2)) + TimeSerial(Mid(s, 9, 2), Mid(s, 11, 2), Mid(s, 13, 2)))
' Add 4 hours to get UTC from EDT timezone
d = DateAdd("h", 4, d)
' Combine URL with timestamp
sUrl = "http://www.siriusxm.com/metadata/pdt/en-us/json/channels/siriushits1/timestamp/" & _
LZ(Month(d), 2) & "-" & _
LZ(Day(d), 2) & "-" & _
LZ(Hour(d), 2) & ":" & _
LZ(Minute(d), 2) & ":" & _
"00"
' Retrieve channelMetadataResponse JSON data
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", sUrl, False
.send
s = .responseText
End With
' Parse JSON response
JSON.Parse s, vJSON, sState
' Check if valid
If sState <> "Object" Then
MsgBox "Invalid JSON response"
Exit Sub
End If
' Check if available
If vJSON("channelMetadataResponse")("messages")("code") <> "100" Then
MsgBox "Unavailable content"
Exit Sub
End If
' Get necessary properties
Set vJSON = vJSON("channelMetadataResponse")("metaData")("currentEvent")
sArtists = vJSON("artists")("name")
sComposer = vJSON("song")("composer")
sAlbum = vJSON("song")("album")("name")
sSong = vJSON("song")("name")
' Output results
MsgBox "On the Air" & vbCrLf & _
"Artists: " & sArtists & vbCrLf & _
"Composer: " & sComposer & vbCrLf & _
"Album: " & sAlbum & vbCrLf & _
"Song: " & sSong
End Sub
Function LZ(n As String, q As Long) As String ' Add leading zeroes
LZ = Right(String(q, "0") & n, q)
End Function
Кстати, тот же подход используется в этом, этом и этом ответах.