{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python для сбора данных\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "### Web-scraping\n", "\n", "Мы уже немного познакомились со структурой html-файлов, теперь попробуем выгрузить информацию из реальной страницы, а точнее, с сайта [nplus1.ru](https://nplus1.ru/). Наша задача: выгрузить недавние новости в датафрейм pandas, чтобы потом сохранить все в файл Excel.\n", "\n", "Сначала сгрузим весь html-код страницы и сохраним его в отдельную переменную. Для этого нам понадобится библиотека `requests`. Импортируем ее:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import requests" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сохраним ссылку на главную страницу сайта в переменную `url` для удобства и выгрузим страницу. Разумеется, это будет работать при подключении к интернету. Если соединение будет отключено, Python выдаст `NewConnectionError`." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "url = \"https://nplus1.ru/\"\n", "page = requests.get(url)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если мы просто посмотрим на объект, мы ничего особенного не увидим:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "page" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Объект `page` имеет тип `Response` и скрыт от наших глаз. Однако при его вызове мы видим число 200 – это код результата, который означает, что страница благополучно загружена." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "У объекта типа `Response` есть атрибут `.text`, в котором хранится исходный код страницы, который мы можем посмотреть, нажав *Ctrl+U* в Chrome:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "page.text" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Результат выше – это обычная строка, тип *string*. Выполнять поиск по такой строке неудобно, поэтому загрузим из модуля `bs4` функцию `BeautifulSoup()`, которая позволит преобразовать эту строку в объект, который позволяет выполнять поиск по тегам." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from bs4 import BeautifulSoup\n", "soup = BeautifulSoup(page.text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если код выше выдает ошибку (зависит от версии `bs4`), можно указать парсер, который необходимо использовать, явно:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "soup = BeautifulSoup(page.text, 'lxml') #lxml" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы сгрузить все новости с главной страницы сайта, нужно собрать все ссылки на страницы с этими новостями. Ссылки в html-файле всегда заключены в тэг `` и имеют атрибут `href`. Посмотрим на кусочки кода, соответствующие всем ссылкам на главной странице сайта:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#\n", "/\n", "#\n", "#\n", "/rubric/astronomy\n", "/rubric/physics\n", "/rubric/biology\n", "/rubric/robots-drones\n", "/theme/explainatorium\n", "/theme/bookshelf\n", "/theme/Courses\n", "/theme/coronavirus-history\n", "/\n", "#\n", "/rubric/astronomy\n", "/rubric/physics\n", "/rubric/biology\n", "/rubric/robots-drones\n", "#\n", "/theme/explainatorium\n", "/theme/bookshelf\n", "/theme/Courses\n", "/theme/coronavirus-history\n", "https://nplus1.ru/blog/2020/04/17/how-music-works\n", "https://nplus1.ru/blog/2020/04/17/how-music-works\n", "https://nplus1.ru/blog/2020/04/17/nudity-censorship\n", "https://nplus1.ru/blog/2020/04/16/stories-of-surgery-for-broken-hearts\n", "https://nplus1.ru/material/2020/04/08/coronarumors\n", "https://nplus1.ru/blog/2020/04/13/ancient-greece-from-prehistoric-to-hellenistic-tim\n", "https://nplus1.ru/blog/2020/04/10/guestmixIvanZoloto\n", "https://nplus1.ru/blog/2020/04/10/the-nature-and-necessity-of-bees\n", "https://nplus1.ru/blog/2020/04/07/troubled-oculudentavis\n", "https://nplus1.ru/blog/2020/04/06/maps-of-meaning\n", "https://nplus1.ru/material/2020/04/08/coronarumors\n", "/news/2020/04/27/venus-atmosphere-tidal-waves\n", "/news/2020/04/27/zumwalt\n", "/news/2020/04/27/starship-pressure-passed\n", "/news/2020/04/27/e-fan-x\n", "/news/2020/04/25/hyperphagia-neurons\n", "/news/2020/04/25/dna-pocket\n", "/news/2020/04/25/moon-landing-spray\n", "/material/2020/04/25/on-montreal\n", "/rubric/ecology\n", "/news/2020/04/25/thermogalvanic-hydrogel-cooling\n", "/news/2020/04/24/30-years-hubble\n", "/news/2020/04/24/feline-grimace-scale\n", "/news/2020/04/24/supermassive-black-hole-escape-star\n", "/news/2020/04/24/adobe\n", "/news/2020/04/24/broken-hearts\n", "/blog/2020/04/24/kronhaus2\n", "/blog/2020/04/15/women-health-animation\n", "/news/2020/04/24/00s-taxi\n", "/rubric/partners\n", "/material/2020/04/23/every-you-every-me\n", "/rubric/psychology\n", "/news/2020/04/24/cold-sweet\n", "/news/2020/04/24/avian\n", "/news/2020/04/24/kentaurs-interstellar\n", "/news/2020/04/24/ocean-macroplastic-finding\n", "/news/2020/04/24/smartwatch\n", "/news/2020/04/24/antarctic-calyptocephalella\n", "/blog/2020/04/24/to-stop-an-epidemic\n", "/blog/2020/04/23/atlas\n", "/material/2020/04/22/antique-masks\n", "/rubric/history\n", "/theme/abc-archeology\n", "/material/2020/04/21/kn-surfaces\n", "/rubric/biology\n", "/theme/bellezza\n", "/news/2020/04/23/underwater-quantum-communication\n", "/news/2020/04/21/self-adapt-PVDF\n", "/news/2020/04/27/venus-atmosphere-tidal-waves\n", "/material/2020/04/22/coffee-aroma\n", "/news/2020/04/25/thermogalvanic-hydrogel-cooling\n", "/news/2020/04/25/hyperphagia-neurons\n", "/news/2020/04/22/carbon-nanothread-bundle\n", "/news/2020/04/21/model-based-learning\n", "/news/2020/04/23/gw-190412-ligo\n", "/news/2020/04/21/digital-embryo\n", "https://nplus1.ru/blog/2020/04/17/how-music-works\n", "https://nplus1.ru/blog/2020/04/17/how-music-works\n", "https://nplus1.ru/blog/2020/04/17/nudity-censorship\n", "https://nplus1.ru/blog/2020/04/16/stories-of-surgery-for-broken-hearts\n", "https://nplus1.ru/material/2020/04/08/coronarumors\n", "https://nplus1.ru/blog/2020/04/13/ancient-greece-from-prehistoric-to-hellenistic-tim\n", "https://nplus1.ru/blog/2020/04/10/guestmixIvanZoloto\n", "https://nplus1.ru/blog/2020/04/10/the-nature-and-necessity-of-bees\n", "https://nplus1.ru/blog/2020/04/07/troubled-oculudentavis\n", "https://nplus1.ru/blog/2020/04/06/maps-of-meaning\n", "https://nplus1.ru/material/2020/04/08/coronarumors\n", "/\n", "/about\n", "/adv\n", "/rules\n", "/vacancy\n", "/difficult\n", "https://nplus1.ru/personal-data-policy\n", "#\n", "https://t.me/nplusone\n", "http://vk.com/nplusone\n", "https://www.facebook.com/nplusone\n", "https://twitter.com/nplusodin\n", "https://ok.ru/nplus1\n", "https://soundcloud.com/nplus_1\n", "/rss\n" ] } ], "source": [ "for link in soup.find_all('a'):\n", " print(link.get('href'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В коде выше мы использовали метод `find_all()`, который выполняет поиск по заданному тэгу и возвращает список частей кода HTML с выбранным тэгом. Каждый элемент возвращаемого списка имеет тип `BeautifulSoup` и структуру, очень похожую на словарь. Например, ссылка `` изнутри выглядит как словарь следующего вида:\n", "\n", " {'href' : '/rubric/robots-drones', \n", " 'class' : ''}.\n", " \n", "Как мы помним, значение по ключу из словаря можно вызвать с помощью метода `.get()`. Именно его мы и использовали в коде выше, чтобы извлечь содержимое `href`. \n", "\n", "Ссылок в списке выше много. Но нам нужны только новости – ссылки, которые начинаются со слова `/news`. Добавим условие: будем выбирать только те ссылки, в которых есть `/news`. Создадим пустой список `urls` и будем добавлять в него только ссылки, которые удовлетворяют этому условию." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['/news/2020/04/27/venus-atmosphere-tidal-waves',\n", " '/news/2020/04/27/zumwalt',\n", " '/news/2020/04/27/starship-pressure-passed',\n", " '/news/2020/04/27/e-fan-x',\n", " '/news/2020/04/25/hyperphagia-neurons',\n", " '/news/2020/04/25/dna-pocket',\n", " '/news/2020/04/25/moon-landing-spray',\n", " '/news/2020/04/25/thermogalvanic-hydrogel-cooling',\n", " '/news/2020/04/24/30-years-hubble',\n", " '/news/2020/04/24/feline-grimace-scale',\n", " '/news/2020/04/24/supermassive-black-hole-escape-star',\n", " '/news/2020/04/24/adobe',\n", " '/news/2020/04/24/broken-hearts',\n", " '/news/2020/04/24/00s-taxi',\n", " '/news/2020/04/24/cold-sweet',\n", " '/news/2020/04/24/avian',\n", " '/news/2020/04/24/kentaurs-interstellar',\n", " '/news/2020/04/24/ocean-macroplastic-finding',\n", " '/news/2020/04/24/smartwatch',\n", " '/news/2020/04/24/antarctic-calyptocephalella',\n", " '/news/2020/04/23/underwater-quantum-communication',\n", " '/news/2020/04/21/self-adapt-PVDF',\n", " '/news/2020/04/27/venus-atmosphere-tidal-waves',\n", " '/news/2020/04/25/thermogalvanic-hydrogel-cooling',\n", " '/news/2020/04/25/hyperphagia-neurons',\n", " '/news/2020/04/22/carbon-nanothread-bundle',\n", " '/news/2020/04/21/model-based-learning',\n", " '/news/2020/04/23/gw-190412-ligo',\n", " '/news/2020/04/21/digital-embryo']" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "urls = []\n", "for link in soup.find_all('a'):\n", " if '/news' in link.get('href'):\n", " urls.append(link.get('href'))\n", "urls" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ссылки, которые у нас есть в списке `urls`, относительные: они неполные, начало ссылки, в данном случае название сайта, отсутствует. Давайте превратим их в абсолютные ‒ склеим с ссылкой https://nplus1.ru." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['https://nplus1.ru/news/2020/04/27/venus-atmosphere-tidal-waves',\n", " 'https://nplus1.ru/news/2020/04/27/zumwalt',\n", " 'https://nplus1.ru/news/2020/04/27/starship-pressure-passed',\n", " 'https://nplus1.ru/news/2020/04/27/e-fan-x',\n", " 'https://nplus1.ru/news/2020/04/25/hyperphagia-neurons',\n", " 'https://nplus1.ru/news/2020/04/25/dna-pocket',\n", " 'https://nplus1.ru/news/2020/04/25/moon-landing-spray',\n", " 'https://nplus1.ru/news/2020/04/25/thermogalvanic-hydrogel-cooling',\n", " 'https://nplus1.ru/news/2020/04/24/30-years-hubble',\n", " 'https://nplus1.ru/news/2020/04/24/feline-grimace-scale',\n", " 'https://nplus1.ru/news/2020/04/24/supermassive-black-hole-escape-star',\n", " 'https://nplus1.ru/news/2020/04/24/adobe',\n", " 'https://nplus1.ru/news/2020/04/24/broken-hearts',\n", " 'https://nplus1.ru/news/2020/04/24/00s-taxi',\n", " 'https://nplus1.ru/news/2020/04/24/cold-sweet',\n", " 'https://nplus1.ru/news/2020/04/24/avian',\n", " 'https://nplus1.ru/news/2020/04/24/kentaurs-interstellar',\n", " 'https://nplus1.ru/news/2020/04/24/ocean-macroplastic-finding',\n", " 'https://nplus1.ru/news/2020/04/24/smartwatch',\n", " 'https://nplus1.ru/news/2020/04/24/antarctic-calyptocephalella',\n", " 'https://nplus1.ru/news/2020/04/23/underwater-quantum-communication',\n", " 'https://nplus1.ru/news/2020/04/21/self-adapt-PVDF',\n", " 'https://nplus1.ru/news/2020/04/27/venus-atmosphere-tidal-waves',\n", " 'https://nplus1.ru/news/2020/04/25/thermogalvanic-hydrogel-cooling',\n", " 'https://nplus1.ru/news/2020/04/25/hyperphagia-neurons',\n", " 'https://nplus1.ru/news/2020/04/22/carbon-nanothread-bundle',\n", " 'https://nplus1.ru/news/2020/04/21/model-based-learning',\n", " 'https://nplus1.ru/news/2020/04/23/gw-190412-ligo',\n", " 'https://nplus1.ru/news/2020/04/21/digital-embryo']" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "full_urls = ['https://nplus1.ru' + u for u in urls]\n", "full_urls" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь наша задача сводится к следующему: изучить одну страницу с новостью, научиться из нее вытаскивать текст и всю необходимую информацию, а потом применить весь набор действий к каждой ссылке из `full_urls` в цикле. Посмотрим на новость с индексом 0, у вас может быть другая, новости обновляются." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "https://nplus1.ru/news/2020/04/27/venus-atmosphere-tidal-waves\n" ] } ], "source": [ "url0 = full_urls[0]\n", "print(url0)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "page0 = requests.get(url0)\n", "soup0 = BeautifulSoup(page0.text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В коде каждой страницы с новостью есть часть с мета-информацией: датой, именем автора и проч. Такая информация окружена тэгом ``. Посмотрим:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup0.find_all('meta')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Из этого списка нам нужны части с именем автора, датой, заголовком и кратким описанием. Воспользуемся поиском по атрибуту `name`. Передадим функции `find_all()` в качестве аргумента словарь с названием и значением атрибута:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup0.find_all('meta', {'name' : 'author'})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь выберем единственный элемент полученного списка (с индексом 0):" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup0.find_all('meta', {'name' : 'author'})[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Объект выше имеет структуру как у словаря, поэтому мы можем вызвать значение `content` через метод `.get()`:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Кристина Уласович'" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup0.find_all('meta', {'name' : 'author'})[0].get('content') " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Или вовсе без него, указав название ключа в квадратных скобках:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "author = soup0.find_all('meta', {'name' : 'author'})[0]['content']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Изучим внимательно исходный код страницы новости и аналогичным образом найдем заголовок новости, описание и дату публикации:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "title = soup0.find_all('meta', \n", " {'property' : 'og:title'})[0]['content']\n", "description = soup0.find_all('meta', \n", " {'property' : 'og:description'})[0]['content']\n", "date = soup0.find_all('meta', \n", " {'itemprop' : 'datePublished'})[0]['content']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Осталось вытащить сложность текста и рубрики. Сложность находится в тэге `span` с классом `difficult-value`:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.7" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup0.find_all('span', {'class' : 'difficult-value'})[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Извлечем текст, который находится внутри тэгов, с помощью атрибута `.text`:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "difficult = soup0.find_all('span', \n", " {'class' : 'difficult-value'})[0].text" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "С рубриками интереснее. Рубрики находятся в тэгах `p` с классом `table`:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "

\n", "Астрономия\n", "

" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup0.find_all('p', {'class' : 'table'})[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В этом отрывке кода есть ссылки на рубрики. «Выцепим» все ссылки по тэгу `a`:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Астрономия]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "raw_rubrics = soup0.find_all('p', \n", " {'class' : 'table'})[0].find_all('a')\n", "raw_rubrics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А теперь извлечем из каждого кусочка кода для ссылки текст:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Астрономия']" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rubrics = []\n", "for r in raw_rubrics:\n", " rubrics.append(r.text)\n", "rubrics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Перейдем к самому главному – тексту новости. Как можно заметить, текст сохранен в абзацах `

`, причем безо всяких атрибутов. Сообщим Python, что нас интересуют куски с пустым атрибутом `class`:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[

Японские планетологи выяснили, что необычно быстрое вращение атмосферы Венеры поддерживается благодаря тепловым приливам, волнам Россби и турбулентности. К такому выводу они пришли на основе снимков облачного слоя, сделанных с помощью межпланетного зонда «Акацуки». Статья опубликована в журнале Science.

,\n", "

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

,\n", "

Такеши Хоринучи (Takeshi Horinouchi) из Университета Хоккайдо вместе с коллегами изучили снимки, сделанные аппаратом «Акацуки» японского аэрокосмического агентства JAXA. Используя данные наблюдений в ультрафиолетовом и инфракрасном диапазонах с 2015 по 2018 год, исследователи отследили движение облаков и определили скорость движения ветров на разных широтах, а затем построили глобальную модель переноса углового момента в атмосфере.

,\n", "

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

,\n", "

,\n", "

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

,\n", "

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

,\n", "

Кристина Уласович

,\n", "

Нашли опечатку? Выделите фрагмент и нажмите Ctrl+Enter.

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

Коэффициент сложности

,\n", "

© 2020 N+1 Интернет-издание   Свидетельство о регистрации СМИ Эл № ФС77-67614

,\n", "

Использование всех текстовых материалов без изменений в некоммерческих целях разрешается со ссылкой на N+1. \n", " Все аудиовизуальные произведения являются собственностью своих авторов и правообладателей и используются \n", " только в образовательных и информационных целях. Если вы являетесь собственником того или иного произведения \n", " и не согласны с его размещением на нашем сайте, пожалуйста, напишите на kirill@nplus1.ru

,\n", "

Материалы, опубликованные в разделе «Блоги», отражают позиции их авторов, которые могут не совпадать с мнением редакции.

,\n", "

Сайт может содержать контент, не предназначенный для лиц младше 18 лет.

,\n", "

\n", " Политика обработки персональных данных пользователей сайта\n", "

,\n", "

\n", " \n", " Change privacy settings\n", "

,\n", "

\n", "

]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup0.find_all('p', {'class' : None})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "«Выцепим» все тексты (без тэгов) из полученного списка и склеим все элементы списка `text` через пробел:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "pars = []\n", "for p in soup0.find_all('p', {'class' : None}):\n", " pars.append(p.text)\n", "text = \" \".join(pars)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Избавимся от лишнего текста после фразы *Нашли опечатку?* и заменим лишние символы на обычные пробелы:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "text_final = text.split(\"Нашли опечатку?\")[0].replace('\\xa0', \n", " ' ').replace('\\n', ' ')" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Японские планетологи выяснили, что необычно быстрое вращение атмосферы Венеры поддерживается благодаря тепловым приливам, волнам Россби и турбулентности. К такому выводу они пришли на основе снимков облачного слоя, сделанных с помощью межпланетного зонда «Акацуки». Статья опубликована в журнале Science. Еще в середине прошлого века астрономы заметили, что верхние слои плотного облачного покрова Венеры движутся намного быстрее ее поверхности. В то время как период вращения планеты составляет 243 земных дня, ее атмосфере на полный оборот требуется всего 92 часа — этот феномен назвали суперротацией. Для поддержания суперротации необходимо непрерывное перераспределение углового момента, которое позволило бы преодолеть трение с поверхностью планеты, однако механизмы, лежащие в основе этого процесса, до сих пор оставались неизвестны. Такеши Хоринучи (Takeshi Horinouchi) из Университета Хоккайдо вместе с коллегами изучили снимки, сделанные аппаратом «Акацуки» японского аэрокосмического агентства JAXA. Используя данные наблюдений в ультрафиолетовом и инфракрасном диапазонах с 2015 по 2018 год, исследователи отследили движение облаков и определили скорость движения ветров на разных широтах, а затем построили глобальную модель переноса углового момента в атмосфере. Анализ показал, что угловой момент возникает и поддерживается за счет тепловых приливов, которые представляют собой изменения атмосферного давления, вызванные солнечным нагревом вблизи экватора планеты. Им в противовес действуют волны планетарного масштаба (также известные как волны Россби) и крупномасштабная атмосферная турбулентность. При этом эксперты отмечают, что вопрос о том, отражает ли построенная японскими планетологами модель полную картину, остается открытым, так как исследователи проанализировали лишь один слой газовой оболочки Венеры. По их мнению, существует вероятность, что активность и сила влияния атмосферных волн может отличаться на других уровнях облачного покрова планеты. Ранее исследователи выяснили, что на поведение атмосферы Венеры может также влиять и форма ее поверхности. По их мнению, под плотным слоем облаков планеты могут скрываться горы, на которые наталкиваются воздушные потоки, в результате чего формируются волны тяготения. Кристина Уласович \n" ] } ], "source": [ "print(text_final)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь все красиво. Перейдем к семинару – напишем функцию для выгрузки информации по одной новости и применим ее к новостям на главной странице." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def get_info(url0):\n", " page0 = requests.get(url0)\n", " soup0 = BeautifulSoup(page0.text, 'lxml')\n", " author = soup0.find_all('meta', {'name' : 'author'})[0]['content']\n", " title = soup0.find_all('meta', {'property' : 'og:title'})[0]['content']\n", " description = soup0.find_all('meta', \n", " {'property' : 'og:description'})[0]['content']\n", " date = soup0.find_all('meta', \n", " {'itemprop' : 'datePublished'})[0]['content']\n", " difficult = soup0.find_all('span', \n", " {'class' : 'difficult-value'})[0].text\n", " raw_rubrics = soup0.find_all('p', \n", " {'class' : 'table'})[0].find_all('a')\n", " rubrics = []\n", " for r in raw_rubrics:\n", " rubrics.append(r.text)\n", " \n", " pars = []\n", " for p in soup0.find_all('p', {'class' : None}):\n", " pars.append(p.text)\n", " text = \" \".join(pars)\n", " \n", " text_final = text.split(\"Нашли опечатку?\")[0].replace('\\xa0', \n", " ' ').replace('\\n', ' ')\n", " return [author, title, description, date, difficult, \n", " rubrics, text_final] " ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }