Запуск пауков Scrapy локально в Cron Job
Table Of Content
- ...или любом другом скрипте
- TLDR…просто дай мне код!!!
- создайте скрипт для запуска паука
- перейти в директорию паука
- запустить паука
- сделать скрипт исполняемым
- добавить cron на ваш компьютер
- добавление скрипта в cron
- экспорт зависимостей
- перейти в каталог со скрапером
- перейти в каталог со скрапером
- проверка успешного выполнения
- перейти в директорию со скрапером
- логирование каждый раз, когда запускается скрапер
- получить дату и время начала
- перейти в каталог со скрапером
- предотвратить сбой click, от которого зависит pipenv, из-за отсутствия информации о локали [https://click.palletsprojects.com/en/7.x/python3/](https://click.palletsprojects.com/en/7.x/python3/)
- запустить скрапер
- получить дату и время окончания
- улучшение скрипта для большей портативности и других улучшений
- получить текущую дату и время
- Заключение
...или любом другом скрипте
У меня есть набор пауков, которые запускаются еженочно для обновления классов для инструмента поиска классов в колледже сообщества, который я создал, btp. После того, как я разместил пауки на Scrapinghub на протяжении нескольких лет, у меня возникла ошибка TSL, которая возникает только на Scrapinghub, но не локально (ошибка, с которой столкнулись несколько других пользователей). Я пытался решить эту проблему несколько месяцев, но безуспешно. Чтобы усугубить моё разочарование, Scrapinghub позволяет получать техническую поддержку только платным пользователям, поэтому было непросто попросить помощи - я пытался заплатить за неё, но моя карта продолжала отклонять запрос, их банк находится в Ирландии.
В выходные я решил просто запустить пауки локально на свободном ноутбуке с Ubuntu, который у меня был. В этом руководстве описан этот процесс, но эти шаги можно выполнить на любой Unix-машине - cron-задания работают на моем Mac, например. Это руководство предназначено для людей, у которых уже есть работающие пауки и которым просто нужно их развернуть. Однако это руководство будет работать для любого, кто пытается периодически запускать любой произвольный скрипт или команду. Я использовал pipenv (виртуальная среда Python) и cron/crontab, чтобы выполнить это.
TLDR…просто дай мне код!!!
Вот gist с конечным скриптом и записью в cron.
создайте скрипт для запуска паука
Создайте новый bash-файл crawl.sh
со следующим содержимым:
#!/bin/sh
# перейти в директорию паука
cd /Users/michael/repos/spiders
# запустить паука
pipenv run scrapy crawl multi_subject_spider
Этот скрипт переходит в директорию, содержащую проект Scrapy, запускает виртуальное окружение с помощью pipenv
и выполняет команду scrapy crawl
внутри этого окружения. Я настоятельно рекомендую использовать pipenv
, потому что он позволяет делать крутые вещи, подобные этой, не беспокоясь о активации и деактивации виртуальных окружений. pipenv run
запускает окружение, выполняет любую команду в нем и выходит из окружения, возвращая вывод команды. Это позволяет передавать аргументы команде, которую вы выполняете, и легко записывать ее вывод.
сделать скрипт исполняемым
По умолчанию новые bash-файлы не являются исполняемыми, и это означает, что cron
не сможет запустить их. Вы можете сделать их исполняемыми, выполнив следующую команду.
chmod +x crawl.sh
добавить cron на ваш компьютер
Cron - это программа, которая запускает задания, описанные в crontab. Вы используете команду crontab -e
для редактирования списка заданий, а crontab -l
для просмотра списка заданий. Запись в cron или crontab - это описание задания, например, 30 1 * * * echo "пора спать!"
выполняет echo "пора спать!"
в 1:30 утра местного времени каждый день недели.
Если вы используете Mac или Linux, cron должен уже быть на вашем компьютере. Проверьте, открыв терминал и запустив crontab -l
, который покажет существующие задания cron. Что насчет Windows? Установите Ubuntu, это бесплатно и просто в использовании. Или запустите его виртуально с помощью VirtualBox.
добавление скрипта в cron
Это можно сделать, запустив crontab -e
в терминале. Это откроет редактор терминала, по умолчанию Vi, с помощью которого вы можете редактировать свой список cron. Вы можете передать переменную среды, чтобы установить редактор, например, для nano EDITOR=nano crontab -e
.
30 1 * * * /Users/michael/repos/crawl.sh
Эта задача будет выполнять crawl.sh
в 1:30 утра местного времени каждый день недели. Вы можете узнать больше о формате времени cron здесь. Выйдите из редактора и сохраните файл, с nano это CTRL+X
, а затем Y
. Запустите crontab -l
, чтобы увидеть новую задачу.
экспорт зависимостей
Работа будет запущена, но скрипт завершится с ошибкой "неизвестная команда". Cron выполняет ваш скрипт в новой оболочке с минимальным набором переменных среды и путей. Библиотеки Python, такие как pipenv
и scrapy
, не будут доступны в этой оболочке. Мы можем исправить это, жестко закодировав пути к необходимым командам в скрипте или, что лучше, экспортировав путь в скрипт. Для этого нам нужно получить путь к pipenv
(вы можете сделать это, запустив which pipenv
). Затем отредактируйте задание, запустив crontab -e
снова. Измените его на следующее:
30 1 * * * export PIPENV=/Library/Frameworks/Python.framework/Versions/3.6/bin/pipenv && /Users/michael/repos/crawl.sh
Это экспортирует путь pipenv
как PIPENV
в оболочку, в которой cron будет запускать crawl.sh
, а затем выполняет crawl.sh
(вы можете объединять команды с помощью оператора "и", &&
). Теперь нам нужно отредактировать crawl.sh
, чтобы использовать переменную среды PIPENV
.
#!/bin/sh
# перейти в каталог со скрапером
cd /Users/michael/repos/spiders# запустить скрапер
$PIPENV run scrapy crawl multi_subject_spider
$
означает, что PIPENV
- это переменная, и ее значение будет получено и выполнено. Однако этот скрипт пока не будет работать. Оказывается, что у pipenv
есть зависимость [click](https://click.palletsprojects.com/en/7.x/)
, которая ожидает, что локаль будет доступна в оболочке, в которой выполняется pipenv
. Это можно исправить, экспортировав еще одну переменную, на этот раз в crawl.sh
.
#!/bin/sh
# перейти в каталог со скрапером
cd /Users/michael/repos/spiders# предотвратить сбой click, от которого зависит pipenv, из-за отсутствия информации о локали [https://click.palletsprojects.com/en/7.x/python3/](https://click.palletsprojects.com/en/7.x/python3/)
export LC_ALL=en_US.utf-8# запустить скрапер
$PIPENV run scrapy crawl multi_subject_spider
Теперь, когда локаль доступна, и мы вызываем pipenv
напрямую, скрипт будет работать.
проверка успешного выполнения
Вы можете проверить, успешно ли выполнилась задача, запустив crontab -l
после выполнения задачи. В выводе терминала будет дополнительный текст, указывающий на var/mail/USERNAME
, где находится вывод ошибок. Если ошибок нет, то этот текст не появится. Более надежный способ проверки статуса задачи - это запись вывода pipenv run
. Давайте запишем вывод pipenv run
:
#!/bin/sh
# перейти в директорию со скрапером
cd /Users/michael/repos/spiders# предотвратить сбой click, от которого зависит pipenv, из-за отсутствия информации о локали [https://click.palletsprojects.com/en/7.x/python3/](https://click.palletsprojects.com/en/7.x/python3/)
export LC_ALL=en_US.utf-8# получить дату и время
datetime=$(date '+%m_%d_%Y_%H_%M_%S')# запустить скрапер
$PIPENV run scrapy crawl multi_subject_spider -a debug='True' &> "logs/log_${datetime}.txt"
Этот код получает временную метку mm_dd_yyyy_hh_mm_ss
и перенаправляет весь вывод $PIPENV run scrapy crawl multi_subject_spider
в файл журнала в /Users/michael/repos/spiders/logs
. Я добавил временную метку в имя журнала, чтобы каждый журнал был уникальным и избежать перезаписи файлов, а также чтобы облегчить отладку. Оператор &>
перезаписывает существующие файлы или создает файл, если он не существует. Он также захватывает как ошибки, так и обычный вывод.
Я передаю аргумент в свой скрапер с помощью -a debug='True'
, это пользовательский код, который я добавил в свой скрапер для записи всех запросов и ответов.
логирование каждый раз, когда запускается скрапер
Мы можем добавить логирование в саму запись в crontab, чтобы перехватить любые ошибки или другой вывод, который находится вне pipenv run
. Это позволит нам добавить время начала и окончания в crawl.sh
, что позволит нам получить больше контекста о наших заданиях. Этот новый лог будет фиксировать ошибки в нашем формате времени cron, в том, как мы экспортируем наши переменные, и любой другой вывод, не созданный pipenv run
. Внесите следующие изменения в запись в crontab:
30 1 * * * export PIPENV=/Library/Frameworks/Python.framework/Versions/3.6/bin/pipenv && /Users/michael/repos/crawl.sh >> cron_log.txt 2 >& 1
Это регистрирует весь вывод crawl.sh
и запись в crontab в файл cron_log.txt
, но в режиме добавления, содержимое файла не будет перезаписано. Затем 2 >& 1
перенаправляет ошибки (2
) туда, куда отправляется обычный вывод (1
), в данном случае в cron_log.txt
. Теперь мы можем использовать команду echo для вывода временной метки и нескольких других полезных сообщений в crawl.sh
, и они будут отображаться в cron_log.txt
.
#!/bin/sh
# получить дату и время начала
start_datetime=$(date '+%m_%d_%Y_%H_%M_%S')
echo "${start_datetime} - начало работы скрапера"
# перейти в каталог со скрапером
cd /Users/michael/repos/spiders
# предотвратить сбой click, от которого зависит pipenv, из-за отсутствия информации о локали [https://click.palletsprojects.com/en/7.x/python3/](https://click.palletsprojects.com/en/7.x/python3/)
export LC_ALL=en_US.utf-8
# запустить скрапер
$PIPENV run scrapy crawl multi_subject_spider -a debug='True' &> "logs/log_${start_datetime}.txt"
# получить дату и время окончания
end_datetime=$(date '+%m_%d_%Y_%H_%M_%S')
echo "${end_datetime} - скрапер успешно завершен"
Теперь у нас есть информация о том, когда наши скраперы начинают и заканчивают работу. Это создаст лог в файле /Users/michael/cron_log.txt
, который будет выглядеть следующим образом:
07_25_2020_22_40_00 - начало работы скрапера
07_25_2020_22_40_03 - скрапер успешно завершен
07_25_2020_22_56_00 - начало работы скрапера
07_25_2020_22_56_03 - скрапер успешно завершен
07_25_2020_23_03_00 - начало работы скрапера
07_25_2020_23_03_02 - скрапер успешно завершен
Мы также можем установить путь к файлу журнала, чтобы он был более доступным: >> /Users/michael/repos/spiders/logs/cron_log.txt 2 >& 1
Еще одно улучшение здесь - зарегистрировать имя скрапера и переданные ему аргументы.
улучшение скрипта для большей портативности и других улучшений
Что если вы хотите взять crawl.sh
и запустить его на другом компьютере? Возможно, вы хотите передать аргументы пауку? Нам нужно больше переменных среды!
Обновите скрипт с дополнительными переменными:
- путь к паукам
SPIDER_PATH
, чтобы сделать скрипт независимым от компьютера - паук для запуска
SPIDER_NAME
, для отладки и гибкости - аргументы для передачи пауку, пока только
DEBUG
#!/bin/sh
# получить текущую дату и время
start_datetime=$(date '+%m_%d_%Y_%H_%M_%S')
echo "${start_datetime} - запуск паука ${SPIDER_NAME} - отладка: ${DEBUG}"# перейти в директорию с пауками
cd $SPIDER_PATH# предотвратить сбои click, от которого зависит pipenv, из-за отсутствия информации о локали [https://click.palletsprojects.com/en/7.x/python3/](https://click.palletsprojects.com/en/7.x/python3/)
export LC_ALL=en_US.utf-8# запустить паука
$PIPENV run scrapy crawl $SPIDER_NAME -a debug=$DEBUG &> "logs/log_${start_datetime}.txt"# получить конечную дату и время
end_datetime=$(date '+%m_%d_%Y_%H_%M_%S')
echo "${end_datetime} - паук успешно завершил работу"
Обновите запись в cron:
30 1 * * * export PIPENV=/Library/Frameworks/Python.framework/Versions/3.6/bin/pipenv SPIDER_PATH=/Users/michael/repos/spiders SPIDER_NAME=multi_subject_spider DEBUG=True && /Users/michael/repos/crawl.sh >> /Users/michael/repos/spiders/logs/cron_log.txt 2 >& 1
Это выглядит не очень красиво, но, к сожалению, записи в crontab должны быть в одной строке, поэтому мы не можем разделить их для улучшения читаемости. Однако, вот что происходит с экспортами:
PIPENV=/Library/Frameworks/Python.framework/Versions/3.6/bin/pipenv
SPIDER_PATH=/Users/michael/repos/spiders
SPIDER_NAME=multi_subject_spider
DEBUG=True
Итоговый скрипт и запись в cron можно посмотреть здесь.
Заключение
С этим у вас должно быть хорошее начальное положение для парсинга интернета в удобном, прозрачном и предсказуемом формате. Лучше всего это все делать с помощью вашего локального компьютера. Что насчет блокировщиков IP? Чтобы избежать блокировки, я бы порекомендовал вам инвестировать в VPN и поместить своих парсеров за ним. Убедитесь, что VPN открывает каждое соединение с новым IP, и у вас все будет в порядке. Счастливого парсинга!