Что нового

[Сеть, интернет] Экспорт данных с сайта

Belfigor

Модератор
Локальный модератор
Сообщения
3,608
Репутация
941
Есть сайт: https://ru.dotabuff.com/players/68730725/matches
Подскажите как экспортировать со страницы список "Победа" "Поражение"? С IE Вообще не силен :(
 

---Zak---

Скриптер
Сообщения
455
Репутация
120
Приветствую...

Надо на все 60 страниц ??? Какие данные нужны - ник + победа/поражени + дата матча + ...?

Тестировалось на Win XP SP3:
Код:
#include <Array.au3>

Global $oRequest
Dim $ARRAY_Y[1][5]					;Используется для получения списка записей

;~ $ARRAY_Y[i][0] - Герой
;~ $ARRAY_Y[i][1] - Результат
;~ $ARRAY_Y[i][2] - Дата матча
;~ $ARRAY_Y[i][3] - Время матча
;~ $ARRAY_Y[i][4] - ID матча

;~ ----------------------------------------------------------------------------------------------------------------
$oRequest = ObjCreate('WinHttp.WinHttpRequest.5.1') ;Создаём COM-объект
   If @error Then
	  MsgBox(16, 'Ошибка', 'Ошибка при создании объекта "WinHttp.WinHttpRequest.5.1".')
	  Exit 1
   EndIf
$oErrorHandler = ObjEvent('AutoIt.Error', 'ErrorFunc')
;~ ----------------------------------------------------------------------------------------------------------------
   $oRequest.Open('GET', 'https://ru.dotabuff.com/players/68730725/matches', 0)
		 $oRequest.SetRequestHeader('User-Agent', 'Testing')
		 $oRequest.Send()
		 $oRequest.WaitForResponse
	  $sData = $oRequest.ResponseText
	$PageS = StringRegExp($sData, '(?s).*?class=["'']*last["'']*>.*?page=(.*?)["'']*>Last', 3) ; Сколько всего страниц
		ConsoleWrite("-Всего страниц на обработку - "&$PageS[0]&@CRLF)
;~ ----------------------------------------------------------------------------------------------------------------
For $Page = 1 To 3 ; Вместо "3" можно подставить "$PageS[0]", но для теста взято 3 страницы...
   $oRequest.Open('GET', 'https://ru.dotabuff.com/players/68730725/matches?page='&$Page, 0)
		 $oRequest.SetRequestHeader('User-Agent', 'Testing')
		 $oRequest.Send()
		 $oRequest.WaitForResponse
	  $sData = $oRequest.ResponseText
	$REC = '(?s).*?<tr data-link-to.*?class=["'']*hero-link["'']*>(.*?)</a>.*?<td><a.*?class.*?>(.*?)</a><div.*?class=["'']*timeago["'']* datetime=["'']*(.*?)T(.*?)Z["'']* title.*?class=["'']*matchid["'']*>(.*?)</a>.*?</tr>'
		$ARRAY_Y = _ArrIN($sData, $REC, $ARRAY_Y)
		ConsoleWrite("-Пастинг "&$Page&" стр выполнен"&@CRLF)
Next
_ArrayDisplay($ARRAY_Y, "Cписок")


Func _ArrIN($DATA, $PATTERN, $ARR)
Local $STR
	$APro_Text = StringRegExp($DATA, $PATTERN, 3)
	If Not @error Then
		For $i = 0 To UBound($APro_Text)-1 Step UBound($ARR, 2)
			$STR = ""
			For $i2 = 0 To UBound($ARR, 2)-1
				If $i2 > 0 Then $STR = $STR &"~"
				$STR = $STR&$APro_Text[$i+$i2]
			Next
			_ArrayAddEx($ARR, $STR)
		Next
	EndIf
	Return $ARR
EndFunc

Func _ArrayAddEx(ByRef $avArray, $vValue)
    If Not IsArray($avArray) Then Return SetError(1, 0, -1)
		Local $iRows, $iCols, $iDims, $aSplit_Val
		$iRows = UBound($avArray)
		$iCols = UBound($avArray, 2)
		$iDims = UBound($avArray, 0)
		If $iDims > 2 Then Return SetError(2, 0, -1)
		If $iDims = 1 Then
			ReDim $avArray[$iRows + 1]
			$avArray[$iRows] = $vValue
			Return $iRows
		Else
		ReDim $avArray[$iRows + 1][$iCols]
		$aSplit_Val = StringSplit($vValue, "~")
		For $i = 0 To $iCols-1
			If $i+1 > $aSplit_Val[0] Then ExitLoop
			$avArray[$iRows][$i] = $aSplit_Val[$i+1]
		Next
		Return $iRows
    EndIf
EndFunc

Func ErrorFunc()
    MsgBox(16, 'Ошибка', $oErrorHandler.description)
    Exit 2
EndFunc

Чтобы получить все 60 страниц - необходимо в 28 строке заменить:
Код:
For $Page = 1 To 3

на
Код:
For $Page = 1 To $PageS[0]


По итогам получаем массив:
Код:
;~ $ARRAY_Y[i][0] - Герой
;~ $ARRAY_Y[i][1] - Результат
;~ $ARRAY_Y[i][2] - Дата матча
;~ $ARRAY_Y[i][3] - Время матча
;~ $ARRAY_Y[i][4] - ID матча
 
Автор
Belfigor

Belfigor

Модератор
Локальный модератор
Сообщения
3,608
Репутация
941
Пока если честно сам не знаю что надо будет в итоге, просто захотел получить график своих игр по соотношению победа\поражение.
Спасибо. Буду теперь пытаться экспериментировать :smile:


Добавлено:
Сообщение автоматически объединено:

Оооооо вообще шикарно, огромное спасибо :laugh:


Добавлено:
Сообщение автоматически объединено:

Возник вопрос. При попытке спарсить например 20 страниц, теоретически скрипт должен выдать результат команды
Код:
UBound($ARRAY_Y,1)

равны 400. Т.к. из расчета 20 игр на страницу, 20 страниц = 400 игр. У меня же он выдает случайные числа от 300 до 380 с шагом в 20. То есть были и результаты 320 и 360 и 380. С чем это связано? Он пропускает какие-то страницы? Пока вставил задержку в 1 секунду после обработки каждой страницы, выдает 400. Но можно как-то это решить не используя задержки?
 

---Zak---

Скриптер
Сообщения
455
Репутация
120
2 Belfigor
Сейчас тоже решил сравнить 60 страниц... странно как-то :whistle:... счас что-нить придумаем.

PS: 1 раз только получилось ровно получить все результаты


Добавлено:
Сообщение автоматически объединено:

Как я понял - не успевает получать страницу...
Надо "WaitForResponse" по серьезнее найти - он считает, что получил страницу - но на самом деле до него не доходит, что он получил только 1/4 страницы...

Твоя задачка пойдет мне на пользу - а то я часто по страничкам таким методам передвигаюсь... учту на будущее и буду искать по-лучше "WaitForResponse".


А вот и результат... почему такие данные получаются:
Код:
For $Page = 1 To $PageS[0] ; Вместо "3" можно подставить "$PageS[0]", но для теста взято 3 страницы...
   $oRequest.Open('GET', 'https://ru.dotabuff.com/players/68730725/matches?page='&$Page, true)
		 $oRequest.SetRequestHeader('User-Agent', 'Testing')
		 $oRequest.Send()
		 ConsoleWrite($oRequest.StatusText)
Next


OffTopic:
OK-Пастинг 12 стр выполнен
OK-Пастинг 13 стр выполнен
OK-Пастинг 14 стр выполнен
Service Temporarily Unavailable-Пастинг 15 стр выполнен
Service Temporarily Unavailable-Пастинг 16 стр выполнен
Service Temporarily Unavailable-Пастинг 17 стр выполнен
OK-Пастинг 18 стр выполнен
Service Temporarily Unavailable-Пастинг 19 стр выполнен
Service Temporarily Unavailable-Пастинг 20 стр выполнен
 
Автор
Belfigor

Belfigor

Модератор
Локальный модератор
Сообщения
3,608
Репутация
941
А я уже с помощью твоего скрипта отрисовал свой график побед, правда только в экселе. Щас буду думать о том чтобы сделать полноценную программу. Задротам понравится :smile:
 

---Zak---

Скриптер
Сообщения
455
Репутация
120
Решение нашел такое (28 строка):
Код:
For $Page = 1 To $PageS[0] ; Вместо "3" можно подставить "$PageS[0]", но для теста взято 3 страницы...
   $oRequest.Open('GET', 'https://ru.dotabuff.com/players/68730725/matches?page='&$Page, true)
		 $oRequest.SetRequestHeader('User-Agent', 'Testing')
		 $oRequest.Send()
		While $oRequest.StatusText <> "OK"
;~ 			ConsoleWrite($oRequest.StatusText)
			$oRequest.Open('GET', 'https://ru.dotabuff.com/players/68730725/matches?page='&$Page, true)
				$oRequest.SetRequestHeader('User-Agent', 'Testing')
				$oRequest.Send()
				$oRequest.StatusText
			Sleep(100)
		WEnd
	  $sData = $oRequest.ResponseText
	$REC = '(?s).*?<tr data-link-to.*?class=["'']*hero-link["'']*>(.*?)</a>.*?<td>.*?class.*?>(.*?)</a>.*?class=["'']*timeago["'']* datetime=["'']*(.*?)T(.*?)Z["'']* title.*?class=["'']*matchid["'']*>(.*?)</a>.*?</tr>'
		$ARRAY_Y = _ArrIN($sData, $REC, $ARRAY_Y)
		ConsoleWrite("-Пастинг "&$Page&" стр выполнен"&@CRLF)
Next

ЗЫ: больше Wait'ов у них не нашел... :'( пошел все свои скриптики переписывать :stars: :'(
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
Мой вариант, примитивнее:

Код:
#include <Array.au3>
#include <Encoding.au3>

Dim $avArray2[1]

For $j = 1 To 10 ; СТРАНИЦЫ
	$sText = _Encoding_CyrillicTo1251(BinaryToString(InetRead('https://ru.dotabuff.com/players/68730725/matches?page=' & $j)))
	$aString = StringRegExp($sText, '">(.{1,50})</a', 3)
	Dim $avArray[Ubound($aString)]
	For $i = 1 To Ubound($aString) - 1
		If StringInStr($aString[$i], 'Победа') Or StringInStr($aString[$i], 'Поражение') Then $avArray[$i]=$aString[$i - 1] & '_' & $aString[$i] & '_' & $aString[$i + 1]
	Next
	_ArrayConcatenate($avArray2, $avArray)
	ReDim $avArray[1]
Next


$avArray2 = _ArrayClearEmpty1($avArray2)

_ArrayDisplay($avArray2)

Func _ArrayClearEmpty1($a_Array, $i_SubItem = 0, $i_Start = 0)
	If Not IsArray($a_Array) Or UBound($a_Array, 0) > 2 Then Return SetError(1, 0, 0)

	Local $i_Index = -1
	Local $i_UBound_Row = UBound($a_Array, 1) - 1
	Local $i_UBound_Column = UBound($a_Array, 2) - 1

	If $i_UBound_Column = -1 Then $i_UBound_Column = 0
	If $i_SubItem > $i_UBound_Column Then $i_SubItem = 0
	If $i_Start < 0 Or $i_Start > $i_UBound_Row Then $i_Start = 0

	Switch $i_UBound_Column + 1
		Case 1
			Dim $a_TempArray[$i_UBound_Row + 1]
			If $i_Start Then
				For $i = 0 To $i_Start - 1
					$a_TempArray[$i] = $a_Array[$i]
				Next
				$i_Index = $i_Start - 1
			EndIf
			For $i = $i_Start To $i_UBound_Row
				If String($a_Array[$i]) Then
					$i_Index += 1
					$a_TempArray[$i_Index] = $a_Array[$i]
				EndIf
			Next
			If $i_Index > -1 Then
				ReDim $a_TempArray[$i_Index + 1]
			Else
				Return SetError(2, 0, 0)
			EndIf
		Case 2
			Dim $a_TempArray[$i_UBound_Row + 1][$i_UBound_Column + 1]
			If $i_Start Then
				For $i = 0 To $i_Start - 1
					For $j = 0 To $i_UBound_Column
						$a_TempArray[$i][$j] = $a_Array[$i][$j]
					Next
				Next
				$i_Index = $i_Start - 1
			EndIf
			For $i = $i_Start To $i_UBound_Row
				If String($a_Array[$i][$i_SubItem]) Then
					$i_Index += 1
					For $j = 0 To $i_UBound_Column
						$a_TempArray[$i_Index][$j] = $a_Array[$i][$j]
					Next
				EndIf
			Next
			If $i_Index > -1 Then
				ReDim $a_TempArray[$i_Index + 1][$i_UBound_Column + 1]
			Else
				Return SetError(2, 0, 0)
			EndIf
	EndSwitch
	Return SetError(0, $i_UBound_Row - $i_Index, $a_TempArray)
EndFunc   ;==>_ArrayClearEmpty1

Почему-то без преобразования кодировки всего текста страницы через Encoding.au3 не работает нормально, что замедляет раза в 4...
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
сайт в кодировке utf-8. Попробуйте BinaryToString с флагом 4.
 
Автор
Belfigor

Belfigor

Модератор
Локальный модератор
Сообщения
3,608
Репутация
941
Расшифруйте мне пожалуйста вот этот паттерн:
Код:
'(?s).*?class=["'']*last["'']*>.*?page=(.*?)["'']*>Last'


И что значат вот эти скобки: ["'']
Если я правильно понимаю то такая конструкция используется чтобы дать скрипту понять что он должен искать двойные кавычки?

И объясните разницу между приведенным выше паттерном и этим:
Код:
'(?si)<span class="last">.*page=(.*?)">Last'


Результат я получаю один и тот же, какой паттерн использовать лучше?
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
второй лучше. Первый просто перегружен не нужными конструкциями типа .*? в начале - что вообще бесполезно. Под эту часть паттерна подходит любой текст. + В первом идет дополнительная обработка класса только для поиска одинарной или двойной ковычки.

Если ковычки могут быть или нет, то лучше cделать так:
Код:
'(?si)<span class=.?last.?>.*?page=(.*?).?>Last'
 
Автор
Belfigor

Belfigor

Модератор
Локальный модератор
Сообщения
3,608
Репутация
941
Ясно, буду иметь ввиду, потихоньку уже разобрался как парсить нужную мне инфу :smile:
 

---Zak---

Скриптер
Сообщения
455
Репутация
120
2 Belfigor
По поводу ["''] - в WinXP при получении HTML-кода есть кавычки, а кто "сидит" в Win7 в коде нет этих кавычек. А таким способом как раз и решил проблему.

["''] - либо есть двойная кавычка - либо вообще ничего нет.

PS: в этих всех понятиях я не очень силен...ибо только недавно начал изучать регулярные выражения. Но как могу - так и придумываю решения)))) inververs скорее всего прав...силен в этом больше, чем я
 
Верх