Четверг, 28.03.2024, 20:55
Приветствую Вас Гость

Не ошибается тот, кто ничего не делает.
Но и ничего не делать - ошибка.

Эмиль Кроткий

Меню сайта
Категории раздела
Парсинг [2]
Статьи по написанию парсеров
Форма входа

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0


















Тиц
Главная » Статьи » Парсинг » Парсинг

Урок 1.2. Парсинг - продолжение.
       На прошлом уроке мы с вами начали проект, создания парсера каталога интернет магазина. Мы получили код HTML  страницы, научились правильно отображать русские буквы и нашли в HTML  коде где находятся товары в каталоге.
На этом уроке мы научимся выделять из HTML кода нужные нам части, используя функции работы со строками и регулярные выражения.

Приступим…

В разделе Uses добавляем модуль RegExpr;

Далее еще раз посмотрим на HTML код. Непосредственно каталог товаров начинается с тегов
<tr class="productListing-odd">  и  <tr class="productListing-even">,



поэтому, используя функции поиска найдем первый из этих тегов и весь код, который был до него удалим.  Для этого добавим к событию OnClick кнопки «Грабим» следующий код:

r.Expression:='<tr class="productListing-(odd|even)">';
if r.Exec (html) then begin
                           edit1.Text:= r.Match [0];
                           Delete(html,1,r.MatchPos[0]-1);
                           memo1.Text:=html;

а в раздел Var добавим еще две переменные:
r : TRegExpr;
id:string;

Для события OnClose формы пишем:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
r.Free;
end;

Для события OnCreate формы пишем:

procedure TForm1.FormCreate(Sender: TObject);
begin
r := TRegExpr.Create;
end;

Немного пояснений:
Через переменную r мы будем работать с регулярными выражениями.

В r.Expression задаем выражение для поиска. В нашем случае мы ищем строку <tr class="productListing-(odd|even)">, (odd|even) – данное выражение означает, что мы ищем productListing-odd или productListing-even, т.е. | - это логическое или;

r.Exec (html) – начинает поиск выражения заданного в r.Expression в строковой переменной html;

r.Match [0] –возвращает найденное выражение, которое мы записываем в edit1, чтобы убедиться в правильности найденного выражения;

Delete(html,1,r.MatchPos[0]-1);
- данная строка удаляет из переменной html строки начиная с позиции 1 до позиции найденного выражения (r.MatchPos[0]);

memo1.Text:=html; - обрезанный текст мы снова выводим в MEMO1 поле.

Далее запускаем и убеждаемся, что все сработало правильно.

Если все сработало правильно, переходим к поиску кода товара (id). В нашем HTML коде это строка 
<td class="productListing-data">&nbsp;465267&nbsp;</td>.

аналогично предыдущему добавляем следующий код:

r.Expression:='<td class="productListing-data">.*?(\d{6}).*?</td>';
if r.Exec (html) then begin
                                        edit2.Text:= r.Match [1];
                                        id:=r.Match [1];
                                     end;

В этом фрагменте мы составили следующее регулярное выражение:
'<td class="productListing-data">.*?(\d{6}).*?</td>'

. – обозначает произвольный символ;

* - ноль или более раз повторение символа;

? в сочетании .* обозначает, что искать будем ближайшее совпадение (так называемый «не жадный» режим);
\d{6} – обозначает, что будем искать 6 повторений любой цифрового символа  (\d – обозначает любую цифру);

r.Match [1]; - первое подвыражение в скобках в регулярном выражении.

Снова запускаем и проверяем правильность работы.

Далее ищем url адрес изображения товара. Снова просматриваем  HTML код и находим наше изображение:

<td align="center" class="productListing-data">&nbsp;<a href="http://price.portalkirov.ru/cat/product_info.php?cPath=418209_463431&products_id=465267&osCsid=9ba6caa3ffe37a95c0f6d51cab0dd145"><img src="images/kat22.gif" border="0" alt="3D Очки - 1шт. Samsung SSG-3050GB для телевизоров Samsung-2011 D6100/ D7000/ D8000/ D9000 (работают" title=" 3D Очки - 1шт. Samsung SSG-3050GB для телевизоров Samsung-2011 D6100/ D7000/ D8000/ D9000 (работают " width="100" height="75"></a>&nbsp;</td>

Из кода видно, что изображения хранятся по адресу http://price.portalkirov.ru/cat/; и от этой папки images/kat22.gif.

Составляем регулярное выражение для поиска второй части пути с именем файла:

r.Expression:='id='+Trim(id)+'.+?"><img src="(.*?)\.(.*?)"';

(.*?)\.(.*?) – в первой скобке (r.Match [1]) получаем часть пути с именем файла до расширения. Во второй скобке (r.Match [1]) получаем расширение файла.

Весь код для получения url адреса изображения товара:

r.Expression:='id='+Trim(id)+'.+?"><img src="(.*?)\.(.*?)"';
if r.Exec (html) then begin
                                        edit3.Text:='http://price.portalkirov.ru/cat/'+ r.Match [1]+'.'+r.Match [2];
                                    end;

Аналогично ищем наименование товара и цену.

После того как все необходимое для заполнения базы данных будет найдено. Добавляем код для сохранения всех пунктов в базу данных и организуем цикл поиска остальных товаров каталога. Смотрите код модуля парсера.





Ниже привожу полный код модуля парсера.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, DBGrids, DB, ADODB, DBCtrls, StdCtrls, IdBaseComponent,
  IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, RegExpr, ExtCtrls, jpeg, GIFImg;

type

  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    DataSource1: TDataSource;
    ADOTable1: TADOTable;
    DBGrid1: TDBGrid;
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Memo1: TMemo;
    IdHTTP1: TIdHTTP;
    Image1: TImage;
    Button2: TButton;
    ADOQuery1: TADOQuery;
    Edit5: TEdit;
    Edit4: TEdit;
    Memo2: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure DBGrid1CellClick(Column: TColumn);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  html:string;
  DestEncoding:TStream;
  mm:TStringList;
  id, xxx:string;
  r : TRegExpr;
  ImgGif:TGifImage;
  ImgJpg:TJpegImage;
  posn,posk:integer;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
//Получаем HTML код сайта в переменную html и мемо поле
DestEncoding:= TMemoryStream.Create;
IdHTTP1.Get(edit5.Text,DestEncoding);
DestEncoding.Position :=0;
mm:=TStringList.Create;
mm.LoadFromStream(DestEncoding);
html:=mm.Text;
DestEncoding.Free;
mm.Free;
//ищем начало каталога
r.Expression:='<tr class="productListing-(odd|even)">';
//запускаем цикл пока есть товары в каталоге?
while r.Exec (html) do
begin
if r.Exec (html) then begin
                           edit1.Text:= r.Match [0];
                           //удаляем лишнее
                           Delete(html,1,r.MatchPos[0]-1);
                           memo1.Text:=html;
//ищем код товара
r.Expression:='<td class="productListing-data">.*?(\d{6}).*?</td>';
if r.Exec (html) then begin
                            edit2.Text:= r.Match [1];
                            id:=r.Match [1];
                            //добавляем новую запись в базу данных
                            ADOTable1.Append;
                            //записываем в базу код товара
                            ADOTable1.FieldByName('CODE').Value:=Trim(r.Match [1]);
                       end;

//ищем url адрес изображения товара
r.Expression:='id='+Trim(id)+'.+?"><img src="(.*?)\.(.*?)"';
if r.Exec (html) then begin
                            edit3.Text:='http://price.portalkirov.ru/cat/'+ r.Match [1];
                            DestEncoding:=TMemoryStream.Create;
                            //грузим в память изображение товара по его url адресу
                            IdHTTP1.Get('http://price.portalkirov.ru/cat/'+r.Match [1]+'.'+r.Match [2], DestEncoding);
                            DestEncoding.Position :=0;
                            //записываем изображение товара в BlobField поле базы данных
                            TBlobField(Form1.ADOTable1.FieldByName('foto')).LoadFromStream(DestEncoding);
                            DestEncoding.Free;
                            //записываем расширение картинки в базу данных
                            ADOTable1.FieldByName('ext').Value:=r.Match [2];
                      end;

//ищем наименование товара

r.Expression:='<td class="productListing-data">.*id='+id+'.+?">.*?</a><br>(.*?)</td>';
if r.Exec (html) then begin
                                //ищем символы '&nbsp;' для удаления
                                r.Expression:='&nbsp;';
                                //заменяем найденные символы на ''
                               xxx:= r.Replace(r.Match [1],'', True);
                                memo2.Text:=xxx;
                                //записываем наименование товара в базу данных
                                ADOTable1.FieldByName('name_tovara').Value:=xxx;
                             end;

//ищем цену товара
r.Expression:='<td align="right" class="productListing-data">(.*?)руб..*?</td>';
if r.Exec (html) then begin
                            posk:=r.MatchPos[0]+r.MatchLen[0];
                            //ищем символы '&nbsp;' для удаления
                            r.Expression:='&nbsp;';
                            //заменяем найденные символы на ''
                            xxx:=Trim(r.Replace(r.Match [1],'', True));
                            //записываем цену товара в базу данных
                            ADOTable1.FieldByName('cost').Value:=strtofloat(xxx);
                            edit4.Text:= xxx;
                            //удаляем найденный товар из HTML кода
                            Delete(html,1,posk);
                            beep;
                      end;

//сохраняем запись
ADOTable1.Post;
                      end;
//задаем выражение для следующего поиска
r.Expression:='<tr class="productListing-(odd|even)">';
end;
end;

//очистка базы  данных
procedure TForm1.Button2Click(Sender: TObject);
begin
     ADOQuery1.SQL.Clear;
     ADOQuery1.SQL.Add('DELETE katalog.* FROM katalog;');
     ADOQuery1.ExecSQL;
     ADOQuery1.Active:=false;
     ADOTable1.Active:=False;
     ADOTable1.Active:=True;

end;


//просмотр изображений в базе в зависимости от рассширения изображения ( jpg или gif)
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
DestEncoding:=TMemoryStream.Create;
TBlobField(Form1.ADOTable1.FieldByName('foto')).SaveToStream(DestEncoding);
DestEncoding.Position :=0;
if (LowerCase(ADOTable1.FieldByName('ext').Value)='jpg') or (LowerCase(ADOTable1.FieldByName('ext').Value)='jpeg') then
begin
    Imgjpg:=TJpegImage.Create;
    Imgjpg.LoadFromStream(DestEncoding);
    Image1.Picture.Assign(Imgjpg);
    Imgjpg.Free;

end;
if (LowerCase(ADOTable1.FieldByName('ext').Value)='gif') then
begin
    ImgGif:=TGifImage.Create;
    ImgGif.LoadFromStream(DestEncoding);
    Image1.Picture.Assign(ImgGif);
    ImgGif.Free;

end;
DestEncoding.Free;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//освобаждаем память
r.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
//создаем объект для работа с регулярными выражениями
r := TRegExpr.Create;
end;

end.

Думаю убрать все лишнее из кода не составит труда.

В нашем случае мы сохраняем изображения товаров прямо в базе, к сожалению это приводит к значительному увеличению размера файла базы MS Access. Поэтому во многих случаях в базе хранят не сами изображения, а имена файлов изображений. А сами изображения помещают отдельную папку.

На этом урок закончен.

Скачать исходники можно здесь.

Автор xaramamburu, сайт basicsprog.ucoz.ru

При копировании материалов  ссылка на сайт обязательна.



Категория: Парсинг | Добавил: xaramamburu (01.12.2011)
Просмотров: 12920 | Теги: парсер, парсинг, каталог интернет магазина | Рейтинг: 5.0/5
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Наш опрос
Оцените мой сайт
Всего ответов: 585
Уголок общения



Copyright MyCorp © 2024Конструктор сайтов - uCoz