Информация о web-ресурсах

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Имеется в базе данных список с URL-адресами. Нужно получить краткую информацию о каждом из этих ресурсов: например строку, которая отображается в заголовке веб-браузера при загрузке данной страницы. Либо получить ответ, что такой сетевой адрес не существует.
Каким наиболее простым способом это можно сделать?
Albor
Сообщения: 491
Зарегистрирован: 06 сен 2004, 13:34
Откуда: Днепропетровск

Можно через компонент CWebBrowser2, загружая в него страницу.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Информация о веб-странице, отображаемая в заголовке окна веб-браузера, содержится в в тегах title. В HTML-коде это так выглядит:
[html]
<title>Название страницы...</title>
[/html]
Обычно эти тэги располагаются в начале HTML-файла, а тебе нужно лишь распознать их в тексте и извлечь соответствующую строку.
Примитивный алгоритм для этого на C++/CLI примерно так выглядит:

Код: Выделить всё

#include "stdafx.h"
 
using namespace System;
 
String^ GetHtmlTitle(String^ text)
{
 String^ tag = L"<title>";
 int nTitle = text->IndexOf(tag);
 int nTitleEnd = text->IndexOf(L"</title>", nTitle);
 return text->Substring(nTitle, nTitleEnd-nTitle)->Replace(tag, L"");
}
 
int main(array<String ^> ^args)
{
 array<String^> ^urlList =
 {
  L"[URL]http://www.microsoft.com[/URL]",
  L"[URL]http://www.google.com[/URL]",
  L"[URL]http://www.yahoo.com[/URL]",
  L"[URL]http://www.apple.com[/URL]",
  L"[URL]http://www.ibm.com[/URL]",
  L"[URL]http://www.sun.com[/URL]",
  L"[URL]http://www.mail.ru[/URL]",
  L"[URL]http://www.Akhgf337458hiksjdl.com[/URL]" // bad address
 };
 //
 Net::WebClient^ wc = gcnew Net::WebClient();
 for each (String^ url in urlList)
 {
  try
  {
   String^ text = wc->DownloadString(url);
   if (text->Length > 0)
   {
    Console::InputEncoding = Text::Encoding::UTF8;
    Console::WriteLine(GetHtmlTitle(text));
   }
  }
  catch (Net::WebException^ ex)
  {
   Console::WriteLine(ex->Message);
  }
 }
 Console::Read();
 //
    return 0;
}

Дело ещё в том, что текст в разных веб-страницах может иметь разную кодировку, поэтому его придётся перекодировать для правильного отображения. Кодировка текста обозначается ключевым словом charset.
В HTML-коде она обычно так представлена:
[html]
<meta content="text/html;charset=windows-1251" http-equiv="Content-Type">
[/html]
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Спасибо, WinMain. Твой пример замечательно работает, только мне теперь и к базе данных придётся обращаться через don't Net. А я по старинке все запросы к СУБД делаю через MFC.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Можно и обычными функциями Win32API обойтись. Если будет интересно, могу пример написать.
А ты чего платформу .NET называешь "don't Net"?
Это типа I don't like the Net? Чем она тебя не так устраивает?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Я подозреваю, что он пишет то, что на слуху воспринял :) Читается dot net, а он услышал don't net :)
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

WinMain, если не трудно, напиши ещё пару своих примеров на тему закачки данных из сети. А я тогда уже выберу тот способ, который мне больше понравится.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Самый простой способ (на Win32API) загрузить файл по HTTP-протоколу - это вызвать функцию URLDownloadToFile или с помощью функции URLOpenBlockingStream читать данные прямо из потока.
Вот пример:

Код: Выделить всё

[size=84][color=#0000ff][size=84][color=#0000ff]#include[/color][/size][/color][/size][size=84][color=#800000][size=84][color=#800000]"stdafx.h"[/color][/size]
[/color][/size][size=84][color=#0000ff][size=84][color=#0000ff]#include[/color][/size][/color][/size][size=84][color=#800000][size=84][color=#800000]<UrlMon.h>[/color][/size][/color][/size]
 
[size=84][color=#0000ff][size=84][color=#0000ff]#pragma [/color][/size][/color][/size][size=84][color=#0000ff][size=84][color=#0000ff]comment[/color][/size][/color][/size][size=84] ([/size][size=84][color=#0000ff][size=84][color=#0000ff]lib[/color][/size][/color][/size][size=84], [/size][size=84][color=#800000][size=84][color=#800000]"urlmon.lib"[/color][/size][/color][/size][size=84])[/size]
 
[size=84][color=#0000ff][size=84][color=#0000ff]int[/color][/size][/color][/size][size=84] _tmain([/size][size=84][color=#0000ff][size=84][color=#0000ff]int[/color][/size][/color][/size][size=84] argc, _TCHAR* argv[])[/size]
[size=84]{[/size]
[size=84]  LPCTSTR pszUrl = _T([/size][size=84][color=#800000][size=84][color=#800000]"http://www.yandex.ru"[/color][/size][/color][/size][size=84]);[/size]
[size=84]  LPCTSTR pszFile = _T([/size][size=84][color=#800000][size=84][color=#800000]"yandex.html"[/color][/size][/color][/size][size=84]);[/size]
[size=84]  ::URLDownloadToFile(NULL, pszUrl, pszFile, 0, NULL);[/size]
[size=84]  _fputts(_T([/size][size=84][color=#800000][size=84][color=#800000]"Downloading has been completed.\n"[/color][/size][/color][/size][size=84]), stdout);[/size]
[size=84]  _gettc(stdin);[/size]
[size=84][color=#0000ff][size=84][color=#0000ff]  return[/color][/size][/color][/size][size=84] 0;[/size]
[size=84]}[/size]
Правда здесь есть одно ограничение: таким образом использовать функцию можно для небольших файлов. Если нужно загрузить большой файл, то в качестве параметра функции нужно передавать указатель на интерфейс IBindStatusCallback, который нужно будет самому имплементировать. Тогда через его метод OnProgress можно получать информацию о текущем состоянии процесса загрузки.
Ещё проблема: эта функция не работает в сетях, где требуется дополнительная аутентификация пользователя при входе в интернет, а так же через модем может не работать.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Спасибо, WinMain. У меня эта функция нормально работает.
А готовый пример имплементации IBindStatusCallback у тебя имеется?
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Используй мой вариант имплементации в качестве базового класса. Унаследуйся от него и переопредели в нём метод OnProgress ().

Код: Выделить всё

class CBindStatusImpl : public IBindStatusCallback
{
public:
 virtual ULONG STDMETHODCALLTYPE 
  AddRef(void){return 0U;}
 virtual ULONG STDMETHODCALLTYPE 
  Release(void){return 0U;}
 virtual HRESULT STDMETHODCALLTYPE 
  QueryInterface(REFIID iid, void ** ppvObject){return S_OK;} 
 //
 virtual HRESULT STDMETHODCALLTYPE 
  GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindinfo){return S_OK;}
 virtual HRESULT STDMETHODCALLTYPE 
  GetPriority(LONG *pnPriority){return S_OK;}
 virtual HRESULT STDMETHODCALLTYPE 
  OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed){return S_OK;}
 virtual HRESULT STDMETHODCALLTYPE 
  OnObjectAvailable(REFIID riid, IUnknown *punk){return S_OK;}
 virtual HRESULT STDMETHODCALLTYPE 
  OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText){return S_OK;}
 virtual HRESULT STDMETHODCALLTYPE 
  OnStartBinding(DWORD dwReserved, IBinding *pib){return S_OK;}
 virtual HRESULT STDMETHODCALLTYPE 
  OnStopBinding(HRESULT hresult,LPCWSTR szError){return S_OK;}
 virtual HRESULT STDMETHODCALLTYPE 
  OnLowResource(DWORD reserved){return S_OK;}
};
Есть ещё готовая имплементация в библиотеке ATL в виде шаблона, но тот вариант лучше использовать в контексте разрабатываемого СОМ-объекта.
Ответить