Говоря об идеях высокопроизводительного краулера из фильмов Douban

рептилия

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

найти адрес данных

Первый шаг сканера, в первую очередь нам нужно найти адрес для получения данных. Вы можете сначала пойти в Douban Moviesтитульная страницаИди проверь.

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

https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start=0

Примечание. Если друг знаком с внешним интерфейсом и у него установлен плагин vue для браузера, он обнаружит, что сайт Douban Movie разработан vue. Эти базовые навыки веб-разработки очень полезны для нашей повседневной разработки поисковых роботов.

Сканировать данные домашней страницы

Откройте указанный выше адрес интерфейса в браузере, и мы обнаружим, что его возвращаемые данные имеют формат json. Используя запросы Python и библиотеки json, вы можете получить данные.

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

import json
import requests

def crawl(url):
    response = requests.get(url)
    if response.status_code != 200:
        raise Exception('http status code is {}'.format(response.status_code))

    data = response.json()['data']

    items = []
    for v in  data:
        items.append({
            'title': v['title'],
            'drectors': v['directors'],
            'rate': v['rate'],
            'casts': v['casts']
        })
    
    return items

def main():
    url = 'https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start=0'
    for item in crawl(url):
        print(item)

if __name__ == "__main__":
    main()

Выполнение кода получает следующие данные:

{'title': '绿皮书', 'drectors': ['彼得·法雷里'], 'rate': '8.9', 'casts': ['维果·莫腾森', '马赫沙拉·阿里', '琳达·卡德里尼', '塞巴斯蒂安·马尼斯科', '迪米特·D·马里诺夫']}
{'title': '惊奇队长', 'drectors': ['安娜·波顿', '瑞安·弗雷克'], 'rate': '7.0', 'casts': ['布丽·拉尔森', '裘德·洛', '塞缪尔·杰克逊', '本·门德尔森', '安妮特·贝宁']}
 ...
{'title': '这个杀手不太冷', 'drectors': ['吕克·贝松'], 'rate': '9.4', 'casts': ['让·雷诺', '娜塔莉·波特曼', '加里·奥德曼', '丹尼·爱罗', '彼得·阿佩尔']}
{'title': '新喜剧之王', 'drectors': ['周星驰', '邱礼涛', '黄骁鹏', '肖鹤'], 'rate': '5.8', 'casts': ['王宝强', '鄂靖文', '张全蛋', '景如洋', '张琪']}

Присмотревшись, мы обнаружим, что было захвачено только 20 фрагментов данных. Это невозможно для данных о фильмах, потому что обычная отображаемая информация веб-сайта будет разбита на страницы. Давайте снова посмотрим на страницу категории фильма, мы прокрутим вниз и найдем кнопку «загрузить еще» внизу. После нажатия будут загружены другие фильмы.

постраничное сканирование

Для вас нумерация страниц должна быть хорошо понятна. Точно так же, как книга, содержащая больше информации, естественно, требует нумерации страниц, и веб-сайт тоже. Однако в зависимости от сцены правила разбиения на страницы будут разными. Расскажем об этом подробнее:

Давайте сначала поговорим о параметрах пейджинга, которые обычно включают три параметра, а именно:

  • Для конкретных номеров страниц общими именами в URL являются page, p, n и т. д. Начальный номер страницы обычно равен 1, а в некоторых случаях равен 0;
  • Количество страниц на странице, общие имена в URL: limit, size, pagesize (page_size pageSize) и т. д.;
  • Начальная позиция, общие имена в url — start, offset и т. д., которые в основном указывают, откуда начинать получать данные;

Пейджинг в основном достигается за счет двух комбинаций этих трех параметров, какие две комбинации? Читать дальше:

  • Конкретный номер страницы + номер каждой страницы, это правило в основном используется в случае пейджера, а возвращаемые данные должны содержать общее количество записей;
  • Начальная позиция + количество страниц. Это правило в основном используется в раскрывающихся сценариях. Пример Douban — использование раскрывающегося списка для разбиения на страницы. В этом случае данные, возвращаемые URL, могут не включать общее количество. Есть ли данные на следующие страницы в начале можно использовать для определения того, разбита ли страница на страницы.Готово.

После введения двух общих правил пейджинга давайте взглянем на наш URL:

https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start=0

Страница пролистывается методом выпадающего списка, затем мы задаемся вопросом, есть ли в URL-адресе информация о начальной позиции. Конечно же, был найден начальный параметр, который здесь равен 0. Затем щелкните раскрывающийся список и получите новый URL-адрес с помощью мониторинга средства разработки браузера следующим образом:

https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start=20

Значение start становится равным 20, что означает, что параметр начальной позиции равен start. Согласно правилам пейджинга, мы модифицируем функцию main и добавим цикл while для получения всех данных о фильме Код выглядит следующим образом:

def main():
    url = 'https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start={}'

    start = 0
    total = 0
    while True:
        items = crawl(url.format(start))
        if len(items) <= 0:
            break

        for item in items:
            print(item)
        
        start += 20
        total += len(items)
        print('已抓取了{}条电影信息'.format(total))
    
    print('共抓取了{}条电影信息'.format(total))

Работа в основном сделана здесь! Измените операцию печати на операцию хранения и поместите захваченные данные в хранилище, и поисковый робот действительно завершится.

дальнейшая оптимизация

Я не знаю, заметили ли вы, что запрос здесь может получить только 20 кусков данных за раз, что неизбежно приведет к увеличению количества запросов данных. Что-то не так с этим? Три вопроса:

  • Серьезная трата сетевых ресурсов;
  • Скорость сбора данных слишком низкая;
  • Легко запустить механизм ползания волос;

Что нет способа сделать запрос на возврат объема данных увеличения? Конечно, есть.

Как упоминалось ранее, существует два линейных правила: конкретные номера страниц + размер и начальная позиция + размер страницы. Оба этих правила относятся к каждой странице, то есть к количеству на странице. Мы знаем, что приведенный выше интерфейс по умолчанию имеет значение 20 на размер страницы. В соответствии с ранее описанными правилами пейджинга мы попытались добавить в URL параметры лимита и размера. После проверки LIMIT можно использовать для изменения количества запросов на запрос. Измените код, добавьте параметр LIMIT в URL, чтобы он был равен 100:

url = 'https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start={}&limit=100'

Простое добавление параметра limit может помочь нам значительно сократить количество запросов к интерфейсу и повысить скорость сбора данных. Чтобы объяснить, не каждый раз нам так везет, иногда количество страниц на странице фиксировано, у нас нет возможности изменить, это нужно знать.

гусеничный ход высокой производительности

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

Параллельное программирование — большая тема, включающая многопоточность, многопроцессорность и асинхронный ввод-вывод, которые не являются предметом рассмотрения в этой статье. Здесь мы используем asyncio Python, чтобы повысить производительность поискового робота. Посмотрим на код реализации. Здесь необходимо объяснить одну проблему, поскольку Douban использует метод выпадающего списка для получения данных.Как описано выше, это способ разбиения на страницы без указания общего количества данных. Но таким образом у меня нет возможности заранее определить общее количество запросов на основе лимита и общего количества.Когда общее количество запросов неизвестно, наши запросы могут выполняться только последовательно. Итак, здесь мы можем продолжить для случая, предполагая, что максимальное количество данных равно 10 000, код выглядит следующим образом:

import json
import asyncio
import aiohttp

async def crawl(url):
    data = None
    async with aiohttp.ClientSession() as s:
        async with s.get(url) as r:
            if r.status != 200:
                raise Exception('http status code is {}'.format(r.status))
            data = json.loads(await r.text())['data']

    items = []
    for v in  data:
        items.append({
            'title': v['title'],
            'drectors': v['directors'],
            'rate': v['rate'],
            'casts': v['casts']
        })
    
    return items

async def main():
    limit = 100
    url = 'https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start={}&limit={}'
    start = 0
    total = 10000

    crawl_total = 0
    tasks = [crawl(url.format(start + i * limit, limit)) for i in range(total // limit)]
    for r in asyncio.as_completed(tasks):
        items = await r
        for item in items:
            print(item)
        crawl_total += len(items)

    print('共抓取了{}条电影信息'.format(crawl_total))

if __name__ == "__main__":
    ioloop = asyncio.get_event_loop()
    ioloop.run_until_complete(main())

Окончательный результат показывает, что было получено 9 900 фрагментов данных. Создается впечатление, что Douban ограничил количество перелистываний страниц и может получить не более 9 900 фрагментов данных.

Окончательный код использует асинхронное одновременное программирование Asyncio для повышения производительности рептилий, но также использует AIOHTTP в этой библиотеке для реализации асинхронных HTTP-запросов. Прыгая немного большая, есть ощущение, что вы можете научиться делать исчисление темы 1 + 1. Если вы хотите воспользоваться многоядерными, могут быть реализованы многопроцессорной комбинацией AiO +.

Суммировать

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

  • Эффективное использование пейджинга для снижения сетевых запросов и потребления ресурсов;
  • Параллельное программирование обеспечивает эффективное использование полосы пропускания и повышает скорость сканирования;

Наконец, если вам интересно, вы можете посмотреть один из них, реализованный в документации по торнадо.Сканер с высокой степенью параллелизма. Если вы не понимаете асинхронный ввод-вывод, этот код может показаться вам очень странным.