В предыдущем уроке я показал вам, как использовать модуль Requests для доступа к веб-страницам с использованием Python . Учебное пособие охватывало множество тем, таких как выполнение запросов GET / POST и загрузка таких программ, как изображения или PDF-файлы. Единственное, чего не хватало в этом руководстве, было руководство по очистке веб-страниц, к которым вы обращались, используя Запросы для извлечения необходимой вам информации.
В этом руководстве вы узнаете о Beautiful Soup — библиотеке Python для извлечения данных из файлов HTML. Основное внимание в этом руководстве будет уделено изучению основ библиотеки, а более сложные темы будут рассмотрены в следующем руководстве. Обратите внимание, что в этом руководстве используется Beautiful Soup 4 для всех примеров.
Установка
Вы можете установить Beautiful Soup 4, используя pip
. Название пакета — beautifulsoup4
. Он должен работать как на Python 2, так и на Python 3.
1
|
$ pip install beautifulsoup4
|
Если в вашей системе не установлен pip, вы можете напрямую загрузить архив с исходным кодом Beautiful Soup 4 и установить его с помощью setup.py
.
1
|
$ python setup.py install
|
BeautifulSoup изначально упакован как код Python 2. Когда вы устанавливаете его для использования с Python 3, он автоматически обновляется до кода Python 3. Код не будет преобразован, если вы не установите пакет. Вот несколько распространенных ошибок, которые вы можете заметить:
- Ошибка
ImportError
«Нет модуля с именем HTMLParser» возникает при запуске версии кода Python 2 под Python 3. - Ошибка «Не
ImportError
модуль с именем html.parser» возникает при запуске версии кода Python 3 под Python 2.
Обе ошибки, описанные выше, можно исправить, удалив и переустановив Beautiful Soup.
Установка парсера
Прежде чем обсуждать различия между различными парсерами, которые вы можете использовать с Beautiful Soup, давайте напишем код для создания супа.
1
2
3
|
from bs4 import BeautifulSoup
soup = BeautifulSoup(«<html><p>This is <b>invalid HTML</p></html>», «html.parser»)
|
Объект BeautifulSoup
может принимать два аргумента. Первый аргумент — это фактическая разметка, а второй аргумент — это анализатор, который вы хотите использовать. Разные парсеры: html.parser
, lxml и html5lib . У парсера lxml
есть две версии: парсер HTML и парсер XML.
html.parser
— это встроенный синтаксический анализатор, и он не очень хорошо работает в старых версиях Python. Вы можете установить другие парсеры, используя следующие команды:
1
2
|
$ pip install lxml
$ pip install html5lib
|
Анализатор lxml
очень быстрый и может быть использован для быстрого анализа заданного HTML. С другой стороны, синтаксический анализатор html5lib
очень медленный, но он также чрезвычайно снисходительный. Вот пример использования каждого из этих парсеров:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
soup = BeautifulSoup(«<html><p>This is <b>invalid HTML</p></html>», «html.parser»)
print(soup)
# <html><p>This is <b>invalid HTML</b></p></html>
soup = BeautifulSoup(«<html><p>This is <b>invalid HTML</p></html>», «lxml»)
print(soup)
# <html><body><p>This is <b>invalid HTML</b></p></body></html>
soup = BeautifulSoup(«<html><p>This is <b>invalid HTML</p></html>», «xml»)
print(soup)
# <?xml version=»1.0″ encoding=»utf-8″?>
# <html><p>This is <b>invalid HTML</b></p></html>
soup = BeautifulSoup(«<html><p>This is <b>invalid HTML</p></html>», «html5lib»)
print(soup)
# <html><head></head><body><p>This is <b>invalid HTML</b></p></body></html>
|
Различия, показанные в приведенном выше примере, имеют значение только при разборе неверного HTML. Тем не менее, большая часть HTML в сети искажена, и знание этих различий поможет вам отладить некоторые ошибки синтаксического анализа и решить, какой анализатор вы хотите использовать в проекте. Как правило, анализатор lxml
— очень хороший выбор.
Предметы в прекрасном супе
Beautiful Soup разбирает данный HTML-документ на дерево объектов Python. Есть четыре основных объекта Python, о которых вам нужно знать: Tag
, NavigableString
, BeautifulSoup
и Comment
.
Объект Tag
ссылается на фактический тег XML или HTML в документе. Вы можете получить доступ к имени тега, используя tag.name
. Вы также можете установить имя тега на что-то другое. Изменение имени будет видно в разметке, созданной Beautiful Soup.
Вы можете получить доступ к различным атрибутам, таким как класс и идентификатор тега, используя tag['class']
и tag['id']
соответственно. Вы также можете получить доступ ко всему словарю атрибутов, используя tag.attrs
. Вы также можете добавлять, удалять или изменять атрибуты тега. Атрибуты, такие как class
элемента, который может принимать несколько значений, хранятся в виде списка.
Текст внутри тега сохраняется в виде NavigableString
в Beautiful Soup. У него есть несколько полезных методов, таких как replace_with("string")
для замены текста внутри тега. Вы также можете преобразовать NavigableString
в строку unicode()
используя unicode()
.
Красивый суп также позволяет получить доступ к комментариям на веб-странице. Эти комментарии хранятся в виде объекта Comment
, который также является в основном NavigableString
.
Вы уже узнали об объекте BeautifulSoup
в предыдущем разделе. Он используется для представления документа в целом. Поскольку это не фактический объект, он не имеет ни имени, ни атрибутов.
Получение заголовка, заголовков и ссылок
Вы можете легко извлечь заголовок страницы и другие подобные данные, используя Beautiful Soup. Давайте почистим страницу Википедии о Python . Во-первых, вам нужно получить разметку страницы, используя следующий код на основе учебного пособия модуля Запросы для доступа к веб-страницам .
1
2
3
4
5
|
import requests
from bs4 import BeautifulSoup
req = requests.get(‘https://en.wikipedia.org/wiki/Python_(programming_language)’)
soup = BeautifulSoup(req.text, «lxml»)
|
Теперь, когда вы создали суп, вы можете получить заголовок веб-страницы, используя следующий код:
1
2
3
4
5
6
7
8
|
soup.title
# <title>Python (programming language) — Wikipedia</title>
soup.title.name
# ‘title’
soup.title.string
# ‘Python (programming language) — Wikipedia’
|
Вы также можете очистить веб-страницу для получения другой информации, такой как основной заголовок или первый абзац, их классы или атрибут id
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
soup.h1
# <h1 class=»firstHeading» id=»firstHeading» lang=»en»>Python (programming language)</h1>
soup.h1.string
# ‘Python (programming language)’
soup.h1[‘class’]
# [‘firstHeading’]
soup.h1[‘id’]
# ‘firstHeading’
soup.h1.attrs
# {‘class’: [‘firstHeading’], ‘id’: ‘firstHeading’, ‘lang’: ‘en’}
soup.h1[‘class’] = ‘firstHeading, mainHeading’
soup.h1.string.replace_with(«Python — Programming Language»)
del soup.h1[‘lang’]
del soup.h1[‘id’]
soup.h1
# <h1 class=»firstHeading, mainHeading»>Python — Programming Language</h1>
|
Точно так же вы можете перебирать все ссылки или подзаголовки в документе, используя следующий код:
1
2
3
4
|
for sub_heading in soup.find_all(‘h2’):
print(sub_heading.text)
# all the sub-headings like Contents, History[edit]…
|
Навигация по DOM
Вы можете перемещаться по дереву DOM, используя обычные имена тегов. Связывание этих имен тегов может помочь вам более глубоко ориентироваться в дереве. Например, вы можете получить первую ссылку в первом абзаце данной страницы Википедии, используя soup.pa
Все ссылки в первом абзаце могут быть доступны с помощью soup.p.find_all('a')
.
Вы также можете получить доступ ко всем tag.contents
тега в виде списка с помощью tag.contents
. Чтобы получить детей по определенному индексу, вы можете использовать tag.contents[index]
. Вы также можете перебирать дочерние теги, используя атрибут .children
.
И .children
и .contents
полезны только тогда, когда вы хотите получить доступ к прямым или .contents
потомкам тега. Чтобы получить всех потомков, вы можете использовать атрибут .descendants
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
print(soup.p.contents)
# [<b>Python</b>, ‘ is a widely used ‘,…..the full list]
print(soup.p.contents[10])
# <a href=»/wiki/Readability» title=»Readability»>readability</a>
for child in soup.p.children:
print(child.name)
# b
# None
# a
# None
# a
# None
# … and so on.
|
Вы также можете получить доступ к родительскому элементу, используя атрибут .parent
. Точно так же вы можете получить доступ ко всем предкам элемента, используя атрибут .parents
. Родителем тега <html>
верхнего уровня является сам объект BeautifulSoup
, а его родителем — None.
01
02
03
04
05
06
07
08
09
10
11
|
print(soup.p.parent.name)
# div
for parent in soup.p.parents:
print(parent.name)
# div
# div
# div
# body
# html
# [document]
|
Вы можете получить доступ к предыдущему и следующему брату элемента, используя .previous_sibling
и .next_sibling
.
Чтобы два элемента были братьями и сестрами, они должны иметь одного и того же родителя. Это означает, что первый дочерний элемент не будет иметь предыдущего родного брата. Точно так же у последнего потомка элемента не будет следующего родного брата. На реальных веб-страницах предыдущий и следующий братья и сестры элемента, скорее всего, будут символом новой строки.
Вы также можете перебрать все элементы одного элемента, используя .previous_siblings
и .next_siblings
.
01
02
03
04
05
06
07
08
09
10
11
|
soup.head.next_sibling
# ‘\n’
soup.panext_sibling
# ‘ for ‘
soup.paprevious_sibling
# ‘ is a widely used ‘
print(soup.pbprevious_sibling)
# None
|
Вы можете перейти к элементу, который идет сразу после текущего элемента, используя атрибут .next_element
. Чтобы получить доступ к элементу, который находится непосредственно перед текущим элементом, используйте атрибут .previous_element
.
Точно так же вы можете перебирать все элементы, которые идут до и после текущего элемента, используя .previous_elements
и .next_elements
соответственно.
Последние мысли
После завершения этого урока вы должны хорошо понимать основные различия между различными HTML-парсерами. Теперь вы также должны иметь возможность перемещаться по веб-странице и извлекать важные данные. Это может быть полезно, если вы хотите проанализировать все заголовки или ссылки на данном веб-сайте.
В следующей части серии вы узнаете, как использовать библиотеку Beautiful Soup для поиска и изменения DOM.