1 (изменено: john_dease, 2024-02-04 08:02:10)

Тема: AHK: WinHTTPRequest

Добрый день. Не удается понять причину, по которой обрывается скачивание для файлов размером больше 20 МБ. Есть два файла по следующим двум ссылкам -


https://view.nebdeti.ru/web/viewer.html?item_id=ea8497ee-4d5a-49f0-8a29-c60fdc2dcd60
https://view.nebdeti.ru/web/viewer.html?item_id=67093957-673b-4871-9aff-41b237f8732a

Первый скачивается нормально, так как он небольшой (3 мб), а второй загружается битым примерно на 20-ти мегабайтах, хотя в браузере видно, что он прогружается полностью. И это относится к попытке скачивания любых файлов этого сайта.

В коде приведены две ссылки - незакомментированная переменная "page_id" по умолчанию скачивает небольшой файл, а закоментированная - 40-мегабайтный.

+ открыть спойлер
HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")

page_id := "ea8497ee-4d5a-49f0-8a29-c60fdc2dcd60"
;page_id := "67093957-673b-4871-9aff-41b237f8732a"

page_link := "https://nebdeti.ru/viewer/item.php?id=" page_id

HTTP.Open("GET", page_link, 1)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36")
HTTP.SetRequestHeader("Pragma", "no-cache")
;HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")

HTTP.SetRequestHeader("scheme", "https")
HTTP.SetRequestHeader("accept", "*/*")
;HTTP.SetRequestHeader("accept-encoding", "gzip, deflate, br")
HTTP.SetRequestHeader("accept-language", "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7")
HTTP.SetRequestHeader("origin", "https://view.nebdeti.ru")
HTTP.SetRequestHeader("referer", page_link)
HTTP.SetRequestHeader("sec-ch-ua", """ Not A;Brand"";v=""99"", ""Chromium"";v=""102""")
HTTP.SetRequestHeader("sec-ch-ua-mobile", "?0")
HTTP.SetRequestHeader("sec-ch-ua-platform", """Windows""")
HTTP.SetRequestHeader("sec-fetch-dest", "empty")
HTTP.SetRequestHeader("sec-fetch-mode", "cors")
HTTP.SetRequestHeader("sec-fetch-site", "cross-site")
HTTP.SetRequestHeader("cookie", "test-cookie=1")

HTTP.Send()
HTTP.WaitForResponse()
Body := HTTP.ResponseBody

pData := NumGet(ComObjValue(Body), A_PtrSize = 8? 16:12, "ptr")
File := FileOpen(A_ScriptDir "\" page_id " " a_now ".pdf", "w")
File.RawWrite(pData + 0, Body.MaxIndex() + 1)
File.Close()
return

2

Re: AHK: WinHTTPRequest

Скачивайте через winhttp.dll напрямую.

3

Re: AHK: WinHTTPRequest

К сожалению, не нашлось ничего про запуск через winhttp.dll - у нас на форуме только несколько упоминаний. На англ. форуме попался ваш код, но вот так скачать файл не получилось:

+ открыть спойлер
ServerName := "nebdeti.ru"
ObjectName := "/viewer/item.php?id=67093957-673b-4871-9aff-41b237f8732a"
noredirect := true


hModule := DllCall("LoadLibrary", "str", "winhttp.dll", "ptr")
if !hModule
   msgbox hmodule failed`n%A_LastError%
hSession := DllCall("winhttp\WinHttpOpen", "str", "autohotkey", "uint", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY := 0, "ptr", WINHTTP_NO_PROXY_NAME := 0, "ptr", WINHTTP_NO_PROXY_BYPASS := 0, "uint", 0, "ptr")
if !hSession
   msgbox WinHttpOpen failed`n%A_LastError%
hConnect := DllCall("winhttp\WinHttpConnect", "ptr", hSession, "str", ServerName, "uint", INTERNET_DEFAULT_HTTPS_PORT := 443, "uint", 0, "ptr")
if !hConnect
   msgbox WinHttpConnect failed`n%A_LastError%
hRequest := DllCall("winhttp\WinHttpOpenRequest", "ptr", hConnect, "str", "get", "str", ObjectName, "ptr", 0, "ptr", WINHTTP_NO_REFERER := 0, "ptr", WINHTTP_DEFAULT_ACCEPT_TYPES := 0, "uint", 0x00800000|0x00000100, "ptr")   ; WINHTTP_FLAG_SECURE|WINHTTP_FLAG_REFRESH
if !hRequest
   msgbox WinHttpOpenRequest failed`n%A_LastError%
if noredirect
{
   option := 2   ; WINHTTP_DISABLE_REDIRECTS
   bResults := DllCall("Winhttp.dll\WinHttpSetOption", "ptr", hRequest, "uint", WINHTTP_OPTION_DISABLE_FEATURE := 63, "ptr", &option, "uint", 1)
   if !bResults
      msgbox WinHttpSetOption failed`n%A_LastError%
}
bResults := DllCall("winhttp\WinHttpSendRequest", "ptr", hRequest, "ptr", WINHTTP_NO_ADDITIONAL_HEADERS := 0, "uint", 0, "ptr", 0, "uint", 0, "uint", 0, "ptr", 0)
if !bResults
   msgbox WinHttpSendRequest failed`n%A_LastError%
bResults := DllCall("winhttp\WinHttpReceiveResponse", "ptr", hRequest, "ptr", 0)
if !bResults
   msgbox WinHttpReceiveResponse failed`n%A_LastError%
else
{
   bResults := DllCall("winhttp\WinHttpQueryHeaders", "ptr", hRequest, "uint", WINHTTP_QUERY_RAW_HEADERS_CRLF := 22, "ptr", WINHTTP_HEADER_NAME_BY_INDEX := 0, "ptr", WINHTTP_NO_OUTPUT_BUFFER := 0, "uint*", dwSize, "ptr", WINHTTP_NO_HEADER_INDEX := 0)
   {
      if !bResults and (A_LastError = 0x7A) ; ERROR_INSUFFICIENT_BUFFER
      {
         VarSetCapacity(outBuffer, dwSize + 2)
         DllCall("winhttp\WinHttpQueryHeaders", "ptr", hRequest, "uint", WINHTTP_QUERY_RAW_HEADERS_CRLF := 22, "ptr", WINHTTP_HEADER_NAME_BY_INDEX := 0, "ptr", &outBuffer, "uint*", dwSize, "ptr", WINHTTP_NO_HEADER_INDEX := 0)
         msgbox % StrGet(&outBuffer, "UTF-16")
      }
      else
         msgbox WinHttpQueryHeaders failed`n%A_LastError%
   }
}
if hRequest
   DllCall("winhttp\WinHttpCloseHandle", "ptr", hRequest)
if hConnect
   DllCall("winhttp\WinHttpCloseHandle", "ptr", hConnect)
if hSession
   DllCall("winhttp\WinHttpCloseHandle", "ptr", hSession)
DllCall("FreeLibrary", "ptr", hModule)

4

Re: AHK: WinHTTPRequest

Для изучения, но нужно будет внести пару правок.
https://www.autohotkey.com/boards/viewt … mp;t=17370

5

Re: AHK: WinHTTPRequest

Перепробовал все коды, но остальные части не докачиваются. Что тут не учтено? -

vUrl := "https://nebdeti.ru/viewer/item.php?id=b3ffbe51-d1e5-44c3-8b3a-d1d77ad4f04c"
SavePath := A_ScriptDir "file.pdf"

WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WebRequest.Open("GET", vUrl)
WebRequest.SetRequestHeader("Range", "bytes=0-10000000000")
WebRequest.SetRequestHeader("referer", vUrl)
WebRequest.SetRequestHeader("cookie", "test-cookie=1")
WebRequest.Send()
SaveResponseBody(WebRequest, "1-100.bin")
return

SaveResponseBody(WinHttpObj, SavePath) {
	ado := ComObjCreate("adodb.stream")
	ado.Type := 1 ; adTypeBinary = 1
	ado.Open()
	ado.Write( WinHttpObj.ResponseBody )
	ado.SaveToFile( SavePath, 2 ) ; adSaveCreateOverWrite = 2
	ado.Close()
}

6

Re: AHK: WinHTTPRequest

Я написал использовать winhttp.dll напрямую, а вы используете ее ком объект.
Я, да и не только я, писали вам не устанавливать лишние хедеры, а вы их всё-равно устанавливаете.
Из всей той кучи, которую вы копипастите, на данном сайте нужен только referrer.

7

Re: AHK: WinHTTPRequest

В следующем коде отредактировал диапазон байтов, но затрудняюсь правильно вписать referer:

+ открыть спойлер

;WebRequest.SetRequestHeader("referer", vUrl)

vUrl := "https://nebdeti.ru/viewer/item.php?id=b3ffbe51-d1e5-44c3-8b3a-d1d77ad4f04c"

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SetBatchLines -1
ListLines Off

WINHTTP_NO_PROXY_NAME     := 0
WINHTTP_NO_PROXY_BYPASS   := 0

WINHTTP_ACCESS_TYPE_DEFAULT_PROXY   := 0
WINHTTP_ACCESS_TYPE_NO_PROXY   := 1
WINHTTP_ACCESS_TYPE_NAMED_PROXY     := 3
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY := 4

INTERNET_DEFAULT_PORT := 0
INTERNET_DEFAULT_HTTP_PORT := 80
INTERNET_DEFAULT_HTTPS_PORT := 443

WINHTTP_NO_REFERER := 0
WINHTTP_DEFAULT_ACCEPT_TYPES := 0

WINHTTP_NO_ADDITIONAL_HEADERS := 0
WINHTTP_NO_REQUEST_DATA  := 0

hModule := DllCall("LoadLibrary", "Str", "winhttp.dll", "Ptr")

if (hModule)
  hSession := DllCall("winhttp\WinHttpOpen", "WStr", "WinHTTP Example/1.0"
          ,"UInt", WINHTTP_ACCESS_TYPE_NO_PROXY ; Probably want WINHTTP_ACCESS_TYPE_DEFAULT_PROXY here
          ,"Ptr", WINHTTP_NO_PROXY_NAME
          ,"Ptr", WINHTTP_NO_PROXY_BYPASS
          ,"UInt", 0
          ,"Ptr")

if (hSession)
  hConnect := DllCall("winhttp\WinHttpConnect", "Ptr", hSession
           ,"WStr", "nebdeti.ru" ; hostname of site to download from
           ,"UInt", INTERNET_DEFAULT_HTTP_PORT
           ,"UInt", 0
           ,"Ptr")

if (hConnect)
  hRequest := DllCall("winhttp\WinHttpOpenRequest", "Ptr", hConnect
        ,"WStr", "GET"
        ,"WStr", "/viewer/item.php?id=b3ffbe51-d1e5-44c3-8b3a-d1d77ad4f04c" ; path to access on host - you can use the WinHttpCrackUrl() function to break a URL down into its parts, look at Bruttosozialprodukt's posts for the DllCall
        ,"Ptr", 0
        ,"Ptr", WINHTTP_NO_REFERER
        ,"Ptr", WINHTTP_DEFAULT_ACCEPT_TYPES
        ,"UInt", 0
        ,"Ptr")

headers := "Range: bytes=0-450673718" ; range given here
if (hRequest)
  bResults := DllCall("winhttp\WinHttpSendRequest", "Ptr", hRequest
        ,"WStr", headers
        ,"UInt", -1
        ,"Ptr", WINHTTP_NO_REQUEST_DATA
        ,"UInt", 0
        ,"UInt", 0
        ,"Ptr", 0)

if (bResults)
  bResults := DllCall("winhttp\WinHttpReceiveResponse", "Ptr", hRequest, "Ptr", NULL)

if (bResults)
{
  hFile := FileOpen(A_ScriptDir "\" a_now ".pdf", "w") ; open the file named in the first argument for writing
  Loop
  {
    if (!DllCall("winhttp\WinHttpQueryDataAvailable", "Ptr", hRequest, "UInt*", dwSize))
    {
      MsgBox Error %A_LastError% in WinHttpQueryDataAvailable
      break
    }
    if (dwSize <= 0)
      break
    if (VarSetCapacity(pszOutBuffer, dwSize + 1, 0) < dwSize)
    {
      MsgBox % Out of memory
      break
    }
    if (!DllCall("winhttp\WinHttpReadData", "Ptr", hRequest, "Ptr", &pszOutBuffer, "UInt", dwSize, "UInt*", dwDownloaded))
      MsgBox Error %A_LastError% in WinHttpReadData
    else
      hFile.RawWrite(pszOutBuffer, dwDownloaded) ; write the downloaded bytes to the file
  }
  hFile.Close()
}

if (!bResults)
  MsgBox Error %A_LastError% has occurred

if (hRequest) DllCall("winhttp\WinHttpCloseHandle", "Ptr", hRequest)
if (hConnect) DllCall("winhttp\WinHttpCloseHandle", "Ptr", hConnect)
if (hSession) DllCall("winhttp\WinHttpCloseHandle", "Ptr", hSession)

DllCall("FreeLibrary", "Ptr", hModule)
return

8

Re: AHK: WinHTTPRequest

Устанавливать хедер с диапозоном байтов не нужно.
Referer устанавливается тут:
https://learn.microsoft.com/en-us/windo … penrequest

9 (изменено: john_dease, 2024-02-06 19:49:42)

Re: AHK: WinHTTPRequest

Спасибо!

10 (изменено: john_dease, 2024-02-07 08:41:44)

Re: AHK: WinHTTPRequest

Так понимаю, если перед этим кодом залогиниться через ком объект, то фрагмент с winhttp.dll логин не подхватывает? Как добавляется инфа о логине?

11

Re: AHK: WinHTTPRequest

Передавайте куки.

12

Re: AHK: WinHTTPRequest

Как присоединить куки к этой строчке? -

headers := "referer: " url

Такие варианты не срабатывают:

headers =
(
referer: %url%
cookie: %cookie%
)

13

Re: AHK: WinHTTPRequest

Без понятия почему не срабатывает.
Заниматься вашим сайтом возьмусь только платно.

14

Re: AHK: WinHTTPRequest

Имелось в виду, как в этом коде правильно указать более одного хедера? То есть, до моей правки на реферер, там был хедер для диапазона байтов:

headers := "Range: bytes=0-450673718"

А в каком формате к нему добавлять еще один хедер? Или это правильный формат? -

headers =
(
referer: %url%
cookie: %cookie%
)

15

Re: AHK: WinHTTPRequest

А кто вам мешает проверить это самому?

16

Re: AHK: WinHTTPRequest

Я проверил — не работает. Просто вы сказали что без понятия, почему не срабатывает - из чего могло следовать, что по формату должно срабатывать.

17 (изменено: Malcev, 2024-02-07 17:08:40)

Re: AHK: WinHTTPRequest

Чтобы понимать почему не работает надо копаться с сайтом, может юзер-агент должен быть идентичным, может еще что, может куки не те отправляете.
Мне в этом копаться неинтересно.

headers =
(
header1: qwert
referer: %url%
header2: qwertyu
)

Если реферер отправляется, то запись правильная.

18

Re: AHK: WinHTTPRequest

Именно куков в дополнение должно быть достаточно - это видно по работе кода через ком объект для ПДФ-файлов небольшого размера, которые нормально грузятся с реферером и логином. Что означает, что куки из логина они подхватывают и скачивают файл. Но код для winhttp.dll нужен для скачивания больших файлов, но в нем непонятно, как прописывать несколько хедеров, и посмотреть нет возможности, так как код мало использовался.

19

Re: AHK: WinHTTPRequest

Если файл скачивается только при отправки в хедерсах рефёрера, то если так файл скачивается, то запись правильная:

headers =
(
header1: qwert
referer: %url%
header2: qwertyu
)

20

Re: AHK: WinHTTPRequest

Спасибо, заработало. Только не понятно, почему логин после авторизации не возвращает куки. К примеру, следующий код логинится, но GetAllResponseHeaders не выводит куки. Есть ли другая команда для показа куки?

login := "ПОЧТА"
pass := "ПАРОЛЬ"

HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
HTTP.Open("POST", "https://nebdeti.ru/authorization", true)
HTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36")
HTTP.SetRequestHeader("referer", "https://nebdeti.ru/authorization")
HTTP.Send("login=" login "&pass=" pass)
HTTP.WaitForResponse()
;RTxt := HTTP.ResponseText
;msgbox % RTxt
msgbox % HTTP.GetAllResponseHeaders

21

Re: AHK: WinHTTPRequest

Нет. Но они могут быть защифрованы в исходном коде страницы.

22 (изменено: Malcev, 2024-02-07 19:10:03)

Re: AHK: WinHTTPRequest

Логиньтесь через winhttp.dll напрямую. По приведённым ссылкам достаточно информации.
Хедеры по правилам разделять `r`n, хотя у меня всегда и с `n работало.
https://learn.microsoft.com/en-us/windo … estheaders

23

Re: AHK: WinHTTPRequest

А как там Send указывать?

HTTP.Send("login=" login "&pass=" pass)

Пробовал в headers и сюда вписывать:

if (hRequest)
  bResults := DllCall("winhttp\WinHttpSendRequest", "Ptr", hRequest
        ,"WStr", headers
        ,"UInt", -1
        ,"Ptr", WINHTTP_NO_REQUEST_DATA
        ,"UInt", 0
        ,"UInt", 0
        ,"Ptr", 0)

24

Re: AHK: WinHTTPRequest

Лень писать. Гуглите примеры.

25

Re: AHK: WinHTTPRequest

Примеров не нашлось - сделал с извлечением кук со страницы. Спасибо!

26

Re: AHK: WinHTTPRequest

А как вы ищите?
Если в поиске на оф. сайте вставить WinHttpSendRequest, то выйдет следующая ссылка:
https://www.autohotkey.com/boards/viewt … amp;t=4038

27 (изменено: john_dease, 2024-02-08 23:16:41)

Re: AHK: WinHTTPRequest

По вашему совету через гугл смотрел. Наверно и так сойдет, тем более что через КОМ короче получается код и его можно запускать с try/catch на случай ошибки соединения:

loop
   {
      HTTP.Open("GET", URL, true)
      try {
         HTTP.Send()
         HTTP.WaitForResponse()
         break
      }
      catch {
         Sleep, 5000
      }
   }

28

Re: AHK: WinHTTPRequest

Пример логина:

login := "qwerty@qwerty.com"
pass := "qwerty"
data := "login=" login "&pass=" pass "&"

DllCall("LoadLibrary", "str", "winhttp.dll", "ptr")
hSession := DllCall("winhttp\WinHttpOpen", "str", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", "uint", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY := 0, "ptr", WINHTTP_NO_PROXY_NAME := 0, "ptr", WINHTTP_NO_PROXY_BYPASS := 0, "uint", 0, "ptr")
hConnect := DllCall("winhttp\WinHttpConnect", "ptr", hSession, "str", "nebdeti.ru", "uint", INTERNET_DEFAULT_HTTPS_PORT := 443, "uint", 0, "ptr")
hRequest := DllCall("winhttp\WinHttpOpenRequest", "ptr", hConnect, "str", "POST", "str", "/authorization", "ptr", 0, "str", "https://nebdeti.ru/authorization", "ptr", WINHTTP_DEFAULT_ACCEPT_TYPES := 0, "uint", 0x00800000|0x00000100, "ptr")   ; WINHTTP_FLAG_SECURE|WINHTTP_FLAG_REFRESH
len := strput(data, "utf-8")
varsetcapacity(body, len, 0)
strput(data, &body, "utf-8")
DllCall("winhttp\WinHttpSendRequest", "ptr", hRequest, "str", "Content-Type: application/x-www-form-urlencoded", "uint", -1, "ptr", &body, "uint", len, "uint", len, "ptr", 0)
DllCall("winhttp\WinHttpReceiveResponse", "ptr", hRequest, "ptr", 0)
varsetcapacity(pszOutBuffer, 100000, 0)
DllCall("winhttp\WinHttpReadData", "ptr", hRequest, "ptr", &pszOutBuffer, "uint", 100000, "uint*", dwDownloaded)
msgbox % ResponseText := strget(&pszOutBuffer, "utf-8")
DllCall("winhttp\WinHttpCloseHandle", "ptr", hRequest)
DllCall("winhttp\WinHttpCloseHandle", "ptr", hConnect)
DllCall("winhttp\WinHttpCloseHandle", "ptr", hSession)