Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.51/83: Рейтинг темы: голосов - 83, средняя оценка - 4.51
10 / 10 / 2
Регистрация: 17.06.2010
Сообщений: 107
Записей в блоге: 1
1

Парсер HTML

01.01.2011, 09:47. Просмотров 16608. Ответов 35
Метки нет (Все метки)

Здравствуйте! Нигде не могу найти парсера HTML на Си/С++, помогите кто чем может!

На PHP все просто выходит в две строки, но надо именно на С++ для реализации многопоточности

Например такая строка
HTML5
1
<h2><a href="http://www.site.ru/something/" rel="bookmark" title="Текст1">Текст2</a></h2>
Нужно получить ссылку и текст2.
На пхп все реализуется в две строки:
PHP
1
2
$grab = file_get_contents("http://www.site.ru");//скачиваем страницу
preg_match("/<h2><a href=\"(.*)\/"[^\"]/",$grab,$urls);//разбираем ее регулярным выражением
Как тоже самое реализуется на Си?
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.01.2011, 09:47
Ответы с готовыми решениями:

Вопрос про Парсер HTML с помощью Indy
Доброе время суток... У меня возникла проблема... Собираю парсер html, и когда вытягиваю из...

HTML парсер
Доброе время суток. Проблема такова: Читаю с помощью WebClient хтмл, сайта. Нахожу тайтл с...

HTML Парсер
Помогите кто-нибудь написать парсер html страницы на php. Парсить нужно...

Html парсер на QT
Добрый день! Я понимаю, что мой вопрос очень абстрактен. Я хочу реализовать програмку на Qt,...

35
7 / 6 / 0
Регистрация: 22.06.2010
Сообщений: 96
05.01.2011, 15:07 2
Вот, моя зарисовочка. Парсит все гиперлинки, но пока она не идеальна:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void __fastcall TForm1::Button3Click(TObject *Sender)
{
 
Memo2->Clear();
 
AnsiString One;
 
Memo1->Lines->LoadFromFile("baza.txt");
 
One=Memo1->Lines->Text;
 
int p,p2;
 
 while (One.Pos("<a href=")&&One.Pos("</a>")) {
 
 
  if (p == 0 && p2 == 0) break;
 
p=One.Pos("<a href=");
p2=One.Pos("</a>");
AnsiString Value="";
Value=One.SubString(p,p2-p);
if (p!=0&&p2!=0) Memo2->Lines->Add(Value+"</a><br>");
 
 int sPos = One.Pos("<a href=");
  int ePos = One.Pos("</a>");
  if (sPos == 0 && ePos == 0) break;
  if (sPos != 0) One.Delete(sPos,1);
  if (ePos != 0) One.Delete(ePos,1);
}
 
}
Ссылки вырезает, но здесь нужно еще продумать варианты, а времени нет.

Если у кого есть готовый парсер, пожалуйста выложите, тоже нужно!
1
Evg
Эксперт CАвтор FAQ
21130 / 8146 / 628
Регистрация: 30.03.2009
Сообщений: 22,459
Записей в блоге: 30
05.01.2011, 16:31 3
Есть специальные библиотеки для работы с регулярными выражениями. Что-то есть в составе Boost. В своей программе все коды по парсингу страниц я вынес в отдельные Lua-скрипты (чтобы не затаскивать в бинарник то, что по сути от меня не зависит)
1
7 / 6 / 0
Регистрация: 22.06.2010
Сообщений: 96
05.01.2011, 16:55 4
Цитата Сообщение от Evg Посмотреть сообщение
В своей программе все коды по парсингу страниц я вынес в отдельные Lua-скрипты
- с этого места по-подробнее, и с примерами!
1
LK
Заблокирован
05.01.2011, 17:32 5
Цитата Сообщение от pascyber1 Посмотреть сообщение
- с этого места по-подробнее, и с примерами!
- Evg Вам что-то задолжал , чтот Вы так требовательно орете ?
1
Evg
Эксперт CАвтор FAQ
21130 / 8146 / 628
Регистрация: 30.03.2009
Сообщений: 22,459
Записей в блоге: 30
05.01.2011, 17:40 6
Цитата Сообщение от pascyber1 Посмотреть сообщение
- с этого места по-подробнее, и с примерами!
https://www.cyberforum.ru/cpp-... 68085.html
2
Эксперт С++
3936 / 1801 / 184
Регистрация: 21.11.2009
Сообщений: 2,540
05.01.2011, 17:43 7
pascyber1, вспомнил, когда-то давно использовал регулярные выражения для получения данных с погодного сайта...
Вот вам пример, часть кода этой программы:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <boost/regex.hpp>
#include <boost/spirit/core.hpp>
#include <boost/spirit/actor/push_back_actor.hpp>
#include <vector>
#include <string>
 
//...
 
std::string s(Form1->IdHTTP1->Get(SiteURL.t_str());
for (int i = 0; i < 4; i++) {
// Контейнер для значений
std::vector<std::string>values;
// Выражение для разбора
boost::regex expression("[^-+0-9]+");
 
switch (i) {
  case 0: s = forecast1; break;
  case 1: s = forecast2; break;
  case 2: s = forecast3; break;
  case 3: s = forecast4; break;
}
 
// Разбор и заполнение контейнера
if (regex_split(back_inserter(values), s, expression)) {
  int j = 0;
  weather[i].dd = StrToInt(values[j++].c_str());
  weather[i].mm = StrToInt(values[j++].c_str());
  weather[i].yy = StrToInt(values[j++].c_str());
}
 
// ...
Описание символов ищите в справочной системе или с помощью поисковика.
1
7 / 6 / 0
Регистрация: 22.06.2010
Сообщений: 96
05.01.2011, 18:05 8
MikeSoft, спасибо, но палец можно сломать. Не-а, это не мой уровень. Мне бы попроще. Но, я так понимаю, готового парсера нет ни у кого. Прийдётся ломать голову самому.
1
Evg
Эксперт CАвтор FAQ
21130 / 8146 / 628
Регистрация: 30.03.2009
Сообщений: 22,459
Записей в блоге: 30
05.01.2011, 18:10 9
Цитата Сообщение от pascyber1 Посмотреть сообщение
Не-а, это не мой уровень
Тогда на Lua сразу забей

Цитата Сообщение от pascyber1 Посмотреть сообщение
Но, я так понимаю, готового парсера нет ни у кого
boost - это по сути дела готовый парсер (а точнее, библиотека для готового парсера). Написать код, который из твоей конкретной строки достанет нужные данные - не вопрос. Но он будет работать только для конкретно данной строки. Шаг влево или вправо - работать скорее всего не будет. Поскольку ты имеешь дело с сайтом, то там могут что-то менять со временем
1
7 / 6 / 0
Регистрация: 22.06.2010
Сообщений: 96
05.01.2011, 18:23 10
Цитата Сообщение от Evg Посмотреть сообщение
Шаг влево или вправо - работать скорее всего не будет. Поскольку ты имеешь дело с сайтом, то там могут что-то менять со временем
- да, действительно, проблема это большая. Немножко погуглив, я понял, что идеального парсера сделать проблематично. Взять хотя бы строгое соответствие (или как говорят, валидность) HTML. Тут, нужно предпологать варианты, что кто-то, например на сайте, расположил так :
HTML5
1
<b><i>пример</b></i>
, или не закрыл таги (или теги?). В общем, для каждого сайта - свой парсер, имхо. Ну, или продумывать все варианты по HTML, которые могут выкинуть создатели HTML-страниц...
1
83 / 18 / 2
Регистрация: 17.11.2010
Сообщений: 107
05.01.2011, 18:34 11
Цитата Сообщение от pascyber1 Посмотреть сообщение
Мне бы попроще. Но, я так понимаю, готового парсера нет ни у кого. Прийдётся ломать голову самому.
Самое интересное что регулярные выражения в php как раз из с++ взяты, а вот функции аналога preg_match-а я не смог найти...

Максимум что я нарыл так это посимвольная "маска". В принципе, более менее хоть какая-то регулярка если нужно именно на c++
Парсер HTML
1
Эксперт С++
3936 / 1801 / 184
Регистрация: 21.11.2009
Сообщений: 2,540
05.01.2011, 21:56 12
Цитата Сообщение от pascyber1 Посмотреть сообщение
MikeSoft, спасибо, но палец можно сломать. Не-а, это не мой уровень. Мне бы попроще.
Попроще... хм, как бы это вам сказать...
Программирование, на самом деле, не такая уж и лёгкая штука, как кажется.
Вы добавляете на форму кнопку и всего лишь описываете поведение на событие щелчка.
А вы задумывались, что нужно сделать, чтобы создать саму форму, которая ещё и способна принимать сообщение от системы?
Знакомы с WinAPI?

Попробуйте создать новый проект: File -> New -> Console Application.
Затем уберите галочку с пунктов Use VCL и с Console Application.

А затем вставьте следующий код и откомпилируйте:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <windows.h>
//-------------------------------------------------------------------------------------
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
//-------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hprevInst, LPSTR lpCmdLine, int nCmdShow)
{
  HWND hMainWnd;
  TCHAR szClassName[] = TEXT("WndClass");
  MSG msg;
  WNDCLASSEX wc;
 
  wc.cbSize = sizeof(wc);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = WinProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInst;
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wc.lpszMenuName = NULL;
  wc.lpszClassName = szClassName;
  wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
 
  if(!RegisterClassEx(&wc)) {
    MessageBox(NULL, TEXT("Can't register window class!"), TEXT("Error message"), MB_OK);
    return 0;
  }
 
  hMainWnd = CreateWindow(
    szClassName,
    TEXT("Simple window"),
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT,
    0,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    (HWND)NULL,
    (HMENU)NULL,
    hInst,
    NULL);
 
  if(!hMainWnd) {
    MessageBox(NULL, TEXT("Can't create the window!"), TEXT("Error message"), MB_OK);
    return 0;
  }
 
  ShowWindow(hMainWnd, nCmdShow);
 
  while(GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}
//-------------------------------------------------------------------------------------
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  HDC hDC;
  PAINTSTRUCT ps;
  RECT rect;
  switch(uMsg) {
    case WM_PAINT:
      hDC = BeginPaint(hwnd, &ps);
      GetClientRect(hwnd, &rect);
      DrawText(hDC, TEXT("This is just a Window"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      EndPaint(hwnd, &ps);
      break;
    case WM_CLOSE:
      DestroyWindow(hwnd);
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
  default:
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
  }
  return 0;
}
//-------------------------------------------------------------------------------------
А вот теперь подумайте и ответьте мне: Легко ли было создать обычное диалоговое окно?
2
10 / 10 / 2
Регистрация: 17.06.2010
Сообщений: 107
Записей в блоге: 1
06.01.2011, 16:56  [ТС] 13
Это все не то. Есть у кого то рабочий парсер html с описанием?
0
10 / 10 / 2
Регистрация: 17.06.2010
Сообщений: 107
Записей в блоге: 1
07.01.2011, 18:04  [ТС] 14
Вот посоветовали использовать токенайзер
http://cpp.pastebin.com/1iLixmbC

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    class tokenizer
    {
    public:
        enum sep_flag
        {
            single,
            multiple,
            whole_str
        };
        struct token
        {
            const char* ptr;
            unsigned    len;
        };
    public:
        tokenizer(const char* sep, 
                  const char* trim=0,
                  const char* quote="\"",
                  char mask_chr='\\',
                  sep_flag sf=multiple);
        void  set_str(const char* str);
        token next_token();
    private:
        int  check_chr(const char *str, char chr);
    private:
        const char* m_src_string;
        int         m_start;
        const char* m_sep;
        const char* m_trim;
        const char* m_quote;
        char        m_mask_chr;
        unsigned    m_sep_len;
        sep_flag    m_sep_flag;
    };
//-----------------------------------------------------------------------
    inline void tokenizer::set_str(const char* str) 
    { 
        m_src_string = str; 
        m_start = 0;
    }
//-----------------------------------------------------------------------
    inline int tokenizer::check_chr(const char *str, char chr)
    {
        return int(strchr(str, chr));
    }
//-----------------------------------------------------------------------
    tokenizer::tokenizer(const char* sep, 
                         const char* trim,
                         const char* quote,
                         char mask_chr,
                         sep_flag sf) :
        m_src_string(0),
        m_start(0),
        m_sep(sep),
        m_trim(trim),
        m_quote(quote),
        m_mask_chr(mask_chr),
        m_sep_len(sep ? strlen(sep) : 0),
        m_sep_flag(sep ? sf : single)
    {
    }
//-----------------------------------------------------------------------
    tokenizer::token tokenizer::next_token()
    {
        unsigned count = 0;
        char quote_chr = 0;
        token tok;
        tok.ptr = 0;
        tok.len = 0;
        if(m_src_string == 0 || m_start == -1) return tok;
        register const char *pstr = m_src_string + m_start;
        if(*pstr == 0) 
        {
            m_start = -1;
            return tok;
        }
        int sep_len = 1;
        if(m_sep_flag == whole_str) sep_len = m_sep_len;
        if(m_sep_flag == multiple)
        {
//Pass all the separator symbols at the begin of the string
            while(*pstr && check_chr(m_sep, *pstr)) 
            {
                ++pstr;
                ++m_start;
            }
        }
        if(*pstr == 0) 
        {
            m_start = -1;
            return tok;
        }
        for(count = 0;; ++count) 
        {
            char c = *pstr;
            int found = 0;
//We are outside of qotation: find one of separator symbols
            if(quote_chr == 0)
            {
                if(sep_len == 1)
                {
                    found = check_chr(m_sep, c);
                }
                else
                {
                    found = strncmp(m_sep, pstr, m_sep_len) == 0; 
                }
            }
            ++pstr;
            if(c == 0 || found) 
            {
                if(m_trim)
                {
                    while(count && 
                          check_chr(m_trim, m_src_string[m_start]))
                    {
                        ++m_start;
                        --count;
                    }
                    while(count && 
                     check_chr(m_trim, m_src_string[m_start + count - 1]))
                    {
                        --count;
                    }
                }
                tok.ptr = m_src_string + m_start;
                tok.len = count;
//Next time it will be the next separator character
//But we must check, whether it is NOT the end of the string.
                m_start += count;
                if(c) 
                {
                    m_start += sep_len;
                    if(m_sep_flag == multiple)
                    {
//Pass all the separator symbols 
//after the end of the string
                        while(check_chr(m_sep, m_src_string[m_start])) 
                        {
                            ++m_start;
                        }
                    }
                }
                break;
            }
//Switch quote. If it is not a quote yet, try to check any of
//quote symbols. Otherwise quote must be finished with quote_symb
            if(quote_chr == 0)
            {
                if(check_chr(m_quote, c)) 
                {
                    quote_chr = c;
                    continue;
                }
            }
            else
            {
//We are inside quote: pass all the mask symbols
                if(m_mask_chr && c == m_mask_chr)
                {
                    if(*pstr) 
                    {
                        ++count;
                        ++pstr;
                    }
                    continue; 
                }
                if(c == quote_chr) 
                {
                    quote_chr = 0;
                    continue;
                }
            }
        }
        return tok;
    }
Говорят использовать надо следующим образом

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    tokenizer cmd_line(" ", "\"' ", "\"'", '\\', tokenizer::multiple);
    cmd_line.set_str(lpszCmdLine);
 
    int argc = 0;
    argv[argc++] = argv_ptr;
    *argv_ptr++ = 0;
 
    while(argc < 64)
    {
        agg::tokenizer::token tok = cmd_line.next_token();
        if(tok.ptr == 0) break;
        if(tok.len)
        {
            memcpy(argv_ptr, tok.ptr, tok.len);
            argv[argc++] = argv_ptr;
            argv_ptr += tok.len;
            *argv_ptr++ = 0;
        }
    }

никто не подскажет как его добавить к моей программе??
0
83 / 18 / 2
Регистрация: 17.11.2010
Сообщений: 107
07.01.2011, 19:44 15
Цитата Сообщение от Egeni Посмотреть сообщение
никто не подскажет как его добавить к моей программе??
Сильно однако!
1
10 / 10 / 2
Регистрация: 17.06.2010
Сообщений: 107
Записей в блоге: 1
11.01.2011, 14:01  [ТС] 16
нет я серьезно, как склеить эти части??

очень нужна помощь
0
10 / 10 / 2
Регистрация: 17.06.2010
Сообщений: 107
Записей в блоге: 1
20.02.2011, 23:09  [ТС] 17
Есть 2 исходных программы одна скачивает страницу, другая ищет по тексту совпадения... помогите пожалуйста их объединить в одну через функции!! очень прошу!
0
LK
Заблокирован
20.02.2011, 23:36 18
а где, собственно, то, что есть ? объединять-то нечего пока...
0
10 / 10 / 2
Регистрация: 17.06.2010
Сообщений: 107
Записей в блоге: 1
27.02.2011, 13:06  [ТС] 19
Решаем программы, пишем собственные модули и функции продолжение темы
0
145 / 100 / 6
Регистрация: 11.03.2010
Сообщений: 478
04.03.2011, 11:40 20
я тут попробовал переделать приведенный пример кода для своих целей
Парсер HTML

вышло вот такое дело:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
RichEdit2->Clear();
 
AnsiString One;
 
 
One = RichEdit1->Lines->Text;
 
int p,p2,i;
 
 while (One.Pos("[")&&One.Pos("]")) {
    if (p == 0 && p2 == 0) break;
 
p=One.Pos("[");
p2=One.Pos("]");
AnsiString Value="";
Value=One.SubString(p,p2-p);
if (p!=0&&p2!=0) RichEdit2->Lines->Add(Value);
 
 int sPos = One.Pos("[");
  int ePos = One.Pos("]");
  if (sPos == 0 && ePos == 0) break;
  if (sPos != 0) One.Delete(sPos,1);
  if (ePos != 0) One.Delete(ePos,1);
код поидеее должен из вот такого набора символов:
[Name] == Heavygloves && [Quality] == Unique
[Name] == ChainGloves && [Quality] == Unique
[Name] == LightGauntlets && [Quality] == Unique
[Name] == OgreGauntlets && [Quality] == Unique
[Name] == VampireboneGloves && [Quality] == Unique

отсеивать все то что находится в [] скобках.

вобщем то работает нормально но только до первой скобки.
и результат выводит в виде

[Name

как можно его заставить сканить весь текст ? и выводить все встречающиеся комбинации?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.03.2011, 11:40

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Парсер html
Ребят пишу парсер, парсю через регулярки, но есть проблема - не могу составить регулярку на код...

Парсер HTML на C++
Помогите найти библиотеку для синтаксического анализа HTML на C++ или Си. Желательно, работающую с...

Html парсер
Здравствуйте!Есть простой код парсинга тега &lt;title&gt; c сайтов. Вот нашел пример: import...

Парсер html на c++
В консольном приложении хочу чтобы для конвертации валют использовались актуальные данные с сайта....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.