eautifulSoup является библиотекой Python для парсинга HTML и XML документов. Часто используется для скрапинга веб-страниц. BeautifulSoup позволяет трансформировать сложный HTML-документ в сложное древо различных объектов Python. Это могут быть теги, навигация или комментарии.
Для установки необходимых модулей используется команда pip3. Для начала требуется установить lxml модуль, который используется в BeautifulSoup.
$ sudo pip3 install lxml
BeautifulSoup устанавливается при помощи использования указанной ниже команды.
$ sudo pip3 install bs4
В последующих примерах будет использован данный HTML-файл:
<!DOCTYPE html> <html> <head> <title>Header</title> <meta charset="utf-8"> </head> <body> <h2>Operating systems</h2> <ul id="mylist" style="width:150px"> <li>Solaris</li> <li>FreeBSD</li> <li>Debian</li> <li>NetBSD</li> <li>Windows</li> </ul> <p> FreeBSD is an advanced computer operating system used to power modern servers, desktops, and embedded platforms. </p> <p> Debian is a Unix-like computer operating system that is composed entirely of free software. </p> </body> </html>
В первом примере будет использован BeautifulSoup модуль для получения трех тегов.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') print(soup.h2) print(soup.head) print(soup.li)
Код в данном примере позволяет вывести HTML-код трех тегов.
from bs4 import BeautifulSoup
Здесь производится импорт класса BeautifulSoup из модуля bs4. Таким образом, BeautifulSoup является главным рабочим классом.
with open("index.html", "r") as f: contents = f.read()
Открывается файл index.html и производится чтение его содержимого при помощи метода read().
soup = BeautifulSoup(contents, 'lxml')
Создается объект BeautifulSoup. Данные передаются конструктору. Вторая опция уточняет объект парсинга.
print(soup.h2) print(soup.head)
Далее выводится HTML-код следующих двух тегов: h2 и head.
print(soup.li)
В примере много раз используются элементы li, однако выводится только первый из них.
$ ./simple.py <h2>Operating systems</h2> <head> <title>Header</title> <meta charset="utf-8"/> </head> <li>Solaris</li>
Это результат вывода.
Атрибут name указывает на название тега, а атрибут text указывает на его содержимое.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') print("HTML: {0}, name: {1}, text: {2}".format(soup.h2, soup.h2.name, soup.h2.text))
Код в примере позволяет вывести HTML-код, название и текст h2 тега.
$ ./tags_names.py HTML: <h2>Operating systems</h2>, name: h2, text: Operating systems
Это результат вывода.
Метод recursiveChildGenerator() позволяет перебрать содержимое HTML-документа.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') for child in soup.recursiveChildGenerator(): if child.name: print(child.name)
Данный пример позволяет перебрать содержимое HTML-документа и вывести названия всех его тегов.
$ ./traverse_tree.py
html
head
title
meta
body
h2
ul
li
li
li
li
li
p
p
Данные теги являются частью рассматриваемого HTML-документа.
При помощи атрибута children можно вывести все дочерние теги.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') root = soup.html root_childs = [e.name for e in root.children if e.name is not None] print(root_childs)
В данном примере извлекаются дочерние элементы html тега, после чего они помещаются в список Python и выводятся в консоль. Так как атрибут children также убирает пробелы между тегами, необходимо добавить условие, которое позволяет выбирать только названия тегов.
$ ./get_children.py ['head', 'body']
Следовательно, у тегов html есть два дочерних элемента: head и body.
При помощи атрибута descendants можно получить список всех потомков (дочерних элементов всех уровней) рассматриваемого тега.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') root = soup.body root_childs = [e.name for e in root.descendants if e.name is not None] print(root_childs)
Данный пример позволяет найти всех потомков главного тега body.
$ ./get_descendants.py ['h2', 'ul', 'li', 'li', 'li', 'li', 'li', 'p', 'p']
Перечисленные выше теги являются потомками главного тега body.
Requests является простой HTTP библиотекой в Python. Она позволяет использовать разнообразные методы для получения доступа к веб-ресурсам при помощи HTTP.
from bs4 import BeautifulSoup import requests as req resp = req.get("http://www.something.com") soup = BeautifulSoup(resp.text, 'lxml') print(soup.title) print(soup.title.text) print(soup.title.parent)
Данный пример извлекает название рассматриваемой веб-страницы. Здесь также выводится имя ее родителя.
resp = req.get("http://www.something.com") soup = BeautifulSoup(resp.text, 'lxml')
Здесь мы получаем информацию о веб-странице.
print(soup.title) print(soup.title.text) print(soup.title.parent)
Код выше помогает вывести HTML-код заголовка, его текст, а также HTML-код его родителя.
$ ./scraping.py <title>Something.</title> Something. <head><title>Something.</title></head>
Это результат вывода.
При помощи метода prettify() можно добиться того, чтобы HTML-код выглядел аккуратнее.
from bs4 import BeautifulSoup import requests as req resp = req.get("http://www.something.com") soup = BeautifulSoup(resp.text, 'lxml') print(soup.prettify())
Таким образом, мы оптимизируем HTML-код простой веб-страницы.
3 4 5 6 7 8 9 10 11 $ ./prettify.py <html> <head> <title> Something. </title> </head> <body> Something. </body> </html>
Это результат вывода.
При помощи метода find() можно найти элементы страницы, используя различные опорные параметры, id в том числе.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') #print(soup.find("ul", attrs={ "id" : "mylist"})) print(soup.find("ul", id="mylist"))
Код в примере находит тег ul, у которого id mylist. Строка в комментарии является альтернативным способом выполнить то же самое задание.
При помощи метода find_all() можно найти все элементы, которые соответствуют заданным критериям.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') for tag in soup.find_all("li"): print("{0}: {1}".format(tag.name, tag.text))
Код в примере позволяет найти и вывести на экран все li теги.
$ ./find_all.py
li: Solaris
li: FreeBSD
li: Debian
li: NetBSD
Это результат вывода.
Метод find_all() также при поиске использует список из названий тегов.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') tags = soup.find_all(['h2', 'p']) for tag in tags: print(" ".join(tag.text.split()))
В данном примере показано, как найти все h2 и p элементы, после чего вывести их содержимое на экран.
Метод find_all() также может использовать функцию, которая определяет, какие элементы должны быть выведены.
from bs4 import BeautifulSoup def myfun(tag): return tag.is_empty_element with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') tags = soup.find_all(myfun) print(tags)
Данный пример выводит пустые элементы.
$ ./find_by_fun.py [<meta charset="utf-8"/>]
Единственным пустым элементом в документе является meta.
Также можно найти запрашиваемые элементы, используя регулярные выражения.
import re from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') strings = soup.find_all(string=re.compile('BSD')) for txt in strings: print(" ".join(txt.split()))
В данном примере выводится содержимое элементов, в которых есть строка с символами ‘BSD’.
$ ./regex.py FreeBSD NetBSD FreeBSD is an advanced computer operating system used to power modern servers, desktops, and embedded platforms.
Это результат вывода.
При помощи методов select() и select_one() для нахождения запрашиваемых элементов можно использовать некоторые CSS селекторы.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') print(soup.select("li:nth-of-type(3)"))
В данном примере используется CSS селектор, который выводит на экран HTML-код третьего по счету элемента li.
$ ./select_nth_tag.py <li>Debian</li>
Данный элемент li является третьим в списке.
В CSS символ # используется для выбора тегов по их id-атрибутам.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') print(soup.select_one("#mylist"))
В данном примере выводятся элементы, которых есть id под названием mylist.
Возвращает ближайшего родителя этого тега, который соответствует заданным критериям.
BeautifulSoup.find_parent(name=None, attrs={}, **kwargs)
Возвращает родителей этого тега, которые соответствуют заданным критериям.
BeautifulSoup.findParents(name=None, attrs={}, limit=None, **kwargs)
Возвращает ближайшего родственника к этому тегу, который соответствует заданным критериям и появляется после этого тега в документе.
BeautifulSoup.find_next_sibling(name=None, attrs={}, text=None, **kwargs)
Возвращает ближайшего родственника к этому тегу, который соответствует заданным критериям и отображается перед этим тегом в документе.
BeautifulSoup.find_previous_sibling(name=None, attrs={}, text=None, **kwargs)
Метод append() добавляет в рассматриваемый HTML-документ новый тег.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') newtag = soup.new_tag('li') newtag.string='OpenBSD' ultag = soup.ul ultag.append(newtag) print(ultag.prettify())
В примере выше показано, как в HTML-документ добавить новый тег li.
newtag = soup.new_tag('li') newtag.string='OpenBSD'
Для начала, требуется создать новый тег при помощи метода new_tag().
ultag = soup.ul
Далее создается сноска на тег ul.
ultag.append(newtag)
Затем созданный ранее тег li добавляется к тегу ul.
print(ultag.prettify())
Таким образом, тег ul выводится аккуратно отформатированным.
Метод insert() позволяет вставить тег в определенно выбранное место.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') newtag = soup.new_tag('li') newtag.string='OpenBSD' ultag = soup.ul ultag.insert(2, newtag) print(ultag.prettify())
В примере показано, как поставить тег li на третью позицию в выбранном ul теге.
Метод replace_with() заменяет содержимое выбранного элемента.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') tag = soup.find(text="Windows") tag.replace_with("OpenBSD") print(soup.ul.prettify())
В примере показано, как при помощи метода find() найти определенный элемент, а затем, используя метод replace_with(), заменить его содержимое.
Метод decompose() удаляет определенный тег из структуры документа и уничтожает его.
from bs4 import BeautifulSoup with open("index.html", "r") as f: contents = f.read() soup = BeautifulSoup(contents, 'lxml') ptag2 = soup.select_one("p:nth-of-type(2)") ptag2.decompose() print(soup.body.prettify())
В данном примере показано, как удалить второй элемент p в документе. В данном руководстве было показано, как использовать библиотеку BeautifulSoup в Python.
Страничка для парсинга:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="container"> <div class="row"> <div class="name">Petr</div> <div id="whois">Python developer</div> <div data-set="salary">salary: 2700 usd per month</div> <div class="links"> <a href="https://www.google.ru">Google</a> <a href="www.website.ru">Website</a> <a href="doroga.ru">Personal Webpage</a> </div> <div> <p></p> <p></p> <p></p> <p>some@mail</p> </div> </div> <div class="row"> <div class="name1"> <div class="name">Alena</div> </div> <div id="whois">Copywriter</div> <div data-set="salary">salary: 2100 usd</div> <div class="links"> <a href="http://yandex.ru">Яндекс</a> <a href="http://yandex.ru/website">Яндекс</a> <a href="http://yandex.ru/website/2">Яндекс</a> <a href="www.website.ru">Website</a> <a href="doroga.ru">Personal Webpage</a> </div> <div> <p>@twitter</p> <p></p> <p>some@mail</p> <p></p> </div> </div> <div class="row"> <div class="name">Kate</div> <div id="whois">Copywriter</div> <div data-set="salary">2100 usd</div> <div class="links"> <a href="http://yandex.ru">Яндекс</a> <a href="http://yandex.ru/website">Яндекс</a> <a href="http://yandex.ru/website/2">Яндекс</a> <a href="www.website.ru">Website</a> <a href="doroga.ru">Personal Webpage</a> </div> <div> <p>@twitter</p> <p></p> <p>some@mail</p> <p></p> </div> </div> <div class="row"> <div class="name">Ksenia</div> <div id="whois">Designer</div> <div data-set="salary">2300 usd</div> <div class="links"> <p>some@mail</p> <!-- мыло здесь --> <a href="http://yandex.ru">Яндекс</a> <a href="http://yandex.ru/website">Яндекс</a> <a href="http://yandex.ru/website/2">Яндекс</a> <a href="www.website.ru">Website</a> <a href="doroga.ru">Personal Webpage</a> </div> <div> Links: <p>Мой твиттер @twitter Подписывайтесь</p> <p></p> <p></p> </div> </div> </div> <div> <a href="mailto:email@mail.net">Это не мое мыло</a> </div> </body> </html>
from bs4 import BeautifulSoup import re def get_salary(s): print(s) # salary: 2700 usd per month pattern = r'\d{1,9}' salary = re.findall(pattern, s)[0] print(salary) def main(): file = open('index.html').read() soup = BeautifulSoup(file, 'lxml') salary = soup.find_all('div', {'data-set': 'salary'}) for i in salary: get_salary(i.text)
результат
salary: 2700 usd per month 2700 salary: 2100 usd 2100 2100 usd 2100 2300 usd 2300
from bs4 import BeautifulSoup import re file = open('index.html').read() soup = BeautifulSoup(file, 'lxml') salary = soup.find_all('div', text=re.compile('\d{1,9}')) for i in salary: print(i.text)
результат
salary: 2700 usd per month salary: 2100 usd 2100 usd 2300 usd