// SEO

NawiSEO 2 - title, description, H1

▸ // rozdziały lekcji

NawiSEO 2 - Wolniś mierzy linijką za długi tytuł strony

Ręczne sprawdzanie meta tagów wygląda tak: otwierasz podstronę, klikasz „Pokaż źródło", szukasz title, kopiujesz do arkusza. Minuta na adres. Przy 300 podstronach to pięć godzin klikologii, po których i tak nie masz pewności, że niczego nie pominąłeś.

Ten workflow bierze adresy z tabeli, wchodzi na każdy i wpisuje obok title, meta description, wszystkie H1, ich długości i liczbę H1. Po kilku uruchomieniach widzisz całą stronę w jednej tabeli: puste opisy, za długie tytuły, podstrony bez H1 albo z trzema.

To druga lekcja serii NawiSEO. Pracuje na tabeli nawiseo_adresy, którą wypełniłeś w NawiSEO 1.

Co robi ten workflow

  1. Uruchom recznie - start kliknięciem.
  2. Ustawienia - pole ile_na_raz, domyślnie 20. Tyle adresów sprawdza jedno uruchomienie.
  3. Przygotuj tabele - zakłada nawiseo_adresy albo używa istniejącej (opcja Reuse Existing Tables).
  4. Adresy do sprawdzenia - pobiera z tabeli wiersze z pustą kolumną sprawdzono, najwyżej ile_na_raz sztuk.
  5. Pobierz strone - HTTP Request pobiera kod HTML każdej podstrony.
  6. Wyciagnij elementy - węzeł HTML wyciąga title, meta description i wszystkie H1.
  7. Policz dlugosci - porządkuje spacje, liczy znaki i nagłówki, dopisuje status HTTP i datę sprawdzenia.
  8. Zapisz wynik - aktualizuje wiersz w tabeli, dopasowując go po url.

Kanwa po uruchomieniu, liczba 20 items na połączeniach od Adresy do sprawdzenia do Zapisz wynik

Czego potrzebujesz

  • tabeli nawiseo_adresy z adresami z NawiSEO 1,
  • niczego więcej. Strony pobierasz jak zwykła przeglądarka, bez kluczy i kont.

Jak uruchomić

  1. Zaimportuj plik z tej lekcji.
  2. Jeśli chcesz, zmień ile_na_raz w węźle Ustawienia.
  3. Kliknij Execute workflow.
  4. Otwórz tabelę nawiseo_adresy (Overview > zakładka Data tables). 20 wierszy ma teraz wypełnione kolumny od status_http do sprawdzono.
  5. Uruchamiaj ponownie, aż wszystkie adresy mają datę w sprawdzono.

W teście sprawdziłem 20 adresów z damianslimak.pl. Strona główna ma title o długości 44 znaków. Przy 235 adresach z pierwszej lekcji i porcji po 20 wychodzi 12 uruchomień.

Kolejka z kolumny sprawdzono

Węzeł Adresy do sprawdzenia to Data Table z operacją Get i warunkiem sprawdzono jest puste. Limit bierze z Ustawień wyrażeniem {{ $('Ustawienia').item.json.ile_na_raz }}.

Po zapisie każdy adres dostaje datę, więc przy następnym uruchomieniu już się nie łapie. Z pustej kolumny robi się kolejka. Przerwiesz workflow w połowie, odpalisz jutro, a on zacznie od pierwszego niesprawdzonego adresu.

Pro-tip. Chcesz sprawdzić wybraną podstronę jeszcze raz, na przykład po poprawce tytułu? Wyczyść jej komórkę sprawdzono w tabeli. Wróci do kolejki przy najbliższym uruchomieniu.

Adres, który zwrócił błąd, też dostaje datę. Tak wynika z konstrukcji workflow: status HTTP ląduje w status_http, a data w sprawdzono niezależnie od wyniku. Martwy adres nie blokuje więc kolejki. Po przebiegu przejrzyj wiersze, w których status_http jest inny niż 200 albo pusty.

Pobieranie bez zatykania serwera

Pobierz strone ma kilka ustawień, które decydują, czy audyt przejdzie spokojnie:

  • batching - 5 zapytań naraz, potem 1 sekunda przerwy. Twój serwer nie dostaje 20 zapytań w tej samej chwili,
  • timeout - 20 sekund. Wolna podstrona nie wisi w nieskończoność,
  • pełna odpowiedź (Full Response) z formatem Text - treść strony trafia do pola data, a kod odpowiedzi do statusCode,
  • Never Error - odpowiedź 404 albo 500 nie przerywa workflow, tylko idzie dalej jak zwykły wynik.

Węzeł ma też ustawione kontynuowanie po błędzie w zakładce ustawień. Przy zerwanym połączeniu albo przekroczonym czasie workflow też idzie dalej.

Trzy selektory i jedna pułapka

Wyciagnij elementy czyta pole data i używa trzech selektorów CSS:

  • title - tekst znacznika title,
  • meta[name="description"] - atrybut content, czyli meta opis,
  • h1 - tekst nagłówka, z włączonym zwracaniem listy. Strona z trzema H1 da trzy wartości, a nie tylko pierwszą.

Węzeł Wyciagnij elementy, trzy wiersze Extraction Values i opcja Clean Up Text wyłączona

Haczyk. Węzeł HTML ma opcję Clean Up Text. Wygląda niewinnie, ale w teście skleiła słowa na łamaniu linii: z tekstu rozbitego na dwie linie zrobiło się „architecturecode". W pliku ta opcja jest wyłączona, a spacje porządkuje dopiero następny węzeł.

Liczenie w Edit Fields

Policz dlugosci to węzeł Edit Fields z dziewięcioma polami. Trzy wyrażenia robią najwięcej:

{{ ($json.title || '').replace(/\s+/g, ' ').trim() }}

|| '' chroni przed pustym wynikiem, gdy strona nie ma title. .replace(/\s+/g, ' ') zamienia każdy ciąg spacji, tabulatorów i znaków nowej linii na jedną spację, a .trim() obcina brzegi.

{{ [].concat($json.h1 || []).map(h => h.replace(/\s+/g, ' ').trim()).join(' | ') }}

Ten sam patent z [].concat(...) co w NawiSEO 1. Zawsze masz listę, nawet przy jednym H1. Nagłówki trafiają do jednej komórki rozdzielone pionową kreską, a h1_ilosc liczy je wyrażeniem {{ [].concat($json.h1 || []).length }}.

Status bierze z węzła pobierania przez {{ $('Pobierz strone').item.json.statusCode }}, a datę z {{ $now.toISO() }}.

Co z tym zrobić

Otwórz tabelę i szukaj trzech rzeczy. Orientacyjne normy poniżej to praktyka branżowa, a nie twarde reguły Google:

  • title_dl powyżej około 60 znaków - wyniki wyszukiwania mogą obciąć tytuł,
  • description_dl równe 0 albo daleko od 150-160 znaków,
  • h1_ilosc równe 0 albo większe niż 1. Jeden H1 na stronę to przyjęty standard.

Haczyk. HTTP Request pobiera surowy kod strony. Jeśli strona buduje treść w przeglądarce przez JavaScript, dostaniesz pusty szkielet i puste H1 w tabeli. Tu pomoże tylko narzędzie, które renderuje stronę.

Podsumowanie

Z listy adresów robisz audyt meta tagów całej strony, porcjami po 20 i bez obciążania serwera. Pusta kolumna sprawdzono działa jak kolejka, więc workflow możesz przerywać i wznawiać. Clean Up Text zostaw wyłączone, spacje porządkuj wyrażeniem.

W NawiSEO 3 - inspekcja adresów w Search Console zapytamy Google, które z tych adresów są w indeksie.

Pokaż JSON do skopiowania - nawiseo-2-title-desc-h1.json
{
  "name": "NawiSEO 2 - Audyt title, description i H1",
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "id": "05a0521d-4c71-e58b-adce-d55f3b1517ef",
      "name": "Uruchom recznie"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a234d4c2-6583-d710-0b90-d2e00a0728e6",
              "name": "ile_na_raz",
              "value": "20",
              "type": "number"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        220,
        0
      ],
      "id": "9e229da8-39d5-3752-ee1e-477426ea5c0f",
      "name": "Ustawienia"
    },
    {
      "parameters": {
        "resource": "table",
        "operation": "create",
        "tableName": "nawiseo_adresy",
        "columns": {
          "column": [
            {
              "name": "url",
              "type": "string"
            },
            {
              "name": "domena",
              "type": "string"
            },
            {
              "name": "sitemap",
              "type": "string"
            },
            {
              "name": "status_http",
              "type": "number"
            },
            {
              "name": "title",
              "type": "string"
            },
            {
              "name": "title_dl",
              "type": "number"
            },
            {
              "name": "description",
              "type": "string"
            },
            {
              "name": "description_dl",
              "type": "number"
            },
            {
              "name": "h1",
              "type": "string"
            },
            {
              "name": "h1_ilosc",
              "type": "number"
            },
            {
              "name": "sprawdzono",
              "type": "date"
            },
            {
              "name": "nowy_title",
              "type": "string"
            },
            {
              "name": "nowy_description",
              "type": "string"
            },
            {
              "name": "nowy_h1",
              "type": "string"
            },
            {
              "name": "gsc_status",
              "type": "string"
            },
            {
              "name": "gsc_ostatni_crawl",
              "type": "string"
            },
            {
              "name": "psi_mobile",
              "type": "number"
            },
            {
              "name": "psi_desktop",
              "type": "number"
            }
          ]
        },
        "options": {
          "createIfNotExists": true
        }
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        440,
        0
      ],
      "id": "b6ce50cd-b630-ed62-a9f1-ff9845c2c940",
      "name": "Przygotuj tabele"
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "value": "nawiseo_adresy",
          "mode": "name"
        },
        "returnAll": false,
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "sprawdzono",
              "condition": "isEmpty"
            }
          ]
        },
        "limit": "={{ $('Ustawienia').item.json.ile_na_raz }}"
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        660,
        0
      ],
      "id": "3d448eed-6999-fdab-1ba1-d74f6a215db3",
      "name": "Adresy do sprawdzenia"
    },
    {
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 5,
              "batchInterval": 1000
            }
          },
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true,
              "responseFormat": "text"
            }
          },
          "timeout": 20000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        880,
        0
      ],
      "id": "2bf4661c-ab4d-c4e6-3515-b6464ce704fc",
      "name": "Pobierz strone",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "dataPropertyName": "data",
        "extractionValues": {
          "values": [
            {
              "key": "title",
              "cssSelector": "title",
              "returnValue": "text"
            },
            {
              "key": "description",
              "cssSelector": "meta[name=\"description\"]",
              "returnValue": "attribute",
              "attribute": "content"
            },
            {
              "key": "h1",
              "cssSelector": "h1",
              "returnValue": "text",
              "returnArray": true
            }
          ]
        },
        "options": {
          "trimValues": true,
          "cleanUpText": false
        }
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        1100,
        0
      ],
      "id": "d163dca1-3f77-e6b4-08e7-4c8b0d79d691",
      "name": "Wyciagnij elementy",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "0da9cb44-a020-6ceb-0687-f2ea3c8ec4f9",
              "name": "url",
              "value": "={{ $('Adresy do sprawdzenia').item.json.url }}",
              "type": "string"
            },
            {
              "id": "18008feb-67cc-e489-6f96-9ddf9bbb7325",
              "name": "status_http",
              "value": "={{ $('Pobierz strone').item.json.statusCode }}",
              "type": "number"
            },
            {
              "id": "f535d45b-47c7-063a-db4e-cb8fea7d4736",
              "name": "title",
              "value": "={{ ($json.title || '').replace(/\\s+/g, ' ').trim() }}",
              "type": "string"
            },
            {
              "id": "7974155f-13b3-8431-8418-5a887a9688bb",
              "name": "title_dl",
              "value": "={{ ($json.title || '').length }}",
              "type": "number"
            },
            {
              "id": "7508c438-1ff6-2e47-0516-c88b09290d7a",
              "name": "description",
              "value": "={{ $json.description || '' }}",
              "type": "string"
            },
            {
              "id": "5134be01-4c25-3092-2b26-9e24e3bca127",
              "name": "description_dl",
              "value": "={{ ($json.description || '').length }}",
              "type": "number"
            },
            {
              "id": "c0a32db9-eb5d-6dfb-b058-d677e7080883",
              "name": "h1",
              "value": "={{ [].concat($json.h1 || []).map(h => h.replace(/\\s+/g, ' ').trim()).join(' | ') }}",
              "type": "string"
            },
            {
              "id": "78b63292-bacb-d9c5-dd2a-f225e4607cad",
              "name": "h1_ilosc",
              "value": "={{ [].concat($json.h1 || []).length }}",
              "type": "number"
            },
            {
              "id": "fe960db1-3e69-0add-b9d5-7f25c6abb4de",
              "name": "sprawdzono",
              "value": "={{ $now.toISO() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1320,
        0
      ],
      "id": "75e86daa-f980-f378-cd44-70e1287896ed",
      "name": "Policz dlugosci"
    },
    {
      "parameters": {
        "operation": "update",
        "dataTableId": {
          "__rl": true,
          "value": "nawiseo_adresy",
          "mode": "name"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "url",
              "condition": "eq",
              "keyValue": "={{ $json.url }}"
            }
          ]
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "status_http": "={{ $json.status_http }}",
            "title": "={{ $json.title }}",
            "title_dl": "={{ $json.title_dl }}",
            "description": "={{ $json.description }}",
            "description_dl": "={{ $json.description_dl }}",
            "h1": "={{ $json.h1 }}",
            "h1_ilosc": "={{ $json.h1_ilosc }}",
            "sprawdzono": "={{ $json.sprawdzono }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "url",
              "displayName": "url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "domena",
              "displayName": "domena",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "sitemap",
              "displayName": "sitemap",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "status_http",
              "displayName": "status_http",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "title",
              "displayName": "title",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "title_dl",
              "displayName": "title_dl",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "description",
              "displayName": "description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "description_dl",
              "displayName": "description_dl",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "h1",
              "displayName": "h1",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "h1_ilosc",
              "displayName": "h1_ilosc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "sprawdzono",
              "displayName": "sprawdzono",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "date",
              "readOnly": false,
              "removed": false
            },
            {
              "id": "nowy_title",
              "displayName": "nowy_title",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "nowy_description",
              "displayName": "nowy_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "nowy_h1",
              "displayName": "nowy_h1",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "gsc_status",
              "displayName": "gsc_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "gsc_ostatni_crawl",
              "displayName": "gsc_ostatni_crawl",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "psi_mobile",
              "displayName": "psi_mobile",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "readOnly": false,
              "removed": true
            },
            {
              "id": "psi_desktop",
              "displayName": "psi_desktop",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "readOnly": false,
              "removed": true
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1540,
        0
      ],
      "id": "1f43de13-77fd-abb4-fad9-2a05745b9b48",
      "name": "Zapisz wynik"
    }
  ],
  "connections": {
    "Uruchom recznie": {
      "main": [
        [
          {
            "node": "Ustawienia",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ustawienia": {
      "main": [
        [
          {
            "node": "Przygotuj tabele",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Przygotuj tabele": {
      "main": [
        [
          {
            "node": "Adresy do sprawdzenia",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Adresy do sprawdzenia": {
      "main": [
        [
          {
            "node": "Pobierz strone",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pobierz strone": {
      "main": [
        [
          {
            "node": "Wyciagnij elementy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wyciagnij elementy": {
      "main": [
        [
          {
            "node": "Policz dlugosci",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Policz dlugosci": {
      "main": [
        [
          {
            "node": "Zapisz wynik",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "active": false
}