Парсинг с: Парсинг данных онлайн-магазина на C#

Парсинг сайта с применением авторизации

Время прочтения: 5 мин.

Любой, кто когда-либо пытался парсить сайты на python начинал с простого запроса «get» библиотеки «requests». Запрос «get» выгружает html код страницы, который можно обрабатывать под свои нужды.

Но иногда данные доступны только после авторизации на ресурсе. В этом посте я покажу, как можно подключаться, используя логин-пароль и библиотеку «requests».

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

Возьмем сайт https://ivi.ru/ и попытаемся залогиниться.

Для авторизации требуется ввести email и пароль. В библиотеке requests есть метод «POST», с помощью которого реализуются отправки данных на сервер.

Общий вид использования метода: «requests.post(url, headers, data)». «url» ссылка на ресурс, «headers» заголовки запроса, «data» данные запроса, которые мы будем передавать.

Импорт, авторизация и исходные параметры

Устанавливаем библиотеку:

pip install requests

Прежде всего, нужно узнать, откуда брать данные «headers» и «data». Для этого запустим инструмент разработчика. Переходим во вкладку СЕТЬ и обновляем страницу. Здесь видим все активности сети.

На главной странице сайта входим в профиль. Открывается форма авторизации, вводим логин-пароль и нажимаем кнопку ВОЙТИ. Ищем нашу ссылку.

Чтобы быстрее находить нужную строку в отображении полей нужно добавить поле «Method» и по нему отсортировать столбец. Данные на авторизацию отправляются в «POST» запросах.

Находим строку v5/

Смотрим информацию по этой строке

Во вкладке «headers» находим «General» в нем возьмем «url», в «Request Headers» нас интересует только «User-Agent», который пропишем в «headers», в «Form Data» данные для запроса «data».

import requests
url = 'https://api.ivi.ru/mobileapi/user/login/ivi/v5/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'
}
data = {
    'email': '[email protected]',
    'password': 'testTEST123',
    'device': 'OS X Chrome v.89.0.4389.90 3a7a0',
    'app_version': '870'
}

Создаем сессию, она будет держать наше соединение с сайтом, и мы сможем с ним работать.

session = requests.Session()
session.headers.update(headers)
response =  session.post(url, data=data)

Смотрим статус ответа

response
<Response [200]>

Ответ 200 означает успешный ответ от сервера.

Посмотрим, что возвратил наш запрос

response.json()
{'result': {'id': 1852143028,
  'gender': 0,
  'birthday': None,
  'session': 'ea85a1001852143028_1634027028-388944532m_RoMwwuIDe_NMcbmefXmw',
  'expiration': '2021-10-12T08:23:48Z',
  'firstname': None,
  'lastname': None,
  'subscribed': True,
  'origin_app_version': 870,
  'actual_app_version': 870,
  'payment_credentials': {},
  'email': 'test@yandex. ru',
  'email_real': 1,
  'msisdn': '',
  'confirmed': 1,
  'storageless': False,
  'is_debug': False,
  'children': [],
  'basic': '0.0000',
  'bonus': '0.0000'}}

Здесь важная строка «session», которая указывает на наш номер сессии. Дальше в примере будет видно, что, если бы мы не создали сессию, изменить данные нам бы не удалось.

Попробуем поменять данные профиля. Нажимаем на кнопку редактировать и меняем имя.

Ищем в инструменте разработчика нашу строку. Чтобы не было много записей, можно сразу же после нажатия кнопки сохранить остановить загрузку страницы, «POST» запрос на изменение будет идти первым, только после этого происходит загрузка страницы с обновленными данными.

Записываем «url» и копируем «data». Необходимо обратить внимание на строку «session», где нужно передать наш номер сессии. Номер берем из ответа сервера.

url_change_nick = 'https://api.ivi.ru/mobileapi/user/info/v5/'
session_id = response.json()['result']['session']
data = {
'nick': 'test-test',
'kind': 'adult',
'lang': 'ru',
'tz': '+03:00',
'app_version': '870',
'session': session_id
}
response =  session. post(url_change_nick, data=data)

Чтобы удостовериться в работе нашего кода обновляем страницу в браузере.

Наш код успешно сработал.

Использование учетных данных WINDOWS

Также бывают редкие случаи, когда нужно использовать логин-пароль от учетной записи Windows. Для этого можно использовать библиотеку «requests-negotiate-sspi». Она становится особенно полезной, когда часто меняется пароль от учетной записи.

Устанавливаем и импортируем библиотеку, нам нужен метод «HttpNegotiateAuth»

pip install requests_negotiate_sspi
from requests_negotiate_sspi import HttpNegotiateAuth

Повторяем все, что делали выше: прописываем «headers», заполняем «data» и поднимаем сессию. Попробуем получить дату и время сервера.

Вначале сделаем запрос без передачи данных авторизации

xml_request = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www. w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetServerDateTime xmlns="http://Server/" />
  </soap:Body>
</soap:Envelope>'''
headers = {
    'Host': host_name,
    'Content-Type': 'text/xml; charset=utf-8',
    'Content-Length': str(len(xml_request))
}
session.headers = headers
response = session.post('http://' + host_name + '/ServerService.asmx?WSDL', data=xml_request)
response
<Response [401]>

Посмотрим текст ответа

response.text
<title>401 - Unauthorized: Access is denied due to invalid credentials.</title>

Как мы видим ошибка авторизации.

Повторяем запрос с использованием «HttpNegotiateAuth»

response = session.post('http://' + host_name + '/ServerService.asmx?WSDL', auth=HttpNegotiateAuth(), data=xml_request)
response.text
<curDateTime>44298.576980902777</curDateTime>

Ответ на запрос даты и времени сервера получен успешно.

Sessions позволяет вам использовать requests более эффективно и решать проблемы с подключением к аккаунту, ускорять работу выполнения запросов и исключать блокировку при ограничении количества соединений.

Парсинг с помощью Python. Урок 4

Продолжаем изучать парсинг на Python. В прошлом уроке мы познакомились с библиотекой Scrapy и попробовали с ее помощью собрать информацию о книгах из одного раздела онлайн-магазина. А сегодня мы соберем информацию обо всех книгах. Сделаем это с помощью специального класса — crawlspider. Он позволяет легко и быстро искать ссылки на странице и переходить по ним.

Съемка и монтаж: Глеб Лиманский

Откроем проект, с которым работали на прошлом уроке и создадим еще одного паука. Для этого переходим в папку spiders и создаем новый файл с расширением «py». Назовем его «all_books_spider. py».

Импорт библиотек

Как и в прошлый раз, мы начинаем наш проект с импорта библиотеки.

Пишем: import scrapy

Кроме этого, нам нужно импортировать библиотеки, которые будут собирать ссылки со страницы. 

Пишем:

from scrapy.spiders import CrawlSpider, Rule

from scrapy.linkextractors import LinkExtractor

Создаем класс

Как и в прошлом уроке, создаем класс, в который запишем правила скрейпинга. Только на этот раз в скобках вместо scrapy.Spider мы напишем CrawlSpider: class BookSpider(CrawlSpider).

Даем пауку имя: name = ‘all_books’. Задаем начальную ссылку — это будет стартовая страница онлайн-магазина: start_urls = [‘https://book24.ru/’].

Сбор ссылок

Теперь нужно написать правило сбора ссылок. 

Пишем: rules =. Cоздаем кортеж. Кортеж похож на список, отличие в том, что список — изменяемый тип данных, а кортеж нет. 

Чтобы понять, какое правило задать, откроем сайт. Мы видим несколько категорий с книгами. Можно переходить по ним поэтапно, собирая информацию о каждой книжке на каждой странице каждого раздела. И так пройтись по всем разделам. Ссылку для каждого перехода нам бы пришлось задавать с помощью css-селектора, как мы это делали в прошлый раз. Класс Crawl spider позволяет выполнить задачу проще и быстрее.

Давайте посмотрим на ссылку одного из разделов. Например, художественная литература. 

Скопируем ссылку и посмотрим на нее. Чтобы эта строка не влияла на код, закомментируем ее, для этого нужно написать в начало решетку: #https://book24.ru/catalog/fiction-1592/.

Мы видим, что после основного названия сайта (https://book24.ru) есть слово «catalog», а затем конкретный раздел каталога: fiction. Если мы зайдем в любой другой раздел, в ссылке тоже будет слово «catalog». Значит, нам нужно создать правило, чтобы паук проходился по всем ссылкам, в которых есть «catalog». Так мы соберем все разделы. 

Теперь зайдем на страницу с книгой. Скопируем ссылку и посмотрим на нее. #https://book24.ru/product/portret-doriana-greya-1597309/.

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

Запишем наше правило: Rule(LinkExtractor(allow=’catalog’)). Команда allow говорит, чтобы паук перешел по всем ссылкам, в которых есть слово «catalog». С помощью deny мы могли бы задать, по ссылкам с каким словом переходить не нужно. 

Вторым правилом зададим переход по страницам книг, то есть ссылкам со словом «product»: Rule(LinkExtractor(allow=’product’).

За то, что паук делает на странице, отвечает callback. Ему мы передадим функцию parse_items, в которой будет лежать информация, что именно нужно собрать со страницы: Rule(LinkExtractor(allow=’product’), callback=’parse_items’)

Мы получили два правила. Первое говорит пауку, что нужно пройти по всем ссылкам со словом «catalog», после этого включается второе правило, которое говорит переходить по ссылкам со словом «product» и собирать нужную информацию.  

Функция

В прошлом уроке первую созданную функцию мы называли parse. Работая с классом CrawlSpider, нельзя использовать это название. Иначе код будет работать некорректно. Это важно помнить. Поэтому мы назвали нашу функцию parse_items. Как собирать информацию со страницы книги, мы подробно разбирали на прошлом уроке. 

Напишем ключевое слово yield и создадим словарь. Собирать необходимые нам элементы будем с помощью css-селекторов. 

Путь к названию и количеству покупок скопируем из предыдущего паука.

‘name’: response.css(‘h2.product-detail-page__title::text’).get().strip(),

‘buy’: response.css(‘p.product-detail-page__purchased-text::text’).get().split()[1], 

Чтобы полученный датасет был хорошо структурирован, соберем информацию обо всех разделах, которым принадлежит книга. Они как матрешка вкладываются друг в друга. Для примера перейдем в раздел «художественная литература» → «проза» → «историческая проза» и откроем страницу с книгой.

Scrapy Shell

Чтобы собрать информацию об этих разделах, перейдем в scrapy shell. Для этого наберем в терминале команду scrapy shell.

После этого передадим команде fetch страницу книги: fetch(‘https://book24.ru/product/odin-den-v-drevnem-mire-zapiski-puteshestvennika-vo-vremeni-6024803/’).

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

Посмотрим, где лежат названия разделов. Нажмем правой кнопкой мыши, выберем «просмотреть код». Мы видим, что название раздела лежит в теге span, который вложен в тег a. 

Обратимся к нему с помощью уже известной команды response.css. Если какой-то тег вложен в другой, мы можем дописать его через пробел. Мы дописываем тег span. Слово text поможет увидеть, что именно находится в css-селекторе, к которому мы обращаемся: response.css(‘a.breadcrumbs__link.smartLink span::text’) 

Мы получили на выход список css-selector, в которых видим нужные слова: 

  • Главная
  • Художественная литература
  • Проза
  • Классическая зарубежная литература

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

Напишем: response.css(‘a.breadcrumbs__link.smartLink span::text’)[1]. На выход мы получим нужный css-селектор. 

Чтобы выбрать содержание селектора, допишем get(): response.css(‘a.breadcrumbs__link.smartLink span::text’)[1].get().

Пробелы в строке по бокам уберем с помощью известного метода strip(): response.css(‘a.breadcrumbs__link.smartLink span::text’)[1].get().strip().

Мы получили нужный элемент, добавим его в словарь. Ключ назовем «first_type».

Чтобы получить следующий раздел, к которому относится книга, обратимся ко второму элементу списка: response.css(‘a.breadcrumbs__link.smartLink span::text’)[2].get().strip()

Назовем ключ «second_type»: ‘second_type’: response.css(‘a.breadcrumbs__link.smartLink span::text’)[2].get().strip(). И так же достанем третий последний раздел.

Мы указали все элементы, которые нам нужно достать. Выходим из ScrapyShell — control+D

Запись в файл

Нам даже не нужно прописывать переход по страницам, потому что паук сам соберет все ссылки на сайте, которые соответствуют нашему правилу. Сохраняем файл и можем запускать паука. Результат запишем в csv-файл all_books.csv. Напишем команду в терминале: scrapy crawl all_books -O all_books.csv

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

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

Анализ определения и значения — Merriam-Webster

1 из 2

ˈpärs

преимущественно британский ˈpärz

переходный глагол

1

а

: разделить (предложение) на грамматические части и определить части и их отношения друг к другу

б

: грамматически описать (слово), указав часть речи и объяснив словоизменение (см. значение словоизменения 2а) и синтаксические отношения

2

: внимательно изучить : критически проанализировать

возникли проблемы синтаксический анализ … объяснения уменьшения доли рынка — Р. S. Anson

непереходный глагол

1

: дать грамматическое описание слова или группы слов сед

разбор

2 из 2

: товар или экземпляр разбора

Знаете ли вы?

Если синтаксический анализ вызывает образы начальной школы и изучения частей речи, вы сделали домашнее задание по этому слову. Parse происходит от первого элемента латинского термина, обозначающего «часть речи», pars orationis . Это старое слово, которое использовалось по крайней мере с середины 1500-х годов, но только в конце 18-го века синтаксический анализ перешел в расширенное, не связанное с грамматикой значение слова «тщательно изучить; критически проанализировать». Помните об этом расширенном смысле, и вы действительно будете во главе класса.

Примеры предложений

Глагол Студентам было предложено разобрать предложения. Экономисты проанализировал

данных переписи.

Последние примеры в Интернете

К ее чести, Тремблей настаивает на том, чтобы представить женщин чероки во всей их сложности, даже если это приводит к парадоксам, что фильм не готов разобрать . — Питер Дебрюге, 9 лет.0033 Разнообразие , 11 марта 2023 г. И несколько источников молочных продуктов было трудно анализировать . — Али Фрэнсис, Приятного аппетита , 16 сентября 2022 г. Что-то настолько простое для понимания людьми, как моя ссылка на Kleenex, может быть очень трудной для ИИ

разбора . — Майк Фейбус, USA TODAY , 14 апреля 2023 г. Теперь результаты тестов, подобных этому, трудно разбор . — Джеймс Винсент, The Verge , 24 марта 2023 г. Глобальный деловой и финансовый мир будет анализировать каждое слово заявления ФРС и пресс-конференции Пауэлла после заседания, чтобы найти ответы на два надвигающихся вопроса: насколько чиновники обеспокоены стабильностью банков? — Ларри Эдельман, BostonGlobe. com , 21 марта 2023 г. Трудно понять, насколько реалистичны опасения Аакервика по поводу безопасности байкеров.0033 разбор . — Пол Робертс,
Anchorage Daily News
, 17 февраля 2023 г. Другие осциллографы могут анализировать атмосферы газовых гигантов по проходящему звездному свету, но атмосферы небольших каменистых экзопланет представляют гораздо более сложную задачу; исследователи надеются, что JWST поможет взломать его. — Сотрудники Byscience News, science.org , 19 января 2023 г. Инвесторы будут проанализируйте протокол декабрьского собрания политиков, опубликованный позже в среду, чтобы пролить свет на перспективы центрального банка. — Рид Пикерт, Fortune , 4 января 2023 г.

Что касается людей европейского происхождения, у исследователей есть информация из достаточного количества геномов, чтобы легче анализировать , какие генетические варианты редки и могут быть патогенными, а какие нет. — Эндрю Джозеф, STAT , 12 апреля 2023 г. В надежде раскрыть секреты этих сохранившихся свитков профессор Университета Кентукки Брент Силз запустил программу Vesuvius Challenge, в которой людей со всего мира просят помочь анализирует на основе данных, собранных Силзом и его командой. — Тим Ньюкомб, Popular Mechanics , 20 марта 2023 г. Обычно управляемые искусственным интеллектом системы периферийных вычислений анализируют производственных данных в источнике и почти мгновенно вносят крошечные изменения, такие как регулировка нагрузки электрического тока в сварочных роботах или силы, прикладываемой механическим прессом. — Ангус Лотен, 9 лет.0033 WSJ , 3 мая 2021 г. Чтобы получить сильную подсказку, проанализируйте это 23-страничное письмо. — Джефф Колвин, Fortune , 7 октября 2020 г. Главный соперник Круза в сфере роботакси, компания Waymo, не пожелала комментировать последние данные CPUC, но было еще много парсинга . — Эндрю Дж. Хокинс, The Verge , 31 января 2023 г. В школе ребенок с дислексией будет с трудом узнавать слова и слова.0033 разобрать предложения. — Элизабет Престон, Discover Magazine , 8 августа 2011 г. Судебный процесс также сопровождался юридическим конфликтом из-за трудного для понимания уголовного закона штата Нью-Йорк, который предписывает стандарты, которым прокуроры должны соответствовать, чтобы добиться осуждения корпораций по уголовным делам. — Кевин Маккой, USA TODAY , 6 декабря 2022 г. Игра была анонсирована в прошлом месяце, и очень короткий тизер показал труднодоступные места. 0033 анализирует сцены с большим количеством осторожной ходьбы вправо и 3D-участком мотоцикла. — Кайл Орланд, Ars Technica , 9 июня 2022 г. Узнать больше

Эти примеры программно скомпилированы из различных онлайн-источников, чтобы проиллюстрировать текущее использование слова «анализ». Любые мнения, выраженные в примерах, не отражают точку зрения Merriam-Webster или ее редакторов. Отправьте нам отзыв об этих примерах.

История слов

Этимология

Глагол и существительное

Латинский pars orationis часть речи

Первое известное употребление

Глагол

около 1568, в значении, определенном в переходном смысле 1a

Существительное

1963, в значении, определенном выше 9 0003

Путешественник во времени

Первое известное использование синтаксического анализа было около 1568 г.

Другие слова того же года

Подкаст

Музыкальная тема Джошуа Стэмпера © 2006 New Jerusalem Music/ASCAP

Получайте Слово дня на свой почтовый ящик!

Словарные статьи рядом с

разбором

Парри пиньон

разобрать

парсек

Посмотреть другие записи поблизости 

Процитировать эту запись

Стиль

MLAChicagoAPAMMercriam-Webster

«Разбор». Словарь Merriam-Webster.com , Merriam-Webster, https://www.merriam-webster.com/dictionary/parse. Доступ 13 мая. 2023.

Копировать цитирование

Детское определение

разбор

глагол

ˈpärs,

ˈpärz

1

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

Еще от Merriam-Webster на тему

parse

Тезаурус: Все синонимы и антонимы к слову parse

Английский: Перевод parse для говорящих на испанском языке

90 002 Britannica English: Перевод разбор для говорящих на арабском языке

Последнее обновление: — Обновлены примеры предложений

Подпишитесь на крупнейший словарь Америки и получите тысячи дополнительных определений и расширенный поиск без рекламы!

Merriam-Webster без сокращений

Синтаксический анализ Определение и значение | Словарь.

com 9
  • Похожие материалы

    Сохрани это слово!


    сущ.

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

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

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

    ВИКТОРИНА

    МОЖЕТЕ ЛИ ВЫ ОТВЕЧАТЬ НА ЭТИ ОБЫЧНЫЕ ГРАММАТИЧЕСКИЕ СПОРЫ?

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

    Вопрос 1 из 7

    Какое предложение правильное?

    Происхождение синтаксического анализа

    pars(e) + -ing 1

    Слова рядом с синтаксическим анализом

    синтаксический анализатор, парша, парсифаль, экономный, экономный, синтаксический анализ, промежуточные части, петрушка, семейство петрушки, петрушка папоротник, петрушка пирс

    Dictionary.com Полный текст На основе Random House Unabridged Dictionary, © Random House, Inc. 2023

    Слова, относящиеся к синтаксическому анализу

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

    Как использовать синтаксический анализ в предложении

    • Хотя драфт-класс 2021 года выглядит лучше, снова будет сложно проанализировать талант, особенно во время баскетбольного сезона в колледже, который будет полон скремблирования и отмен.

      Межсезонье НБА в обычное время — это безумие. В этом году? Пристегнитесь.|Джерри Брюэр|19 ноября 2020 г.|Washington Post

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

      Научная связь между вакцинами против COVID от Pfizer и Moderna|Сай Мукерджи|12 ноября 2020 г.|Fortune

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

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

      Google подтверждает, что не индексирует отрывки отдельно|Барри Шварц|20 октября 2020 г.|Search Engine Land

    • Майя Шрикришнан проанализировала некоторые из недавних скандалов и проблем в школе, а также запись Варгаса на доске .

      Утренний отчет: проблема ограничения роста, о которой никто не говорит|Голос Сан-Диего|20 октября 2020 г.|Голос Сан-Диего

    • Разногласия будут сосредоточены на правильном и неправильном, а не на разборе юридического языка.

      Бюджетная волокита душит добрых самаритян|Филип К. Ховард|27 декабря 2014|DAILY BEAST

    • Хотя идея анализа смысла хип-хопа нова, связь между музыкой и психическим здоровьем хорошо известна .

      Психология хип-хопа: использование музыки для борьбы с психическими заболеваниями|Шарлотта Литтон|17 ноября 2014 г.|DAILY BEAST

    • Когда их переписка была наконец раскрыта, ее нужно было тщательно проанализировать.

      Кровь и война: суровая правда о «сапогах на земле»|Клайв Ирвинг|22 сентября 2014 г.|DAILY BEAST

    • Итак, большое жюри заседает в округе Сент-Луис, собирая показания и анализируя улики.

      Вопрос округа Сент-Луис: могут ли белые сопереживать чернокожим?|Салли Кон|23 августа 2014 г.

  • Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *