Post text error

Ответили на вопрос 2 человека. Оцените лучшие ответы! И подпишитесь на вопрос, чтобы узнавать о появлении новых ответов.

Пишу парсер сайта для отслеживания цены и по заданному времени отправляю отчёт в Телеграм если цена упала.
Есть хороший код для отправки текстового сообщения:

def send_telegram(text: str):
    token = "MY_TOKEN"
    url = "https://api.telegram.org/bot"
    channel_id = "MY_CHANNELID"
    url += token
    method = url + "/sendMessage"
    r = requests.post(method, data={
         "chat_id": channel_id,
         "text": text
          })
    if r.status_code != 200:
        raise Exception("post_text error")

как используя ту же конструкцию отправить фото, либо с компа либо напрямую с сайта.


  • Вопрос задан

    более года назад

  • 876 просмотров

Ответ нашёл. Оставлю готовый код:

import requests
def send_photo_telegram():
    files = {'photo': open('sity.jpg', 'rb')}
    token = "ТОКЕН БОТА"
    chat_id = "ЧАТ ID" # если у вас группа то будет так chat_id = "-1009999999"
    r = requests.post("https://api.telegram.org/bot"+token+"/sendPhoto?chat_id=" + chat_id, files=files)
    if r.status_code != 200:
        raise Exception("post_text error")
send_photo_telegram()

Пригласить эксперта


  • Показать ещё
    Загружается…

10 февр. 2023, в 02:20

3000 руб./за проект

10 февр. 2023, в 01:33

1500 руб./за проект

10 февр. 2023, в 00:54

2000 руб./в час

Минуточку внимания

Задача: отправлять сообщение о звонке в телеграм, данные о звонке которые мы будем отправлять — номер звонящего и номер вызываемого абонента. Нам потребуется: cервер с Asterisk, Python3.6 или выше и pip3. 1. Создадим телеграм бота 1.1. Открываем телеграмм и в поиске находим BotFather 1.2. пишем ему команду /newbot пишем ему имя бота и username (username […]

Отправка уведомлений о звонках в Telegram

Задача: отправлять сообщение о звонке в телеграм, данные о звонке которые мы будем отправлять — номер звонящего и номер вызываемого абонента.

Нам потребуется: cервер с Asterisk, Python3.6 или выше и pip3.

1. Создадим телеграм бота

1.1. Открываем телеграмм и в поиске находим BotFather

BotFather

1.2. пишем ему команду /newbot пишем ему имя бота и username (username на конце должен содержать слово bot), а в ответ мы получаем api key который нужен дальше для отправки сообщений через бота.

(Мой ключ использовать не нужно, я все равно удалю бота)

2. Пишем бота.

Бот будет максимально простой, но для его работы нам понадобится установить пару зависимостей.

2.1. Установка библиотеки requests и asterisk в python.

       Выполним команду pip3 install requests asterisk

выполним команду pip3 install requests asterisk

2.2. В папке /usr/share/asterisk/agi-bin/ создаем файл bot.py

cd /usr/share/asterisk/agin-bin/
touch bot.py - команда touch создает или обновляет дату создания файла

2.3 после чего откроем его в любом удобном текстовом редакторе в моем случаи это vim

vim bot.py

2.4. Впишем следующий код в данный файл:

#!/usr/bin/python3.6

import requests
import sys
import pymssql
from asterisk.agi import AGI

agi = AGI()
phone = str(agi.env["agi_callerid"])
exten = str(agi.env["agi_extension"])

text = 'Совершен вызов с номера: ' + phone + ' на номер: ' + exten

def main(text: str):
    token = ""
    url = "https://api.telegram.org/bot"
    channel_id = ""
    url += token
    method = url + "/sendMessage"

    r = requests.post(method, data={
         "chat_id": channel_id,
         "text": text
          })

    if r.status_code != 200:
        raise Exception("post_text error")

if __name__ == '__main__':
    main(text)

token — токен для бота, который выдал вам BotFather.

channel_id — ваш id телеграмма.

3. В /etc/asterisk/extensions_custom.conf пропишем следующее:

[from-code-num]

exten => 333,1,Answer()
same => n,AGI(bot.py)
same => n,Hangup()

При звонке на номер 333 Мы запускаем наш скрипт bot.py, что бы ловить вызов на любой номер вместо 333 напишите _XXX.

4. В разделе Connectivity перейдем в custom context и создадим новый контекст нажав на кнопку Add Context.

Настройки выставим следующие:

Тут мы разрешаем вызовы на все локальные номера, а также вызовы по всем маршрутам.

Далее идем в Applications -> Extensions

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

Во вкладке Advanced находим Custom Context

Сохраняем.

Теперь пробуем сделать вызов с этого номера на номер 333.

И нам пришло уведомление.

Вывод: Мы настроили нашу АТС на отправку уведомлений о звонках в телеграм, написали простого бота, который это реализует.

Idea to create channel in the telegram came me from my friend. I have a lot of  useful electronic materials about programming, and he offered me to share them in telegram channel. To create channel is very easy. But share materials manually is very boring and wasting time. That’s why I’ve decided to automate it using mysql and python. First of all I’ve created table in the mysql to store my books there. And then i’ve created my first bot in telegram. Documentation of telegram bots: https://core.telegram.org/bots

Also you can find API documentation of telegram bots here: https://core.telegram.org/bots/api

And than was created channel. You can learn how to create channel from here: https://telegram.wiki/generalfaq/channels

So interesting part is a python code to work with telegram api. You can find many written libraries in internet written in python to work with telegram API. But I wanna show how to write simple script from zero. Table structure:

CREATE TABLE `books` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
`content` longblob,
`author` varchar(120) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`description` text COLLATE utf8mb4_unicode_ci,
`image` blob,
`size` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`year` int(11) unsigned DEFAULT NULL,
`extension` varchar(4) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_type` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_length` int(20) unsigned DEFAULT ‘0’,
`last_modified` int(11) unsigned DEFAULT ‘0’,
`is_shared` tinyint(1) unsigned NOT NULL DEFAULT ‘0’,
PRIMARY KEY (`id`),
UNIQUE KEY `book_download` (`book_download`),
KEY `year` (`year`),
KEY `is_shared` (`is_shared`),
KEY `last_modified` (`last_modified`),
KEY `content_length` (`content_length`),
KEY `content_type` (`content_type`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

So let’s assume that our books are stored in the table already and pending to be shared.

So let’s write our poster class step by step. Required python libraries are requests, pymysql and re. We will use python3. Let’s create project folder and then virtualenv and install required libraries

mkdir telegram_bot
> cd telegram_bot
> virtualenv .py3
> source .py3/bin/activate
> pip install requests pymysql
> touch telegram_bot.py

Now, let’s create our first class

import requests as rq
import pymysql as mysql
import re

class poster:
   _token = "****"
   _url = "https://api.telegram.org/bot"
   _channel_id = "@mychannel"
   _conn = None
   def __init__(self):
      self._url += self._token
      self._conn = mysql.connect(host="localhost", user="user", password="password", db="books", charset="utf8")

   def __exit__(self, exc_type, exc_val, exc_tb):
      self._conn.close()

As you see in example we connect to mysql db on initialization, and close on destroying o object. Now let’s add send_book method:

def send_book(self):
   strsql = """select id, 
                      title, 
                      author, 
                      description, 
                      image, 
                      year, 
                      content,
                      extension
                 from books 
                      limit 2
                order by year desc"""

   cur = self._conn.cursor()
   if cur.execute(strsql):
      for id, title, author, description, image, year, content, extension, in cur:
         self.post_text(description)
         self.post_document(title, extension, author, year, content)
         self.post_image(image, title)

In this method we choose 2 books from database, and then call three other methods in the loop: post_text, post_document, post_image

These methods uses there types of bot API of telegram: sendMessage, sendDocument and sendPhoto

Let’s define next methods:

def post_text(self, description):
   method = self._url + "/sendMessage"
   r = rq.post(method, data={
          "chat_id": channel_id,
          "text": description
       })
   
   if r.status_code != 200:
      raise Exception("post_text error")
def post_photo(self, image, title):
   method = self._url + "/sendPhoto"
   r = rq.post(method, data={
          "chat_id": channel_id,
          "photo": image,
          "caption": title
       })

    if r.status_code != 200:
       raise Exception("post_photo error")
def post_document(self, title, extension, author, year, content):
   method = self._url + "/sendDocument"
   filename = title + "-" + author + "-" + year
   filename = re.sub(r'[^a-zA-Z0-9]+', '', filename)
   filename += "." + extension
   r = rq.post(method, data={
          "chat_id": channel_id,
          "caption": title + ", " + author + ", " + year,
       },
       files={
          "document":(filename, content)
       })
   if r.status_code != 200:
      raise Exception("post_document error")

And last step is to create single script file, import our module and connect this script to cron to share books periodically.

cron.py
-----------------
from telegram_bot import poster

p = poster()
p.send_book()
cron.sh
------------------

#!/bin/bash

cd ~/telegram_bot
source .py3/bin/activate
python cron.py

That’s all 🙂

В одном из приложении сайта на Django описаны две модели Group и Post.

Group — является категорией для постов.
Post — является моделью постов.

Модель Group

class Group(models.Model):

    title = models.CharField(max_length=200, verbose_name='Жанр')

    slug = models.SlugField(max_length=255, unique=True, verbose_name='Параметр')

    description = models.TextField(verbose_name='Содержание')

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = 'Жанр'
        verbose_name_plural = 'Жанры'
        ordering = ('title',)

Модель Post

class Post(models.Model):

    text = models.TextField(verbose_name='Текст поста', help_text='Введите текст поста')
    
    pub_date = models.DateTimeField(auto_now_add=True, verbose_name='Дата публикации')

    group = models.ForeignKey('Group', blank=True, null=True, on_delete=models.SET_NULL,
                              related_name='posts', verbose_name='Группа', help_text='Группа, относительно поста')

    author = models.ForeignKey(User, on_delete=models.CASCADE,
                               related_name='posts', verbose_name='Автор')

    def __str__(self):
        return self.text[:15]

    class Meta:
        verbose_name = 'Пост'
        verbose_name_plural = 'Посты'
        ordering = ('-pub_date', 'author')

Что в моделях нужно тестировать

В обязательном порядке тестами должен быть код:

  • валидация полей моделей,
  • методы по работе с моделями,
  • метаданные полей

Перед тестированием моделей необходимо создать класс группы тестов, который наследуется от класса TaskCase.

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

Далее создаются тестовые записи в таблицах. Данный код описывается в методе setUpClass. Метод указан с декоратором @classmetod.

class PostModelTest(TestCase):

    @classmethod
    def setUpClass(self):
        super().setUpClass()
        self.user = User.objects.create_user(username='auth')
        self.group = Group.objects.create(title='Тестовая группа',
                                          slug='Тестовый слаг',
                                          description='Тестовое описание',)
        self.post = Post.objects.create(author=cls.user,
                                         text='Тестовое описание поста',)

Описание метода setUpClass

self.user = User.objects.create_user(username=’auth’) — создание тестового пользователя
self.group = Group.objects.create(…) — создание «записи» о категории
self.post = Post.objects.create(…) — создание «записи» о посте

Проверка заполнения verbose_name
в модели Post

    def test_title_label(self):
        '''Проверка заполнения verbose_name'''
        field_verboses = {'text': 'Текст поста',
                          'pub_date': 'Дата публикации',
                          'group': 'Группа',
                          'author': 'Автор'}
        for field, expected_value in field_verboses.items():
            with self.subTest(field=field):
                error_name = f'Поле {field} ожидало значение {expected_value}'
                self.assertEqual(
                    self.post._meta.get_field(field).verbose_name,
                    expected_value, error_name)

Описание теста test_title_label

Создается словарь с указанным заполнением полей verbose_name.

1. Запускается цикл перебора элементов словаря
2. В циклической проверке используется метод SubTest (метод subTest() устроен так, что при падении вложенного теста в отчёт будет выведено имя того поля, на котором упал тест)
3. Формирование строки описания ошибки error_name
4. Вызов метода теста assertEqual для сравнения полей поста verbose_name и элементов словаря

Проверка заполнения help_text
в модели Post

    def test_title_help_text(self):
        '''Проверка заполнения help_text'''
        field_help_texts = {'text': 'Введите текст поста',
                            'group': 'Группа, относительно поста'}
        for field, expected_value in field_help_texts.items():
            with self.subTest(field=field):
                error_name = f'Поле {field} ожидало значение {expected_value}'
                self.assertEqual(
                    self.post._meta.get_field(field).help_text,
                    expected_value, error_name)

Описание метода test_title_help_text

Создается словарь с указанным заполнением полей help_text.

1. Запускается цикл перебора элементов словаря
2. В циклической проверке используется метод SubTest
3. Формирование строки описания ошибки error_name
4. Вызов метода теста assertEqual для сравнения полей поста help_text и элементов словаря

Проверка длины вывода метода __str__ Post

    def test_models_have_correct_object_names(self):
        '''Проверка длины __str__ post'''
        error_name = f"Вывод не имеет {settings.LEN_OF_POSTS} символов"
        self.assertEqual(self.post.__str__(),
                         self.post.text[:settings.LEN_OF_POSTS],
                         error_name)

Описание метода test_models_have_correct_object_names

В модели Post используется метод __str__. Он выводит первые 15 символов текста поста. Необходимо проверить корректность вывода.

1. Используется метод asserEqual для сравнения вывода self.post.__str__() и формирование строки из поля text — self.post.text[:settings.LEN_OF_POSTS]
2. Формирование строки ошибки
3. Константа settings.LEN_OF_POSTS указана в файле настроек settings и вверху импортируется, она равна 15

Построение тестов для модели Group

В обязательном порядке тестами должен быть код:

  • валидация полей моделей,
  • методы по работе с моделями,
  • метаданные полей

По аналогии выстраиваются тесты для модели Group.

1. Тест проверяет поле verbose_name у элементов модели
2. Тест проверяет поле help_text у элементов модели
3. Проверяется метод __str__. В данном примере он возвращает заголовок title

По методологии TDD в начале Вы описываете тесты моделей по техническому заданию. Далее описываете сами модели.

Содержание

  1. Введение в тему
  2. Создание get и post запроса
  3. Передача параметров в url
  4. Содержимое ответа response
  5. Бинарное содержимое ответа
  6. Содержимое ответа в json
  7. Необработанное содержимое ответа
  8. Пользовательские заголовки
  9. Более сложные post запросы
  10. Post отправка multipart encoded файла
  11. Коды состояния ответа
  12. Заголовки ответов
  13. Cookies
  14. Редиректы и история
  15. Тайм ауты
  16. Ошибки и исключения

Введение в тему

Модуль python requests – это общепринятый стандарт для работы с запросами по протоколу HTTP.

Этот модуль избавляет Вас от необходимости работать с низкоуровневыми деталями. Работа с запросами становится простой и элегантной.

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

Перед использованием модуля его необходимо установить:

Создание get и post запроса

Сперва необходимо добавить модуль Requests в Ваш код:

Создадим запрос и получим ответ, содержащий страницу и все необходимые данные о ней.


import requests

response = requests.get('https://www.google.ru/')

В переменную response попадает ответ на запрос. Благодаря этому объекту можно использовать любую информацию, относящуюся к этому ответу.

Сделать POST запрос так же очень просто:


import requests

 

response = requests.post('https://www.google.ru/', data = {'foo':3})

Другие виды HTTP запросов, к примеру: PUT, DELETE, и прочих, выполнить ничуть не сложнее:


import requests

 

response = requests.put('https://www.google.ru/', data = {'foo':3})

response = requests.delete('https://www.google.ru/')

response = requests.head('https://www.google.ru/')

response = requests.options('https://www.google.ru/')

Передача параметров в url

Иногда может быть необходимо отправить различные данные вместе с запросом URL. При ручной настройке URL, параметры выглядят как пары ключ=значение после знака «?». Например, https://www.google.ru/search?q=Python. Модуль Requests предоставляет возможность передать эти параметры как словарь, применяя аргумент params. Если вы хотите передать q = Python и foo=’bar’ ресурсу google.ru/search, вы должны использовать следующий код:


import requests

params_dict = {'q':'Python', 'foo':'bar'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.url)

#Вывод:

https://www.google.ru/search?q=Python&foo=bar

Здесь мы видим, что URL был сформирован именно так, как это было задумано.

Пара ключ=значение, где значение равняется None, не будет добавлена к параметрам запроса URL.

Так же есть возможность передавать в запрос список параметров:


import requests

params_dict = {'q':'Python', 'foo':['bar', 'eggs']}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.url)
#Вывод:

https://www.google.ru/search?q=Python&foo=bar&foo=eggs

Содержимое ответа response

Код из предыдущего листинга создаёт объект Response, содержащий ответ сервера на наш запрос. Обратившись к его атрибуту .url можно просмотреть адрес, куда был направлен запрос. Атрибут .text позволяет просмотреть содержимое ответа. Вот как это работает:


import requests

params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.text)
#Вывод:<!doctype html><html lang="ru"><head><meta charset="UTF-8"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png"…

Библиотека автоматически пытается определить кодировку ответа основываясь на его заголовках. Узнать, какую кодировку выбрал модуль, можно следующим образом:


import requests

params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.encoding)
#Вывод:

windows-1251

Можно так же самостоятельно установить кодировку используя атрибут .encoding.


import requests

params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
response.encoding = 'utf-8' # указываем необходимую кодировку вручную
print(response.encoding)
#Вывод:

utf-8

Бинарное содержимое ответа

Существует возможность просмотра ответа в виде байтов:


import requests

params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.content)
#Вывод:

b'<!doctype html><html lang="ru"><head><meta charset="UTF-8"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" …

При передаче со сжатием ответ автоматически декодируется для Вас.

Содержимое ответа в json

Так же в Requests есть встроенная обработка ответов в формате JSON:

import requests
import json

response = requests.get(‘http://api.open-notify.org/astros.json’)
print(json.dumps(response.json(), sort_keys=True, indent=4))
#Вывод:

{

«message»: «success»,

«number»: 10,

«people»: [

{

«craft»: «ISS»,

«name»: «Mark Vande Hei»

},

{

«craft»: «ISS»,

«name»: «Oleg Novitskiy»

},

[/dm_code_snippet]

Если ответ не является JSON, то .json выбросит исключение:


import requests
import json

response = requests.get('https://www.google.ru/search')
print(json.dumps(response.json(), sort_keys=True, indent=4))
#Вывод:

…

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Необработанное содержимое ответа

Если Вам нужно получить доступ к ответу сервера в чистом виде на уровне сокета, обратитесь к атрибуту .raw. Для этого необходимо указать параметр stream=True в запросе. Этот параметр заставляет модуль читать данные по мере их прибытия.


import requests

response = requests.get('https://www.google.ru/', stream=True)
print(response.raw)
print('Q'*10)
print(response.raw.read(15))
#Вывод:

<urllib3.response.HTTPResponse object at 0x000001E368771FA0>

QQQQQQQQQQ

b'x1fx8bx08x00x00x00x00x00x02xffxc5[[sxdb'

Так же можно использовать метод .iter_content. Этот метод итерирует данные потокового ответа и это позволяет избежать чтения содержимого сразу в память для больших ответов. Параметр chunk_size – это количество байтов, которые он должен прочитать в памяти.  Параметр chunk_size можно произвольно менять.


import requests

response = requests.get('https://www.google.ru/', stream=True)
print(response.iter_content)
print('Q'*10)
print([i for i in response.iter_content(chunk_size=256)])
#Вывод:

<bound method Response.iter_content of <Response [200]>>

QQQQQQQQQQ

[b'<!doctype html><html itemscope="" itemtype="http://sche', b'ma.org/WebPage" lang="ru"><head><meta content=…

response.iter_content будет автоматически декодировать сжатый ответ. Response.raw — чистый набор байтов, неизменённое содержимое ответа.

Пользовательские заголовки

Если необходимо установить заголовки в HTTP запросе, передайте словарь с ними в параметр headers. Значения заголовка должны быть типа string, bytestring или unicode. Имена заголовков не чувствительны к регистру символов.
В следующем примере мы устанавливаем информацию об используемом браузере:


import requests

response = requests.get('https://www.google.ru/', headers={'user-agent': 'unknown_browser'})
print(response.request.headers)
# Вывод:

{'user-agent': 'unknown_browser', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

Более сложные post запросы

Существует способ отправить данные так, будто это результат заполнения формы на сайте:


import requests

response = requests.post('https://httpbin.org/post', data={'foo': 'bar'})
print(response.text)
# Вывод:

{

"args": {},

"data": "",

"files": {},

"form": {

"foo": "bar"

},

"headers": {

…

Параметр data может иметь произвольное количество значений для каждого ключа. Для этого необходимо указать data в формате кортежа, либо в виде dict со списками значений.


import requests

response = requests.post('https://httpbin.org/post', data={'foo':['bar', 'eggs']})
print(response.json()['form'])
print('|'*10)
response = requests.post('https://httpbin.org/post', data=[('foo', 'bar'), ('foo', 'eggs')])
print(response.json()['form'])
# Вывод:

{'foo': ['bar', 'eggs']}

||||||||||

{'foo': ['bar', 'eggs']}

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


import requests

response = requests.post('https://httpbin.org/post', data={'foo': 'bar'})
print('URL:', response.request.url)
print('Body:', response.request.body)
print('-' * 10)
response = requests.post('https://httpbin.org/post', data='foo=bar')
print('URL:', response.request.url)
print('Body:', response.request.body)
# Вывод:

URL: https://httpbin.org/post

URL: https://httpbin.org/post

Body: foo=bar

----------

URL: https://httpbin.org/post

Body: foo=bar

Post отправка multipart encoded файла

Запросы упрощают загрузку файлов с многостраничным кодированием (Multipart-Encoded):


import requests

url = 'https://httpbin.org/post'

files = {'file': open('report.xls', 'rb')}

response = requests.post(url, files=files)

print(response.text)

# Вывод:

{

...

"files": {

"file": "<censored...binary...data>"

},

...

}

Вы можете установить имя файла, content_type и заголовки в явном виде:


import requests

url = 'https://httpbin.org/post'

files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

response = requests.post(url, files=files)

print(response.text)

# Вывод:

{

...

"files": {

"file": "<censored...binary...data>"

},

...

}

Можете отправить строки, которые будут приняты в виде файлов:


import requests

url = 'https://httpbin.org/post'

files = {'file': ('report.csv', 'some,data,to,sendnanother,row,to,sendn')}

response = requests.post(url, files=files)

print(response.text)

# Вывод:

{

...

"files": {

"file": "some,data,to,send\nanother,row,to,send\n"

},

...

}

Коды состояния ответа

Возможно, наиболее важные данные (первые – уж точно), которые вы можете получить, используя библиотеку requests, является код состояния ответа.

Так, 200 статус означает, что запрос выполнен успешно, тогда как 404 статус означает, что ресурс не найден.

Важнее всего то, с какой цифры начинается код состояния:

  • 1XX — информация
  • 2XX — успешно
  • 3XX — перенаправление
  • 4XX — ошибка клиента (ошибка на нашей стороне)
  • 5XX — ошибка сервера (самые страшные коды для разработчика)

Используя атрибут .status_code можно получить статус, который вернул сервер:


import requests

response = requests.get('https://www.google.ru/')
print(response.status_code)

# Вывод:

200

.status_code вернул 200 — это означает, что запрос успешно выполнен и сервер вернул запрашиваемые данные.

При желании, такую информацию можно применить в Вашем Пайтон скрипте для принятия решений:


import requests

response = requests.get('https://www.google.ru/')
if response.status_code == 200:    print('Успех!')elif response.status_code == 404:    print('Страница куда-то пропала…')

# Вывод:

Успех!

Если код состояния response равен 200, то скрипт выведет «Успех!», но, если он равен 404, то скрипт вернёт «Страница куда-то пропала…».

Если применить модуль Response в условном выражении и проверить логическое значение его экземпляра (if response) то он продемонстрирует значение True, если код ответа находится в диапазоне между 200 и 400, и False во всех остальных случаях.

Упростим код из предыдущего примера:


import requests

response = requests.get('https://www.google.ru/fake/')
if response:
print('Успех!')
else:
print('Хьюстон, у нас проблемы!')
# Вывод:

Хьюстон, у нас проблемы!

Данный способ не проверяет, что код состояния равен именно 200.
Причиной этого является то, что response с кодом в диапазоне от 200 до 400, такие как 204 и 304, тоже являются успешными, ведь они возвращают обрабатываемый ответ. Следовательно, этот подход делит все запросы на успешные и неуспешные – не более того. Во многих случаях Вам потребуется более детальная обработка кодов состояния запроса.

Вы можете вызвать exception, если requests.get был неудачным. Такую конструкцию можно создать вызвав .raise_for_status() используя конструкцию try- except:


import requests

from requests.exceptions import HTTPError

for url in ['https://www.google.ru/', 'https://www.google.ru/invalid']:
try:
response = requests.get(url)

response.raise_for_status()
except HTTPError:
print(f'Возникла ошибка HTTP: {HTTPError}')
except Exception as err:
print(f'Возникла непредвиденная ошибка: {err}')
else:
print('Успех!')
# Вывод:

Успех!

Возникла ошибка HTTP: <class 'requests.exceptions.HTTPError'>

Заголовки ответов

Мы можем просматривать заголовки ответа сервера:


import requests

response = requests.get('https://www.google.ru/')
print(response.headers)
# Вывод:

{'Date': 'Sun, 27 Jun 2021 13:43:17 GMT', 'Expires': '-1', 'Cache-Control': 'private, max-age=0', 'Content-Type': 'text/html; charset=windows-1251', 'P3P': 'CP="This is not a P3P policy! See g.co/p3phelp for more info."', 'Content-Encoding': 'gzip', 'Server': 'gws', 'X-XSS-Protection': '0', 'X-Frame-Options': …

Cookies

Можно просмотреть файлы cookie, которые сервер отправляет вам обратно с помощью атрибута .cookies. Запросы также позволяют отправлять свои собственные cookie-файлы.

Чтобы добавить куки в запрос, Вы должны использовать dict, переданный в параметр cookie.


import requests

url = 'https://www.google.ru/'
headers = {'user-agent': 'your-own-user-agent/0.0.1'}
cookies = {'visit-month': 'February'}

response = requests.get(url, headers=headers, cookies=cookies)

print(response.request.headers)
# Вывод:

{'user-agent': 'your-own-user-agent/0.0.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'visit-month=February'}

Редиректы и история

По умолчанию модуль Requests выполняет редиректы для всех HTTP глаголов, кроме HEAD.

Существует возможность использовать параметр history объекта Response, чтобы отслеживать редиректы.

Например, GitHub перенаправляет все запросы HTTP на HTTPS:


import requests

response = requests.get('https://www.google.ru/')
print(response.url)
print(response.status_code)
print(response.history)
# Вывод:

https://www.google.ru/

200

[]

Тайм ауты

Так же легко можно управлять тем, сколько программа будет ждать возврат response. Время ожидания задаётся параметром timeout. Это очень важный параметр, так как, если его не использовать, написанный Вами скрипт может «зависнуть» в вечном ожидании ответа от сервера. Используем предыдущий код:


import requests

response = requests.get(‘https://www.google.ru/’, timeout=0.001)
print(response.url)
print(response.status_code)
print(response.history)
# Вывод:

raise ConnectTimeout(e, request=request)

requests.exceptions.ConnectTimeout: HTTPSConnectionPool(host=’www.google.ru’, port=443): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x000001E331681C70>, ‘Connection to www.google.ru timed out. (connect timeout=0.001)’))

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

Ошибки и исключения

Если возникнет непредвиденная ситуация – ошибка соединения, модуль Requests выбросит эксепшн ConnectionError.

response.raise_for_status() возвращает объект HTTPError, если в процессе произошла ошибка. Его применяют для отладки модуля и, поэтому, он является неотъемлемой частью запросов Python.

Если выйдет время запроса, вызывается исключение Timeout. Если слишком много перенаправлений, то появится исключение TooManyRedirects.


Понравилась статья? Поделить с друзьями:
  • Post preflight cors error
  • Post logs python ошибка
  • Post error при запуске компьютера
  • Post error pause что это
  • Post error occurs что это такое