# Crawler: обход множества страниц

> Обзор: чем отличается от Fetch, как устроен обход и в каком порядке всё происходит

Источник: https://docs.parreq.com/crawl/

`/v1/crawl` — это Fetch, которому не нужно диктовать каждый адрес. Fetch знает
ровно одну страницу: вы её назвали, он её принёс. Crawler получает начальный
адрес и **правило, куда идти дальше**, и дальше ходит сам, пока не наберёт
заказанное число страниц.

Внутри обхода работает тот же браузер, что и в Fetch: настоящий Chrome, та же
эмуляция устройства и страны, то же ожидание догрузки. И результат каждой
страницы — **ровно ответ Fetch**, поле в поле:

```json
{
  "pages": [
    { "fetch_metadata": { "…": "…" }, "parsed": { "…": "…" } },
    { "fetch_metadata": { "…": "…" }, "parsed": { "…": "…" } }
  ]
}
```

Ничего нового разбирать не придётся: код, который уже читает ответ Fetch,
читает и страницу обхода.

## Два способа двигаться

Сайт со списком товаров устроен в два измерения, и обход повторяет ровно их.

**next — вдоль**
    Селектор кнопки «следующая страница». Даёт цепочку листингов: второй,
    третий, четвёртый. Остаётся **на своём уровне глубины** — сколько бы
    страниц пагинации ни прошли, глубже вы не стали.

**follow — вглубь**
    Селектор ссылок на карточки. Каждая найденная ссылка уводит **на уровень
    глубже**, и потолок этих уровней задаёт `depth`.

Обычная задача — «пройти каталог и забрать карточки» — это оба сразу: `next`
листает страницы каталога, `follow` с каждой из них уходит в товары. Хотя бы
одно из двух указать обязательно: без правила движения обход выродится в один
Fetch, а за такое нечестно брать надбавку.

## Когда брать Crawler, а когда Fetch

| Задача | Чем брать |
|---|---|
| Известен точный список адресов | [Fetch](https://docs.parreq.com/fetch) в цикле — дешевле на кредит со страницы |
| Адреса лежат на самом сайте, и их надо сначала найти | Crawler |
| Пагинация неизвестной длины | Crawler: `next` идёт, пока кнопка находится |
| Нужно нажать, заполнить, войти | [Browser API](https://docs.parreq.com/browser): обход не умеет действовать на странице |
| Одна страница | Fetch. Обход одной страницы — это Fetch с наценкой |

Правило простое: если адреса вы уже знаете — знать их браузеру незачем. Обход
нужен ровно тогда, когда список страниц живёт внутри сайта, а не в вашем коде.

## Порядок работы

**1. Описать правило**

    `POST /v1/crawl` — начальный адрес, сколько страниц брать и по каким
    ссылкам идти. Подробно — на странице [Правило обхода](https://docs.parreq.com/crawl-rules).

**2. Получить результат или идентификатор**

    Маленький обход возвращает всё сразу, ответом `200`. Большой отвечает `202`
    и идентификатором задания: держать соединение полчаса незачем.

**3. Дождаться и забрать**

    `GET /v1/crawl/{job_id}` показывает ход и отдаёт страницы срезами,
    `GET /v1/crawl/{job_id}/pages` — только страницы. См.
    [Задания](https://docs.parreq.com/crawl-jobs).

## Первый обход

Возьмём витрину, на которой всё проверяемо: `books.toscrape.com`. Кнопка
пагинации у неё — `li.next a`, ссылки на карточки — `.product_pod h3 a`.

```python Python
from parreq import Parreq

client = Parreq("pr_ВАШКЛЮЧ")
res = client.crawl(
    url="https://books.toscrape.com/catalogue/category/books/mystery_3/index.html",
    pages=8,
    next="li.next a",
    follow=".product_pod h3 a",
)

print(res.metadata["status"], res.metadata["pages_done"], res.metadata["credits"])

for page in res.pages:
    print(page["fetch_metadata"]["final_url"], page["fetch_metadata"]["title"])
```

```javascript Node

const client = new Parreq({ apiKey: "pr_ВАШКЛЮЧ" });
const res = await client.crawl({
  url: "https://books.toscrape.com/catalogue/category/books/mystery_3/index.html",
  pages: 8,
  next: "li.next a",
  follow: ".product_pod h3 a",
});

console.log(res.metadata.status, res.metadata.pages_done, res.metadata.credits);

for (const page of res.pages) {
  console.log(page.fetch_metadata.final_url, page.fetch_metadata.title);
}
```

```bash cURL
curl -X POST https://api.parreq.com/v1/crawl \
  -H "Authorization: Bearer pr_ВАШКЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://books.toscrape.com/catalogue/category/books/mystery_3/index.html",
    "pages": 8,
    "next": "li.next a",
    "follow": ".product_pod h3 a"
  }'
```

Восемь страниц — это меньше десяти, и ответ придёт целиком, синхронно. Где
проходит граница и что делать с большим обходом — на странице
[Задания](https://docs.parreq.com/crawl-jobs).

## Что обход делает сам

### Не ходит дважды по одному адресу

    Адреса дедуплицируются: карточка, на которую ведут ссылки с трёх страниц
    каталога, будет пройдена один раз и оплачена один раз. Считать это самому
    не нужно.

### Не выходит во внутреннюю сеть

    Каждая найденная ссылка проверяется на принадлежность внутренней сети.
    Ведущая внутрь — молча пропускается: это не ваша ошибка и не повод ронять
    задание, но и ходить туда браузеру нечего.

### Ходит теми же выходами, что Fetch

    Страницы обхода забираются через прокси-выходы сервиса, по кругу, из
    профилей Fetch. На каждом выходе держится живой браузер, поэтому первая
    страница задания не ждёт старта Chrome — ни после паузы, ни после
    перезапуска сервиса. Подробнее — в [Fetch](https://docs.parreq.com/fetch#откуда-идёт-запрос).

### Уступает живым запросам

    Обход — работа фоновая, и очередь у неё последняя. Если в пуле браузеров
    нет запаса вкладок, задание ждёт, а не отнимает вкладку у синхронного
    запроса, за которым стоит живое соединение.

### Переживает перезапуск

    Задание живёт в хранилище, а не в памяти процесса: перезапуск сервиса его
    не теряет. Брошенное задание — то, чей исполнитель не вернулся, —
    возвращается в очередь автоматически и продолжается с того места, где
    остановилось.

> **К сведению.**
>   Режим ответа — синхронный или с идентификатором — на поведение обхода не
>   влияет. Исполнитель один и тот же, правила те же, счёт тот же. Разница
>   только в том, ждёте вы результат в соединении или забираете позже.

## Страницы раздела

**[Правило обхода](https://docs.parreq.com/crawl-rules)**
    `follow`, `next`, `depth`, `pages`, `same_site`, `allow` и `deny` — что
    каждое значит и как их сочетать.

**[Задания](https://docs.parreq.com/crawl-jobs)**
    Два режима, статусы, опрос, постраничная выдача и отмена.

**[Обход с разбором](https://docs.parreq.com/crawl-extract)**
    `extract` на каждой странице: обход возвращает готовые объекты, а не
    разметку.

**[Цена обхода](https://docs.parreq.com/crawl-pricing)**
    Надбавка за страницу, арифметика с примерами и почему это один запрос в
    лимитах.

**[Ошибки](https://docs.parreq.com/crawl-errors)**
    Коды отказов и что делать с каждым.

**[Справочник](https://docs.parreq.com/api-reference/crawl-post)**
    Все параметры `/v1/crawl` и коды ответов.
