powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Оптимизировать код (проверка URL на запрет в robots.txt)
15 сообщений из 15, страница 1 из 1
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39614490
Forx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем привет!

Есть задача - проверять большое кол-во URL на запрет индексации в robots.txt
Нагуглить ничего не удалось, поэтому изобретал свой велосипед

Нужен взгляд со стороны, есть ли какие явные косяки и можно ли как-то оптимизировать код?
Подозреваю, что можно сделать регулярками, но с ними совсем не дружу

Заранее благодарен)


Код: pascal
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.
unit Robots;

interface

uses
   System.SysUtils, System.Classes, StrUtils;

type

   TxRobots = class
   private
      sRobots   : TStringList;
      sRules    : TStringList;
      FUserAgent: string;

      procedure ParseRules;

   public
      function URLisDisallow(AURL: string): boolean;

      constructor Create(ARobots: string; AUserAgent: string);
      destructor Destroy; override;
   end;

implementation

{ TxRobots }

constructor TxRobots.Create(ARobots: string; AUserAgent: string);
begin
   sRules := TStringList.Create;
   sRules.Sorted := true;

   sRobots := TStringList.Create;
   sRobots.Text := ARobots;
   FUserAgent := AUserAgent;
   ParseRules;
end;

destructor TxRobots.Destroy;
begin
   if Assigned(sRobots) then
      sRobots.Free;
   sRules.Free;
end;

procedure TxRobots.ParseRules;
var
   i, j: integer;
   tmp : string;
begin
   for i := 0 to sRobots.Count - 1 do
   begin
      // Чекаем наш user-agent
      if pos('user-agent:', LowerCase(sRobots[i])) > 0 then
      begin
         // Проверка на комментарии
         if pos('#', tmp) > 0 then
            tmp := Trim(Copy(tmp, 1, pos('#', tmp) - 1));

         // убрали директиву
         tmp := Trim(StringReplace(sRobots[i], 'user-agent:', '', [rfIgnoreCase]));

         // Если наш user-agent
         if tmp = FUserAgent then
            Break;
      end;
   end;

   for j := i + 1 to sRobots.Count - 1 do
   begin
      // Если строка не пустая и не начинается с комментария
      if (Trim(sRobots[j]) <> '') AND (Trim(sRobots[j])[1] <> '#') then
      begin
         tmp := sRobots[j];

         // Если в строке есть комментарии - удаляем, на случай если в комментарии будут ключевые директивы
         if pos('#', tmp) > 0 then
            tmp := Trim(Copy(tmp, 1, pos('#', tmp) - 1));

         // Если правило запрещающее
         if pos('disallow', LowerCase(tmp)) > 0 then
            sRules.AddObject(Trim(StringReplace(tmp, 'disallow:', '', [rfIgnoreCase])), TObject(0))

            // Если правило разрешающее
         else if pos('allow', LowerCase(tmp)) > 0 then
            sRules.AddObject(Trim(StringReplace(tmp, 'allow:', '', [rfIgnoreCase])), TObject(1))
         else
            Break; // Если директивы указанной секции кончились
      end;
   end;
end;

function TxRobots.URLisDisallow(AURL: string): boolean;
var
   i, j      : integer;
   st        : TStringList;
   xURL      : string;
   xRules    : string;
   isRightStr: boolean;
   isFind    : boolean;
begin
   Result := false;
   isFind := false;

   st := TStringList.Create;
   st.Delimiter := '*';

   for i := sRules.Count - 1 downto 0 do
   begin
      if isFind then // Если правило для URL найдено
         Break;

      xURL := AURL;
      isRightStr := false; // Наличие символа $

      st.DelimitedText := sRules[i]; // Текущее правило
      for j := 0 to st.Count - 1 do
      begin
         if st[j] = '' then
            Continue;

         xRules := st[j];
         isRightStr := RightStr(xRules, 1) = '$';
         if isRightStr then                    // Если найден $ в конце
            Delete(xRules, Length(xRules), 1); // убираем

         if pos(xRules, xURL) > 0 then // Если в URL найдено правило
         begin
            Delete(xURL, 1, pos(xRules, xURL) + Length(xRules) - 1); // Удаляем то, что проверили
            isFind := NOT(isRightStr AND (xURL <> '')); // Если найден ограничитель $, но URL не конечный
            Continue;
         end
         else
         begin
            isFind := false;
            Break;
         end;
      end;
   end;

   if isFind then
      Result := integer(sRules.Objects[i]) = 0; // Если правило найдено, возвращаем Allow или Disallow
end;

end.


...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39614568
Василий №2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Разбираться в коде лениво, навскидку:
- не знаю синтаксиса правил, но у тебя сейчас для каждого урла выполняется преобразование всех имеющихся правил, а потом тупой пробег по каждому элементу. Это самый большой убийца производительности. Расщепи правила до самого конца, загони хотя бы в сортированный список, чтобы поиск шёл бинарный, и будет уже прирост на порядок, а то и не один.
- имеет смысл разделить списки на allow и disallow. т.к. логика "все, что не запрещено - разрешено", то достаточно пробегаться по disallow, и если урл найден, то уже искать его в allow
- const у строковых параметров
- избегать постоянного создания/удаления объекта st (кстати, а он и не удаляется - утечка памяти)
- избегать перераспределения строк. RightStr(s, 1) заменяется на s[Length(s)]. Delete тоже не нужно, выполняй поиск по PosEx.

Остальное надо смотреть исходя из синтаксиса правил. У тебя не увидел обработки символов подстановки, хотя они допустимы, емнип.
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39614583
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Forx,

TDictionary тебе случайно не поможет?

http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.Generics.Collections.TDictionary
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39614617
Forx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий №2,

разделить списки на allow и disallow - сначала так и хотел делать, но в хелпе яндекса указано, что так больше не работает.

Директивы Allow и Disallow из соответствующего User-agent блока сортируются по длине префикса URL (от меньшего к большему) и применяются последовательно. Если для данной страницы сайта подходит несколько директив, то робот выбирает последнюю в порядке появления в сортированном списке. Таким образом, порядок следования директив в файле robots.txt не влияет на использование их роботом.

Сортировку в текущем коде по длине префикса пока не проверял, хочу общую концепцию отладить

удаление объекта st - да, упустил, спасибо
Еще нужно if isFind then break переносить в конец цикла, т.к. сейчас прерывание происходит на следующей итерации и Result не верное значение получает.

Обработка символов подстановки - так для этого и делал
Код: pascal
1.
st.Delimiter := '*';


Т.е.
Правило: /cat/*/subcat

Делим на:
/cat/
/subcat

И последовательно проверяем на вхождения в URL (URL всегда относительный)

По остальному - спасибо! Учту


авторTDictionary тебе случайно не поможет?

Возможно, пошел читать, спасибо!
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39614783
Василий №2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Forxразделить списки на allow и disallow - сначала так и хотел делать, но в хелпе яндекса указано, что так больше не работает.
Тогда да
Обработка символов подстановки - так для этого и делал
Код: pascal
1.
st.Delimiter := '*';


Т.е.
Правило: /cat/*/subcat

Делим на:
/cat/
/subcat

И последовательно проверяем на вхождения в URL (URL всегда относительный)

По остальному - спасибо! Учту

Уууу... тяжелый случай. Проверка на маску далеко не так делается - можно заюзать MatchesMask, или наваять свою простую функцию без лишних заморочек. КМК, твой код еще и некорректен - правило /cat/*/subcat может сработать на /subcat/foo/cat. В общем, весь код проверки на маску выкинуть. Вместо него при загрузке правил отмечать флагом правила с маской и без, при проверке - правила без маски проверять на StartsFrom, а с маской уже через отдельную функцию. Также, если такое допускается форматом, надо предусмотреть различие случаев путей от корня и со вхождением в любом месте; пути от корня проверяются быстрее.
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39614784
Василий №2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ForxНагуглить ничего не удалось, поэтому изобретал свой велосипед
Исходники любого веб-сервера не предлагать?))
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39615358
Forx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий №2,

понял, вы правы, буду переделывать, спасибо!


Но, кстати,
Код: pascal
1.
/cat/*/subcat

на /subcat/foo/cat не сработает, т.к. /cat/ <> /cat

да и на /subcat/foo/cat/

т.к.
Код: pascal
1.
Delete(xURL, 1, pos(xRules, xURL) + Length(xRules) - 1); // Удаляем то, что проверили

:)
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39615516
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Forx,

За 100500 тыщ могу оптимизировать твой код
Безналичный расчёт :)
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39616181
Forx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU,

спасибо за предложение, но не думаю, что мне прям уж так необходим суперпупермегаскоростной код за 100500 ;)
--

Использовать MatchesMask не получилось, т.к. она не правильно обрабатывает вложенность

На данный момент получилось следующее:


Код: pascal
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.
   TxRules = record
      isSingle: boolean;
      isStrict: boolean;
      isDisallow: boolean;
      Rules: array of string;
   end;

   xRules: array of TxRules;



function TxRobots.isDisallow(aURL: string): boolean;
var
   i, j, N, R: integer;
   isFind    : boolean;
   isLast    : boolean;
begin
   R := 1;
   isFind := false;
   
   for i := Low(xRules) to High(xRules) do
   begin
   
      if xRules[i].isSingle then // Если правило без подстановки
      begin
         if xRules[i].isStrict then // Если стоит ограничитель $
            isFind := (StartsStr(xRules[i].Rules[0], aURL)) AND ((Length(xRules[i].Rules[0]) = Length(aURL))) // Проверяем на точное совпадение
         else
            isFind := (StartsStr(xRules[i].Rules[0], aURL)); // Иначе на вхождение
      end      
      else
      begin   
             
         for j := Low(xRules[i].Rules) to High(xRules[i].Rules) do // Если есть подстановка *
         begin
            isFind := false;              
            if (j = 0) then // Проверяем первое вхождение
            begin
               if (xRules[i].Rules[0] <> '') then // Если первый символ не знак подстановки *
               begin
                  isFind := StartsStr(xRules[i].Rules[0], aURL); // Проверяем начальное вхождение
                  R := Length(xRules[i].Rules[0]) + 1; // Запоминаем позицию
               end
               else
                  Continue;
            end             
            else
            begin              
               N := PosEx(xRules[i].Rules[j], aURL, R); // Ищем вхождение 
               if N > 0 then
               begin
                  R := N;
                  isLast := (j = High(xRules[i].Rules)) AND (xRules[i].isStrict); // Если у правила есть ограничитель $
                  isFind := NOT(isLast AND (Length(aURL) - R + 1 <> Length(xRules[i].Rules[j]))); // Если есть ограничитель, но URL не кончился
               end;                  
            end;      
                        
            if NOT isFind then
               Break;                     
         end; 
      end; 
      
      if isFind then
      begin
         isFind := xRules[i].isDisallow;
         Break;
      end;        
   end;
   
   Result := isFind;
end;


...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39616182
Forx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Только щас увидел
Код: pascal
1.
2.
3.
4.
5.
isFind := (StartsStr(xRules[i].Rules[0], aURL)) AND ((Length(xRules[i].Rules[0]) = Length(aURL))) // Проверяем на точное совпадение

Можно заменить на 

isFind :=xRules[i].Rules[0] = aURL // :))
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39616184
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Forx,

На x86 даст прирост, на x64 нет. На x64 нужно сначала сверять длину, а потом CompareMem
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39617982
Василий №2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SOFT FOR YOUForx,

На x86 даст прирост, на x64 нет. На x64 нужно сначала сверять длину, а потом CompareMem
При чем тут CompareMem? UStrEqual и так проверяет длины. Неужели есть извращенцы, заменяющие сравнение строк самопальным кодом?
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39618437
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий №2,

Код смотри.
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39618515
kep-ko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Василий №2Неужели есть извращенцы, заменяющие сравнение строк самопальным кодом?Угу, недавно цельный топик был с SSE и AVX-ом!
...
Рейтинг: 0 / 0
Оптимизировать код (проверка URL на запрет в robots.txt)
    #39618650
Василий №2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
kep-koВасилий №2Неужели есть извращенцы, заменяющие сравнение строк самопальным кодом?Угу, недавно цельный топик был с SSE и AVX-ом!
Лучше бы шустрые Move и ZeroMem намутили под х64... ну и Pos[Ex] для юникодных строк тоже не помешал бы.
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Оптимизировать код (проверка URL на запрет в robots.txt)
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]