2012-05-18 3 views
2

Мне нужно извлечь данные примерно с 6000 страниц веб-сайта. После некоторых исследований я решил дать WinHTTP выстрел. Я смог получить эту работу, однако я делал это синхронно, поэтому потребовалось некоторое время, чтобы закончить. Теперь я пытаюсь использовать WinHTTP асинхронно, но я попал в блокпост. Я искал несколько руководств и примеров, но я мог найти только документацию MSDN, которая кажется слишком сложной для того, что я делаю. Как уже упоминалось, я не мог найти много ресурсов, поэтому я пошел вперед и дал ему шанс:Несколько асинхронных запросов WinHTTP

std::string theSource = ""; 
char * httpBuffer; 
DWORD dwSize = 1; 
DWORD dwRecv = 1; 

HINTERNET hOpen = 
      WinHttpOpen 
      (
       L"Example Agent", 
       WINHTTP_ACCESS_TYPE_NO_PROXY, 
       NULL, 
       NULL, 
       WINHTTP_FLAG_ASYNC 
      ); 

WINHTTP_STATUS_CALLBACK theCallback = 
      WinHttpSetStatusCallback 
      (
       hOpen, 
       (WINHTTP_STATUS_CALLBACK) HttpCallback, 
       WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 
       NULL 
      ); 

HINTERNET hConnect = 
      WinHttpConnect 
      (
       hOpen, 
       L"example.org", 
       INTERNET_DEFAULT_HTTPS_PORT, 
       0 
      ); 

HINTERNET hRequest = NULL; 

BOOL allComplete = false; 

int theRequest = 1; 


while (!allComplete) 
{ 
    if (theRequest == 1) 
    { 
     hRequest = WinHttpOpenRequest 
        (
         hConnect, 
         L"GET", 
         L"example.html", 
         0, 
         WINHTTP_NO_REFERER, 
         WINHTTP_DEFAULT_ACCEPT_TYPES, 
         WINHTTP_FLAG_SECURE 
        ); 


     WinHttpSendRequest 
     (
      hRequest, 
      WINHTTP_NO_ADDITIONAL_HEADERS, 
      0, 
      WINHTTP_NO_REQUEST_DATA, 
      0, 
      0, 
      0 
     ); 
    } 

    else if (theRequest == 2) 
    { 
     WinHttpReceiveResponse(hRequest, NULL); 
    } 

    else if (theRequest == 3) 
    { 
     WinHttpQueryHeaders 
     (
      hRequest, 
      WINHTTP_QUERY_RAW_HEADERS_CRLF, 
      WINHTTP_HEADER_NAME_BY_INDEX, 
      NULL, 
      &dwSize, 
      WINHTTP_NO_HEADER_INDEX 
     ); 

     WCHAR * headerBuffer = new WCHAR[dwSize/sizeof(WCHAR)]; 

     WinHttpQueryHeaders 
     (
      hRequest, 
      WINHTTP_QUERY_RAW_HEADERS_CRLF, 
      WINHTTP_HEADER_NAME_BY_INDEX, 
      headerBuffer, 
      &dwSize, 
      WINHTTP_NO_HEADER_INDEX 
     ); 

     delete [] headerBuffer; 

     dwSize = 1; 

     while (dwSize > 0) 
     { 
      if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) 
      { 
       break; 
      } 

      httpBuffer = new char[dwSize + 1]; 

      ZeroMemory(httpBuffer, dwSize + 1); 

      if (!WinHttpReadData(hRequest, httpBuffer, dwSize, &dwRecv)) 
      { 
       std::cout << "WinHttpReadData() - Error Code: " << GetLastError() << "\n"; 
      } 

     else 
     { 
      theSource = theSource + httpBuffer; 
     } 

     delete [] httpBuffer; 

     // Parse the source for the data I'm looking for. 

     break; 

    } 
} 

Ниже моя функция обратного вызова:

void CALLBACK HttpCallback(HINTERNET hInternet, DWORD * dwContext, DWORD dwInternetStatus, void * lpvStatusInfo, DWORD dwStatusInfoLength) 
{ 
    switch (dwInternetStatus) 
    { 
     default: 
      std::cout << dwInternetStatus << "\n"; 
      break; 

     case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED: 
      std::cout << "Handle created.\n"; 
      theRequest = 1; 
      break; 

     case WINHTTP_CALLBACK_STATUS_REQUEST_SENT: 
      std::cout << "Request sent.\n"; 
      theRequest = 2; 
      break; 

     case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: 
      std::cout << "Response received.\n"; 
      theRequest = 3; 
      break; 

    } 
} 

Примечание: Я только при условии этот раздел моего кода, поскольку это часть, относящаяся к моему вопросу/проблеме. Прошу прощения, если отсутствует объявление переменной.

Приведенный выше код работает для меня и фактически получает желаемую информацию, которую я ищу, но только для одной страницы. Подойдя к этому моменту, я понял, что не имел никакого представления о том, что делать, когда речь идет о создании нескольких запросов с помощью этого метода. Опять же, поиск не включался в многое кроме статей MSDN, которые, насколько я могу судить, не являются примерами, которые делают сразу несколько запросов. Кроме того, цикл while, который я использую для открытия/отправки/etc. запросы, основанные на значении Request, кажутся ужасным способом сделать это. Я был бы признателен за любые другие советы по улучшению моего кода.

В общем, вот резюме моей проблемы: мне нужно сделать около 6000 запросов GET с использованием WinHTTP асинхронно. Я не совсем уверен, как это сделать, потому что я новичок в WinHTTP, поэтому я ищу наиболее простой (или, возможно, эффективный) способ работы с несколькими асинхронными запросами.

+0

Вы видите эту статью MSDN: [Асинхронный WinHTTP] (http://msdn.microsoft.com/en-us/magazine/cc716528.aspx)? И, возможно, этот однопоточный, многопроцессорный и простой в понимании [Perl API 'HTTP :: Async'] (https://metacpan.org/module/HTTP::Async) может дать вам некоторое вдохновение в том, как действовать дальше. – Lumi

ответ

2

Вы должны повторить то, что вы делаете в while (!allComplete) { ... }, и снимать больше запросов таким образом. Вы можете повторно использовать hConnect, но вам нужно сделать WinHttpOpenRequest для каждого запроса на ресурс.

+0

Не могли бы вы разработать или предоставить примерный код? Последний был бы самым полезным для меня, если это было возможно. Я не могу понять, как я могу включить дополнительные запросы в мой цикл и все равно следить за ними. Я не буду зависеть от значений Request для запросов заголовков или чтения данных, так как каждый запрос будет изменять это значение через функцию обратного вызова в любой момент времени на основе текущего кода. –

+1

'theRequest' не может быть глобальным в этом сценарии, он будет специфичен для конкретного' hRequest'. Таким образом, вам понадобится некая коллекция структур с значениями 'theRequest' +' hRequest'. –

Смежные вопросы