Руководство по использованию cURL с Python

В этой статье вы узнаете, как можно использовать вместе Python и cURL для автоматизации запросов GET, POST и PUT, а также для загрузки файлов и веб-страниц.
4 min read
Guide to using cURL with Python

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

Использование cURL с языком программирования дает множество преимуществ. Например, создание запросов может быть автоматизировано для настройки или веб-скрапинга.

В этой статье вы узнаете, как можно использовать Python и cURL для автоматизации запросов GET, POST и PUT, а также для загрузки файлов и веб-страниц.

Что такое cURL?

 

cURL — это программный проект. Однако его имя также используется в двух продуктах: библиотека libcurl и инструмент командной строки, известный как curl (который использует libcurl). При упоминании curl в этой статье подразумевается именно инструмент командной строки.

cURL считается универсальным. Однако его основная задача простая – передача данных по различным сетевым протоколам. Учитывая сложность современной сети, curl предлагает огромный список опций для обработки самых сложных запросов.

cURL выпустили в 1996 году под названием HttpGet и позже переименовали в urlget, затем он стал curl. Первым вариантом использования было получение курсов обмена валют для использования их в IRC-канале. В настоящее время curl поддерживает передачу данных различными способами, включая FTP(S), HTTP(S) (POST, GET, PUT), IMAP, POP3, MQTT и SMB. Кроме того, curl может обрабатывать файлы cookie и SSL-сертификаты.

Когда curl устанавливает соединение через HTTPS, он получает сертификат удаленного сервера и сверяет его со своим хранилищем сертификатов CA, чтобы убедиться, что удаленный сервер является тем, за кого себя выдает. Например, следующий запрос отправляет HTTPS-запрос на сайт Bright Data и устанавливает файл cookie, известный как greeting, со значением hello:

curl --cookie "greeting=hello" https://www.brightdata.com

Зачем использовать curl с Python?

Несмотря на то, что curl является универсальным инструментом, все же есть одна основная причина, по которой вы захотите использовать его с Python: Python может автоматизировать ваши запросы. Представляем 3 случая, когда эта комбинация является полезной:  

Веб-скрапинг

Веб-скрапинг — это практика сбора (часто больших) объемов данных с одной или нескольких веб-страниц. Чтобы собрать данные с помощью Python, люди часто используют библиотеку requests. Для рекурсивного парсинга вы можете использовать wget. Однако для продвинутых случаев парсинга со сложными вызовами HTTP(S) идеально подходит curl с Python.

Хотя данные с веб-страницы можно собрать с помощью одной команды curl, которая генерирует и обрабатывает запрос HTTP(S), она не может делать это рекурсивно. Встраивая curl в код Python, вы можете имитировать путь навигации по сайту, манипулируя такими элементами, как параметры запроса, cookie и пользовательские агенты.

Навигацию даже не нужно исправлять. За счет того, что он зависит от соскобленного содержимого, каждый новый запрос может быть полностью динамичным.

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

Кроме того, многие сайты имеют механизмы безопасности, которые затрудняют парсинг большого количества страниц: вспомните о защите от распределенного отказа в обслуживании (DDoS) или подсказке reCAPTCHA. Применяя определенные правила и паузы между запросами, можно имитировать поведение человека, которое сложнее обнаружить.

Тестирование и отладка

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

Например, если вы выпускаете новый процесс оформления заказа для своего (сложного) онлайн-сервиса, который использует файлы cookie, полагается на реферер, имеет незначительные различия для каждого браузера (т.е. пользовательский агент) и упаковывает все этапы процесса оформления заказа в тело POST-запроса, ручное тестирование может занять вечность. В Python вы можете создать словарь со всем набором параметров и отправить запрос с помощью curl для каждой возможной комбинации.

Автоматизация рабочего процесса

Помимо тестирования, отладки и просмотра веб-страниц, curl можно использовать для автоматизации рабочих процессов. Например, многие конвейеры интеграции данных начинаются с повторяющегося дампа экспорта данных, такого как файл CSV или Apache Parquet. С приложением Python, которое опрашивает новые файлы на (S)FTP-сервере, копирование дампов данных можно быть полностью автоматизировано.

Или рассмотрите настройку почтовых ящиков. Представьте, сколько ежедневных задач можно было бы автоматизировать, если бы приложение могло опрашивать сообщения электронной почты, содержащие запрос. Опрашивая новые сообщения по протоколу POP3 или IMAP, приложения Python могут запускаться, когда почтовый ящик получает определенное электронное письмо.

Как использовать cURL с Python

Существуют различные способы выполнения запросов с помощью curl в Python. В этой статье мы рассматриваем 2 варианта. Первый — имитировать запросы curl в командной строке через пакеты os и subprocess Python. Этот простой подход программно отправляет команды в интерфейс командной строки вашей ОС.

Второй вариант — использовать пакет PycURL. Если вы хотите узнать о других способах парсинга сайтов с помощью Python (без использования curl), ознакомьтесь с нашей статьей “Скрапинг веб-сайтов на Python — пошаговое руководство

Требования

Прежде чем приступить к работе, убедитесь, что вы загрузили и установили curl. Если вы используете Windows, обязательно добавьте curl в переменную среды PATH, чтобы вы могли просто выполнить команду curl.

Чтобы создать интерфейс Python с вашей ОС, вы можете использовать различные пакеты. Однако двумя наиболее популярными являются os и subprocess. Чтобы установить их, выполните следующую команду pip:

pip install os subprocess

Создание запроса с помощью curl и os

Пакет os — максимально простой пакет. Выполнение запроса curl без обработки ответа занимает всего две строки кода. Вам просто нужно передать файл cookie, описанный в предыдущем примере, и результат будет записан в файл output.txt:

import os
os.system('curl -o output.txt --cookie "greeting=hello" -k https://curl.se')

Если вы хотите обработать ответ в Python, а не записывать его в файл, вам следует использовать пакет subprocess, о котором мы расскажем в следующем разделе.

Следующий код выполняет тот же оператор, но вместо записи ответа в файл выводит stdout и stderr в виде кортежа. Затем этот вывод можно обработать с помощью других пакетов Python, таких, как Beautiful Soup:

import shlex
import subprocess
shell_cmd = shlex.split('curl --cookie "greeting=hello" -k https://curl.se')
process = subprocess.Popen(shell_cmd,
                    stdout = subprocess.PIPE,
                    stderr = subprocess.PIPE,
                    text = True,
                    shell = True
                    )
std_out, std_err = process.communicate()
std_out.strip(), std_err

Использование PycURL

Вместо взаимодействия с вашим терминалом на Python вы можете использовать пакет PycURL. Если вы пользователь Linux, вам повезло, поскольку вы можете установить PycURL с помощью pip:

pip install pycurl
pip install certifi

Вам нужно установить certifi для взаимодействия по протоколу HTTPS. Если у вас возникнут проблемы, следуйте этим инструкциям из Stack Overflow.

Хотя PycURL также можно установить и на Windows, это очень неприятное занятие. Если вы попытаетесь установить его через pip, он выдаст ошибку:

Please specify --curl-dir=/path/to/built/libcurl

Поэтому вам нужно установить его из исходного кода, что “не для слабонервных из-за множества возможных зависимостей, каждая из которых имеет свою структуру каталогов, стиль конфигурации, параметры и особенности”. Рекомендуем придерживаться пакета requests для основных сетевых запросов, если вы работаете на Windows.

Как создавать запросы с PycURL

Следующая часть статьи будет посвящена созданию различных типов запросов с помощью пакета PycURL.

Создание запроса GET с помощью PycURL

Самый простой запрос, который вы можете сделать с помощью PycURL, — это запрос GET. По сути, это шаблон для всех других шаблонов в данном разделе.

В следующем коде можно выделить 5 шагов:

  1. Импорт всех необходимых пакетов
  2. Создание 2-х объектов: буфер, в котором запрос curl будет хранить свой ответ, и объект curl, который используется для выполнения запроса.
  3. Введение параметров запроса: URL-адрес, пункт назначения и проверка SSL.
  4. Выполнение запроса.
  5. Результат выполнения запроса.
# Preparation
import pycurl
import certifi
from io import BytesIO

# Set buffer and Curl object.
buffer = BytesIO()
c = pycurl.Curl()

# Set request options.
## Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/')

## Set the buffer as the destination of the request's response.
c.setopt(c.WRITEDATA, buffer)

## Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
c.perform()
c.close()

# Print the buffer's content with a Latin1 (iso-8859-1) encoding.
body = buffer.getvalue()
data = body.decode('iso-8859-1')
print(data)

Выполнение POST-запроса с помощью PycURL

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

# Preparation
import pycurl
import certifi
from io import BytesIO

# Set buffer and Curl object.
buffer = BytesIO()
c = pycurl.Curl()

# Set request options.
## Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/')

## Set the request's body.
post_body = {'greeting': 'hello'}
postfields = urlencode(post_body)
c.setopt(c.POSTFIELDS, postfields)

## Set the buffer as the destination of the request's response.
c.setopt(c.WRITEDATA, buffer)

## Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
c.perform()
c.close()

# Print the buffer's content with a Latin1 (iso-8859-1) encoding.
body = buffer.getvalue()
print(body.decode('iso-8859-1'))

Выполнение запроса PUT с PycURL

Запрос POST, который вы создали в предыдущем разделе, также можно отправить как запрос PUT. Вместо того чтобы отправлять ключевое значение в теле запроса, вы отправите его в виде представления файла, закодированного в UTF-8. Этот метод также можно использовать для загрузки файлов:

import pycurl
import certifi
from io import BytesIO

c = pycurl.Curl()

# Set request options.
## Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/')

## Set data for the PUT request.
c.setopt(c.UPLOAD, 1)
data = '{"greeting": "hello"}'
buffer = BytesIO(data.encode('utf-8'))
c.setopt(c.READDATA, buffer)

## Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
c.perform()
c.close()

Загрузка файла с помощью PycURL

Следующий фрагмент демонстрирует, как можно загрузить файл с помощью PycURL. Запрашивается случайное изображение в формате JPEG, открывается поток записи на some_image.jpg и передается в PycURL в качестве места назначения для файла:  

import pycurl
import certifi

c = pycurl.Curl()

# Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/some_image.jpg')

# Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
with open('some_image.jpg', 'w') as f:
    c.setopt(c.WRITEFUNCTION, f.write)
    c.perform()

c.close()

Загрузка и обработка веб-страницы с помощью PycURL

Поскольку многие случаи использования PycURL связаны с парсингом веб-страниц, далее описывается, как вы можете обрабатывать ответ на запрос с помощью Beautiful Soup, популярного пакета для анализа HTML-файлов.

Для начала установите Beautiful Soup 4 с помощью pip:

pip install beautifulsoup4

Затем поместите следующий сниппет сразу после первого фрагмента PycURL, который сделал запрос GET. Это заставит Beautiful Soup обработать данные ответа.

Для демонстрации используется метод find_all, чтобы найти все элементы параграфа, и вывести содержимое отдельных параграфов:

from bs4 import BeautifulSoup

# Parsing data using BeautifulSoup
soup = BeautifulSoup(data, 'html.parser')

# Find all paragraphs
paragraphs = soup.find_all('p')
for p in paragraphs:
   print(p.text)

Использование прокси с PycURL

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

В заключительном разделе вы узнаете, как создать запрос с PycURL через прокси. Для этого нужны настройки параметров запроса, как вы делали это ранее. Мы представляем 4 настройки, однако вы можете настроить их под свою ситуацию:

  1. Для облегчения задачи включены небезопасные прокси.
  2. Прокси настроен.
  3. Скрипт аутентифицируется на сервере.
  4. Прокси устанавливается как HTTPS.
# Enable insecure proxies
c.setopt(c.PROXY_SSL_VERIFYHOST, 0)
c.setopt(c.PROXY_SSL_VERIFYPEER, 0)

# Set proxy server
c.setopt(pycurl.PROXY, <YOUR_HTTPS_PROXY_SERVER>)

# Authenticate with the proxy server
c.setopt(pycurl.PROXYUSERPWD, f"{<YOUR_USERNAME>}:{<YOUR_PASSWORD>}")

# Set proxy type to https
c.setopt(pycurl.PROXYTYPE, 2)

Эти параметры можно вставить в любом месте ранее описанного фрагмента кода, чтобы запрос перенаправлялся через прокси-сервер.

Подведем итог

В этой статье мы подробно рассказали о комбинации curl и Python, а также показали, почему следует использовать их вместе для генерации сложных запросов для веб-скрапинга и тестирования приложений. Вы увидели несколько примеров, демонстрирующих универсальность PycURL для создания множества сетевых запросов.

В качестве альтернативы вы можете использовать прокси-сеть Bright Data и IDE веб-парсера, которая была разработана специально для выполнения всей тяжелой работы разработчиков. Таким образом, вы можете сосредоточиться на работе с полученными данными, а не беспокоиться о том, как обойти механизмы защиты от парсинга.