Как очистить веб-страницы с красивым супом и Python 3

Вступление

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

Beautiful Soup, намек на песнюMock Turtle’s, найденную в главе 10 книги Льюиса КэрроллаAlice’s Adventures in Wonderland, представляет собой библиотеку Python, которая позволяет быстро выполнять проекты по парсингу веб-страниц. В настоящее время доступно как Beautiful Soup 4 и совместимо с Python 2.7 и Python 3, Beautiful Soup создает дерево синтаксического анализа из проанализированных документов HTML и XML (включая документы с незамкнутыми тегами илиtag soup и другой искаженной разметкой).

В этом руководстве мы соберем и проанализируем веб-страницу, чтобы получить текстовые данные и записать собранную информацию в файл CSV.

Предпосылки

Перед тем как приступить к работе с этим руководством, на вашем компьютере должна быть установлена ​​среда программирования Pythonlocal илиserver-based.

У вас должны быть модули Requests и Beautiful Soupinstalled, которых вы можете достичь, следуя нашему руководству «https://www.digitalocean.com/community/tutorials/how-to-work-with-web-data- using-requests-and-beautiful-soup-with-python-3 [Как работать с веб-данными с помощью запросов и Beautiful Soup с Python 3] ». Также было бы полезно ознакомиться с этими модулями.

Кроме того, поскольку мы будем работать с данными, извлеченными из Интернета, вам должно быть удобно с HTML-структурой и тегами.

Понимание данных

В этом руководстве мы будем работать с данными с официального сайтаNational Gallery of Art в США. Национальная галерея - это художественный музей, расположенный в Национальном торговом центре в Вашингтоне, округ Колумбия. В нем хранится более 120 000 произведений, начиная с эпохи Возрождения и до наших дней, выполненных более 13 000 художников.

Мы хотели бы выполнить поиск в Index of Artists, который на момент обновления этого руководства доступен черезWayback MachineInternet Archive по следующему URL-адресу:

[.Примечание]##

Note: Длинный URL-адрес выше связан с тем, что этот веб-сайт заархивирован Интернет-архивом.

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

Под заголовком интернет-архива вы увидите страницу, которая выглядит следующим образом:

Index of Artists Landing Page

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

Artist names beginning with Z list

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

Для дальнейшего важно отметить, сколько всего страниц есть для письма, которое вы выбираете в списке, которое вы можете узнать, перейдя на последнюю страницу художников. В этом случае всего 4 страницы, и последний исполнитель, указанный на момент написания, -Zykmund, Václav. Последняя страница художниковZ имеет следующий URL:

However, вы также можете получить доступ к указанной выше странице, используя ту же числовую строку Internet Archive первой страницы:

Это важно отметить, потому что мы будем повторять эти страницы позже в этом руководстве.

Чтобы начать знакомство с тем, как устроена эта веб-страница, вы можете взглянуть на ееDOM, которая поможет вам понять, как структурирован HTML. Чтобы проверить DOM, вы можете открытьDeveloper Tools в своем браузере.

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

Чтобы начать наш проект кодирования, давайте активируем нашу среду программирования Python 3. Убедитесь, что вы находитесь в каталоге, в котором находится ваша среда, и выполните следующую команду:

. my_env/bin/activate

Активировав нашу среду программирования, мы создадим новый файл, например, nano. Вы можете назвать свой файл как хотите, в этом руководстве мы назовем егоnga_z_artists.py.

nano nga_z_artists.py

В этом файле мы можем начать импортировать библиотеки, которые мы будем использовать -Requests и Beautiful Soup.

Библиотека запросов позволяет вам использовать HTTP в своих программах на Python удобным для восприятия человеком способом, а модуль Beautiful Soup предназначен для быстрой очистки веб-страниц.

Мы будем импортировать запросы и Beautiful Soup сimport statement. Для Beautiful Soup мы будем импортировать его изbs4, пакета, в котором находится Beautiful Soup 4.

nga_z_artists.py

# Import libraries
import requests
from bs4 import BeautifulSoup

Импортировав модули Requests и Beautiful Soup, мы можем перейти к работе, чтобы сначала собрать страницу, а затем проанализировать ее.

Сбор и анализ веб-страницы

Следующий шаг, который нам нужно сделать, это собрать URL первой веб-страницы с запросами. Мы присвоим URL-адрес первой страницыvariablepage с помощьюmethod requests.get().

nga_z_artists.py

import requests
from bs4 import BeautifulSoup


# Collect first page of artists’ list
page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')

Note: поскольку URL-адрес длинный, код выше и в этом руководстве не будет передаватьPEP 8 E501, который отмечает строки длиной более 79 символов. Вы можете назначить URL-адрес переменной, чтобы сделать код более читабельным в окончательных версиях. Код в этом руководстве предназначен для демонстрационных целей и позволит вам заменять более короткие URL-адреса как часть ваших собственных проектов.

Теперь мы создадим объектBeautifulSoup или дерево синтаксического анализа. Этот объект принимает в качестве аргументов документpage.text из запросов (содержимое ответа сервера), а затем анализирует его из встроенного в Pythonhtml.parser.

nga_z_artists.py

import requests
from bs4 import BeautifulSoup


page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')

# Create a BeautifulSoup object
soup = BeautifulSoup(page.text, 'html.parser')

Когда наша страница собрана, проанализирована и настроена как объектBeautifulSoup, мы можем перейти к сбору данных, которые нам нужны.

Вытягивание текста с веб-страницы

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

Для этого в веб-браузере щелкните правой кнопкой мыши - илиCTRL + щелкните в macOS - на имя первого исполнителя,Zabaglia, Niccola. Во всплывающем контекстном меню вы должны увидеть пункт меню, похожий наInspect Element (Firefox) илиInspect (Chrome).

Context Menu — Inspect Element

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

Web Page Inspector

Сначала мы увидим, что таблица имен находится внутри тегов<div>, гдеclass="BodyText". Важно отметить, что мы ищем только текст в этом разделе веб-страницы. Мы также замечаем, что имяZabaglia, Niccola находится в теге ссылки, поскольку имя ссылается на веб-страницу, которая описывает исполнителя. Поэтому нам нужно ссылаться на тег<a> для ссылок. Имя каждого артиста является ссылкой на ссылку.

Для этого мы воспользуемся методами Beautiful Soupfind() иfind_all(), чтобы извлечь текст имен художников изBodyText<div>.

nga_z_artists.py

import requests
from bs4 import BeautifulSoup


# Collect and parse first page
page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')
soup = BeautifulSoup(page.text, 'html.parser')

# Pull all text from the BodyText div
artist_name_list = soup.find(class_='BodyText')

# Pull text from all instances of  tag within BodyText div
artist_name_list_items = artist_name_list.find_all('a')

Затем в нижней части нашего программного файла мы захотим создатьfor loop, чтобы перебирать все имена исполнителей, которые мы только что поместили в переменнуюartist_name_list_items.

Мы напечатаем эти имена с помощью методаprettify(), чтобы превратить дерево синтаксического анализа Beautiful Soup в красиво отформатированную строку Unicode.

nga_z_artists.py

...
artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')

# Create for loop to print out all artists' names
for artist_name in artist_name_list_items:
    print(artist_name.prettify())

Давайте запустим программу так, как она у нас есть:

python nga_z_artists.py

Как только мы это сделаем, мы получим следующий вывод:

На этом этапе мы видим полный текст и теги, относящиеся ко всем именам художников в тегах<a>, найденных в теге<div class="BodyText"> на первой странице, а также некоторые дополнительные текст ссылки внизу. Поскольку нам не нужна эта дополнительная информация, давайте поработаем над ее удалением в следующем разделе.

Удаление лишних данных

До сих пор нам удалось собрать все данные о тексте ссылок в одном разделе<div> нашей веб-страницы. Однако мы не хотим иметь нижние ссылки, которые не ссылаются на имена художников, поэтому давайте поработаем над тем, чтобы удалить эту часть.

Чтобы удалить нижние ссылки страницы, давайте снова щелкните правой кнопкой мыши иInspect DOM. Мы увидим, что ссылки внизу раздела<div class="BodyText"> содержатся в таблице HTML:<table class="AlphaNav">:

Links in AlphaNav HTML Table

Поэтому мы можем использовать Beautiful Soup для поиска классаAlphaNav и использовать методdecompose() для удаления тега из дерева синтаксического анализа, а затем уничтожить его вместе с его содержимым.

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

nga_z_artists.py

import requests
from bs4 import BeautifulSoup


page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')

soup = BeautifulSoup(page.text, 'html.parser')

# Remove bottom links
last_links = soup.find(class_='AlphaNav')
last_links.decompose()

artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')

for artist_name in artist_name_list_items:
    print(artist_name.prettify())

Теперь, когда мы запустим программу с командойpython nga_z_artist.py, мы получим следующий вывод:

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

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

Вытащить содержимое из тега

Чтобы получить доступ только к реальным именам исполнителей, нам нужно настроить таргетинг на содержимое тегов<a>, а не распечатывать весь тег ссылки.

Мы можем сделать это с помощью.contents от Beautiful Soup, который вернет дочерние элементы тега как Pythonlist data type.

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

nga_z_artists.py

import requests
from bs4 import BeautifulSoup


page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')

soup = BeautifulSoup(page.text, 'html.parser')

last_links = soup.find(class_='AlphaNav')
last_links.decompose()

artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')

# Use .contents to pull out the  tag’s children
for artist_name in artist_name_list_items:
    names = artist_name.contents[0]
    print(names)

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

OutputZabaglia, Niccola
Zaccone, Fabian
Zadkine, Ossip
...
Zanini-Viola, Giuseppe
Zanotti, Giampietro
Zao Wou-Ki

Мы получили список всех имен артистов, которые указаны на первой странице с буквойZ.

Однако что, если мы хотим также захватить URL-адреса, связанные с этими художниками? Мы можем извлечь URL-адреса, найденные в тегах<a> страницы, с помощью методаget('href') в Beautiful Soup.

Из вывода ссылок выше мы знаем, что весь URL-адрес не захватывается, поэтому мы будемconcatenate строка ссылки с передней частью строки URL (в данном случаеhttps://web.archive.org/).

Эти строки мы также добавим в циклfor:

nga_z_artists.py

...
for artist_name in artist_name_list_items:
    names = artist_name.contents[0]
    links = 'https://web.archive.org' + artist_name.get('href')
    print(names)
    print(links)

Когда мы запустим указанную выше программу, мы получимboth имена художников и URL-адреса ссылок, которые расскажут нам больше о художниках:

OutputZabaglia, Niccola
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=11630
Zaccone, Fabian
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=34202
...
Zanotti, Giampietro
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=11631
Zao Wou-Ki
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=3427

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

Запись данных в файл CSV

Сбор данных, которые живут только в терминальном окне, не очень полезен. Файлы с разделенными запятыми значениями (CSV) позволяют нам хранить табличные данные в виде простого текста и являются распространенным форматом для электронных таблиц и баз данных. Перед тем, как начать с этого раздела, вы должны ознакомиться сhow to handle plain text files in Python.

Во-первых, нам нужно импортировать встроенный модуль Pythoncsv вместе с другими модулями в верхней части файла программирования Python:

import csv

Затем мы создадим и откроем для нас файл с именемz-artist-names.csv вwrite to (здесь мы будем использовать переменнуюf для файла), используя режим'w'. Мы также напишем заголовки верхней строки:Name иLink, которые мы передадим методуwriterow() в виде списка:

f = csv.writer(open('z-artist-names.csv', 'w'))
f.writerow(['Name', 'Link'])

Наконец, в нашем циклеfor мы запишем каждую строку сnames исполнителей и связанными с нимиlinks:

f.writerow([names, links])

Вы можете увидеть строки для каждой из этих задач в файле ниже:

nga_z_artists.py

import requests
import csv
from bs4 import BeautifulSoup


page = requests.get('https://web.archive.org/web/20121007172955/http://www.nga.gov/collection/anZ1.htm')

soup = BeautifulSoup(page.text, 'html.parser')

last_links = soup.find(class_='AlphaNav')
last_links.decompose()

# Create a file to write to, add headers row
f = csv.writer(open('z-artist-names.csv', 'w'))
f.writerow(['Name', 'Link'])

artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')

for artist_name in artist_name_list_items:
    names = artist_name.contents[0]
    links = 'https://web.archive.org' + artist_name.get('href')


    # Add each artist’s name and associated link to a row
    f.writerow([names, links])

Когда вы запустите программу сейчас с помощью командыpython, никакие выходные данные не будут возвращены в окно вашего терминала. Вместо этого в каталоге, в котором вы работаете, будет создан файл с именемz-artist-names.csv.

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

z-artist-names.csv

Name,Link
"Zabaglia, Niccola",https://web.archive.org/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=11630
"Zaccone, Fabian",https://web.archive.org/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=34202
"Zadkine, Ossip",https://web.archive.org/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=3475w
...

Или это может выглядеть больше как электронная таблица:

CSV Spreadsheet

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

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

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

Для начала мы хотим инициализировать список для хранения страниц:

pages = []

Мы заполним этот инициализированный список следующим цикломfor:

for i in range(1, 5):
    url = 'https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ' + str(i) + '.htm'
    pages.append(url)

Earlier in this tutorial, мы отметили, что нам следует обратить внимание на общее количество страниц, на которых имена художников начинаются с буквыZ (или любой другой буквы, которую мы используем). Поскольку для буквыZ есть 4 страницы, мы построили циклfor выше с диапазоном от1 до5, чтобы он проходил по каждой из 4 страниц. .

Для этого конкретного веб-сайта URL-адреса начинаются со строкиhttps://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ, а затем следуют номер страницы (который будет целым числомi из циклаfor, который мыconvert to a string) и заканчиваются.htm. Мы объединим эти строки вместе, а затем добавим результат в списокpages.

В дополнение к этому циклу у нас будет второй цикл, который будет проходить через каждую из страниц выше. Код в этом циклеfor будет похож на код, который мы создали до сих пор, поскольку он выполняет задачу, которую мы выполнили для первой страницы художников буквыZ для каждой из 4 страниц всего . Обратите внимание: поскольку мы поместили исходную программу во второй циклfor, теперь у нас есть исходный цикл какnested for loop, содержащийся в нем.

Два циклаfor будут выглядеть так:

pages = []

for i in range(1, 5):
    url = 'https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ' + str(i) + '.htm'
    pages.append(url)

for item in pages:
    page = requests.get(item)
    soup = BeautifulSoup(page.text, 'html.parser')

    last_links = soup.find(class_='AlphaNav')
    last_links.decompose()

    artist_name_list = soup.find(class_='BodyText')
    artist_name_list_items = artist_name_list.find_all('a')

    for artist_name in artist_name_list_items:
        names = artist_name.contents[0]
        links = 'https://web.archive.org' + artist_name.get('href')

        f.writerow([names, links])

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

Эти два циклаfor идут под операторамиimport, созданием и записью файла CSV (со строкой для записи заголовков файла) и инициализацией переменнойpages (назначенной к списку).

В более широком контексте программного файла полный код выглядит следующим образом:

nga_z_artists.py

import requests
import csv
from bs4 import BeautifulSoup


f = csv.writer(open('z-artist-names.csv', 'w'))
f.writerow(['Name', 'Link'])

pages = []

for i in range(1, 5):
    url = 'https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ' + str(i) + '.htm'
    pages.append(url)


for item in pages:
    page = requests.get(item)
    soup = BeautifulSoup(page.text, 'html.parser')

    last_links = soup.find(class_='AlphaNav')
    last_links.decompose()

    artist_name_list = soup.find(class_='BodyText')
    artist_name_list_items = artist_name_list.find_all('a')

    for artist_name in artist_name_list_items:
        names = artist_name.contents[0]
        links = 'https://web.archive.org' + artist_name.get('href')

        f.writerow([names, links])

Поскольку эта программа выполняет небольшую работу, создание файла CSV займет некоторое время. Как только это будет сделано, вывод будет завершен, показывая имена исполнителей и связанные с ними ссылки отZabaglia, Niccola доZykmund, Václav.

Быть внимательным

При очистке веб-страниц важно внимательно относиться к серверам, с которых вы собираете информацию.

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

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

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

import requests

headers = {
    'User-Agent': 'Your Name, example.com',
    'From': '[email protected]'
}

url = 'https://example.com'

page = requests.get(url, headers = headers)

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

Заключение

В этом руководстве использовались Python и Beautiful Soup для очистки данных с веб-сайта. Мы сохранили текст, который мы собрали в файле CSV.

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

Чтобы продолжить изучение информации из Интернета, прочитайте наш учебник «https://www.digitalocean.com/community/tutorials/how-to-crawl-a-web-page-with-scrapy-and-python-3 [ Как сканировать веб-страницу с помощью Scrapy и Python 3] ».

Related