Часто задаваемые вопросы

В чём отличие Scrapy по сравнению с BeautifulSoup или lxml?

BeautifulSoup и lxml — библиотеки для синтаксического анализа HTML и XML. Scrapy — это платформа приложений для написания веб-пауков, которые сканируют веб-сайты и извлекают из них данные.

Scrapy предоставляет встроенный механизм для извлечения данных (называемый селекторы), но вы можете легко использовать вместо него BeautifulSoup (или lxml), если вам удобнее с ними работать. В конце концов, они просто анализируют библиотеки, которые можно импортировать и использовать из любого кода Python.

Другими словами, сравнение BeautifulSoup (или lxml) с Scrapy похоже на сравнение jinja2 с Django.

Могу ли я использовать Scrapy с BeautifulSoup?

Да, ты можешь. Как уже упоминалось, выше, BeautifulSoup может использоваться для анализа ответов HTML в обратных вызовах Scrapy. Вам просто нужно передать тело ответа в объект BeautifulSoup и извлечь из него все необходимые данные.

Вот пример паука, использующего BeautifulSoup API с lxml в качестве парсера HTML:

from bs4 import BeautifulSoup
import scrapy


class ExampleSpider(scrapy.Spider):
    name = "example"
    allowed_domains = ["example.com"]
    start_urls = (
        'http://www.example.com/',
    )

    def parse(self, response):
        # use lxml to get decent HTML parsing speed
        soup = BeautifulSoup(response.text, 'lxml')
        yield {
            "url": response.url,
            "title": soup.h1.string
        }

Примечание

BeautifulSoup поддерживает несколько парсеров HTML/XML. См. официальную документацию BeautifulSoup“, чтобы узнать, какие из них доступны.

Scrapy «украл» X у Django

Наверное, но нам это слово не нравится. Мы думаем, что Django — отличный проект с открытым исходным кодом и пример для подражания, поэтому мы использовали его как источник вдохновения для Scrapy.

Мы считаем, что если что-то уже сделано хорошо, нет необходимости изобретать это заново. Эта концепция, помимо того, что является одной из основ для программного обеспечения с открытым исходным кодом и бесплатного программного обеспечения, применима не только к программному обеспечению, но и к документации, процедурам, политикам и т. д. Таким образом, вместо того, чтобы самостоятельно решать каждую проблему, мы предпочитаем копировать идеи из данных проектов. которые уже решили их должным образом, и сосредоточить внимание на реальных проблемах, которые нам нужно решить.

Мы будем гордиться, если Scrapy послужит источником вдохновения для других проектов. Не стесняйтесь воровать у нас !

Scrapy работает с HTTP-прокси?

Да. Поддержка HTTP-прокси предоставляется (начиная с Scrapy 0.8) через промежуточное программное обеспечение загрузчика HTTP-прокси. См. HttpProxyMiddleware.

Как я могу очистить элемент с атрибутами на разных страницах?

См. Передача дополнительных данных в функции обратного вызова.

Scrapy вылетает с ошибкой: ImportError: No module named win32api

Вам необходимо установить pywin32 из-за бага в Twisted.

Как я могу смоделировать логин пользователя в моём пауке?

См. Использование FormRequest.from_response() для имитации входа пользователя в систему.

Сканирует ли Scrapy в ширину или в глубину?

По умолчанию Scrapy использует очередь LIFO для хранения ожидающих запросов, что в основном означает, что он просматривает DFO порядок. Данный порядок в большинстве случаев более удобен.

Если вы действительно хотите сканировать с истинным BFO порядком, вы можете сделать это, установив следующие параметры:

DEPTH_PRIORITY = 1
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'

Хотя ожидающие запросы ниже настроенных значений CONCURRENT_REQUESTS, CONCURRENT_REQUESTS_PER_DOMAIN или CONCURRENT_REQUESTS_PER_IP, данные запросы отправляются одновременно. В результате первые несколько запросов сканирования редко следуют желаемому порядку. Понижение данных параметров до 1 обеспечивает желаемый порядок, но значительно замедляет сканирование в целом.

У моего паука Scrapy утечки памяти. Что я могу сделать?

См. Устранение утечек памяти.

Кроме того, Python имеет встроенную проблему утечки памяти, которая описана в Утечки без утечек.

Как сделать так, чтобы Scrapy потреблял меньше памяти?

См. предыдущий вопрос.

Как я могу предотвратить ошибки памяти из-за большого количества разрешенных доменов?

Если у вас есть паук с длинным списком allowed_domains (например, 50 000+), подумайте о замене промежуточного программного обеспечения паука OffsiteMiddleware по умолчанию на пользовательское промежуточное ПО паука, которое требует меньше памяти. Например:

  • Если ваши доменные имена достаточно похожи, используйте собственное регулярное выражение вместо объединения строк в allowed_domains в сложное регулярное выражение.

  • Если вы можете соответствовать требованиям установки, используйте pyre2 вместо Python re для компиляции регулярного выражения фильтрации URL-адресов.

См. также другие предложения в StackOverflow.

Примечание

Не забудьте отключить scrapy.spidermiddlewares.offsite.OffsiteMiddleware при включении собственной реализации:

SPIDER_MIDDLEWARES = {
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
    'myproject.middlewares.CustomOffsiteMiddleware': 500,
}

Могу ли я использовать базовую HTTP-аутентификацию в своих пауках?

Да, см. HttpAuthMiddleware.

Почему Scrapy загружает страницы на английском, а не на моем родном языке?

Попробовать изменить заголовок запроса по умолчанию Accept-Language, переопределив параметр DEFAULT_REQUEST_HEADERS.

Где я могу найти примеры проектов Scrapy?

См. Примеры.

Могу ли я запустить паука без создания проекта?

Да. Вы можете использовать команду runspider. Например, если у вас есть паук, записанный в файле my_spider.py, вы можете запустить его:

scrapy runspider my_spider.py

См. команду runspider для получения дополнительной информации.

Я получаю сообщения «Отфильтрованный внешний запрос». Как я могу их исправить?

Данные сообщения (зарегистрированные с уровнем DEBUG) не обязательно означают наличие проблемы, поэтому вам, возможно, не нужно их исправлять.

Данные сообщения отправляются Offsite Spider Middleware, которое является промежуточным программным обеспечением для пауков (включено по умолчанию), целью которого является отфильтровывать запросы к доменам за пределами тех, которые покрываются пауком.

Для получения дополнительной информации см .: OffsiteMiddleware.

Могу ли я использовать JSON для большого экспорта?

Это будет зависеть от того, насколько велик ваш результат. См. эти предупреждения в документации JsonItemExporter.

Могу ли я вернуть (Twisted) deferred’ы из обработчиков сигналов?

Некоторые сигналы поддерживают возврат отложенных сообщений от своих обработчиков, другие — нет. См. Справочник по встроенным сигналам, чтобы узнать, какие именно.

Что означает код состояния ответа 999?

999 — это настраиваемый код состояния ответа, используемый сайтами Yahoo для ограничения запросов. Попробовать снизить скорость сканирования, используя для своего паука задержку загрузки 2 (или выше):

class MySpider(CrawlSpider):

    name = 'myspider'

    download_delay = 2

    # [ ... rest of the spider code ... ]

Или установив глобальную задержку загрузки в вашем проекте с помощью параметра DOWNLOAD_DELAY.

Могу ли я вызвать pdb.set_trace() от моих пауков, чтобы отладить их?

Да, но вы также можете использовать оболочку Scrapy, которая позволяет вам быстро анализировать (и даже изменять) ответ, обрабатываемый вашим пауком, что довольно часто более полезно, чем старый добрый pdb.set_trace().

Для получения дополнительной информации см. Вызов оболочки от пауков для проверки ответов.

Самый простой способ сбросить все мои скопированные элементы в файл JSON/CSV/XML?

Сбросить в файл JSON:

scrapy crawl myspider -O items.json

Сбросить в файл CSV:

scrapy crawl myspider -O items.csv

Сбросить в XML файл:

scrapy crawl myspider -O items.xml

Для получения дополнительной информации см. Экспорт фидов

Что за огромный загадочный параметр __VIEWSTATE используется в некоторых формах?

Параметр __VIEWSTATE используется на сайтах, созданных с помощью ASP.NET/VB.NET.

Как лучше всего анализировать большие потоки данных XML/CSV

Разбор больших фидов с помощью селекторов XPath может быть проблематичным, поскольку им необходимо построить DOM всего фида в памяти, а это может быть довольно медленным и потреблять много памяти.

Чтобы не разбирать весь фид сразу в памяти, можно использовать функции xmliter и csviter из модуля scrapy.utils.iterators. Фактически, это то, что пауки подачи (см. Пауки) используемые под капотом.

Управляет ли Scrapy файлами cookie автоматически?

Да, Scrapy получает и отслеживает cookie, отправленные серверами, и отправляет их обратно при последующих запросах, как это делает любой обычный веб-браузер.

Для получения дополнительной информации см. Запросы и ответы и CookiesMiddleware.

Как я могу увидеть cookie, отправляемые и получаемые от Scrapy?

Включает параметр COOKIES_DEBUG.

Как я могу заставить паука остановиться?

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

Как я могу предотвратить блокировку моего бота Scrapy?

См. Как избежать бана.

Должен ли я использовать аргументы или настройки паука для настройки моего паука?

И аргументы паука, и настройки можно использовать для настройки вашего паука. Нет строгого правила, которое обязывает использовать тот или иной, но настройки больше подходят для параметров, которые после установки не сильно меняются, в то время как аргументы паука должны изменяться чаще, даже при каждом запуске паука, а иногда и изменяются. требуется для запуска паука (например, для установки начального URL-адреса паука).

Чтобы проиллюстрировать это примером, предположим, что у вас есть паук, которому необходимо войти на сайт для очистки данных, и вы хотите очистить данные только из определенного раздела сайта (который каждый раз меняется). В этом случае учётные данные для входа будут настройками, а URL-адрес раздела, который нужно очистить, будет аргументом паука.

Я очищаю XML-документ, и мой селектор XPath не возвращает никаких элементов

Возможно, вам придется удалить пространства имён. См. Удаление пространств имён.

Как разделить элемент на несколько элементов в конвейере элементов?

Конвейеры элементов не может давать несколько элементов для одного элемента ввода. Создание промежуточного программного обеспечения паука и используйте для этой цели его метод process_spider_output(). Например:

from copy import deepcopy

from itemadapter import is_item, ItemAdapter

class MultiplyItemsMiddleware:

    def process_spider_output(self, response, result, spider):
        for item in result:
            if is_item(item):
                adapter = ItemAdapter(item)
                for _ in range(adapter['multiply_by']):
                    yield deepcopy(item)

Поддерживает ли Scrapy адреса IPv6?

Да, установив DNS_RESOLVER на scrapy.resolver.CachingHostnameResolver. Обратите внимание, что при этом вы теряете возможность устанавливать определенный тайм-аут для DNS-запросов (значение параметра DNS_TIMEOUT игнорируется).

Как бороться с исключениями <class 'ValueError'>: filedescriptor out of range in select()?

Эта проблема, как сообщалось, появляется при выполнении широких обходов в macOS, где по умолчанию используется витой реактор twisted.internet.selectreactor.SelectReactor. Переключение на другой реактор возможно с помощью настройки TWISTED_REACTOR.

Как я могу отменить загрузку данного ответа?

В некоторых ситуациях может быть полезно остановить загрузку определенного ответа. Например, иногда вы можете определить, нужно ли вам полное содержимое ответа, проверив его заголовки или первые байты его тела. В этом случае вы можете сэкономить ресурсы, подключив обработчик к сигналам bytes_received или headers_received и вызвав исключение StopDownload. Пожалуйста, обратитесь к теме Остановка загрузки ответа за дополнительной информацией и примерами.

Запустив runspider, я получаю error: No spider found in file: <filename>

Это может произойти, если в вашем проекте Scrapy есть модуль-паук с именем, которое конфликтует с именем одного из модулей стандартной библиотеки Python, например csv.py или os.py, или любого установленного вами Python пакета.