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

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

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

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

http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.Generics.Collections.TDictionary
...
Рейтинг: 0 / 0
14.03.2018, 11:17
    #39614617
Forx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
Василий №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
14.03.2018, 14:49
    #39614783
Василий №2
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
Forxразделить списки на allow и disallow - сначала так и хотел делать, но в хелпе яндекса указано, что так больше не работает.
Тогда да
Обработка символов подстановки - так для этого и делал
Код: pascal
1.
st.Delimiter := '*';


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

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

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

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

Уууу... тяжелый случай. Проверка на маску далеко не так делается - можно заюзать MatchesMask, или наваять свою простую функцию без лишних заморочек. КМК, твой код еще и некорректен - правило /cat/*/subcat может сработать на /subcat/foo/cat. В общем, весь код проверки на маску выкинуть. Вместо него при загрузке правил отмечать флагом правила с маской и без, при проверке - правила без маски проверять на StartsFrom, а с маской уже через отдельную функцию. Также, если такое допускается форматом, надо предусмотреть различие случаев путей от корня и со вхождением в любом месте; пути от корня проверяются быстрее.
...
Рейтинг: 0 / 0
14.03.2018, 14:50
    #39614784
Василий №2
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
ForxНагуглить ничего не удалось, поэтому изобретал свой велосипед
Исходники любого веб-сервера не предлагать?))
...
Рейтинг: 0 / 0
15.03.2018, 13:42
    #39615358
Forx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
Василий №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
15.03.2018, 16:14
    #39615516
SOFT FOR YOU
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
Forx,

За 100500 тыщ могу оптимизировать твой код
Безналичный расчёт :)
...
Рейтинг: 0 / 0
17.03.2018, 03:05
    #39616181
Forx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
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
17.03.2018, 03:14
    #39616182
Forx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
Только щас увидел
Код: 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
17.03.2018, 03:54
    #39616184
SOFT FOR YOU
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизировать код (проверка URL на запрет в robots.txt)
Forx,

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

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

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


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