Содержание

BeautifulSoup

eautifulSoup является библиотекой Python для парсинга HTML и XML документов. Часто используется для скрапинга веб-страниц. BeautifulSoup позволяет трансформировать сложный HTML-документ в сложное древо различных объектов Python. Это могут быть теги, навигация или комментарии.

Описание всех методов

Установка BeautifulSoup в Python

Для установки необходимых модулей используется команда pip3. Для начала требуется установить lxml модуль, который используется в BeautifulSoup.

$ sudo pip3 install lxml

BeautifulSoup устанавливается при помощи использования указанной ниже команды.

$ sudo pip3 install bs4

Пример HTML-кода страницы

В последующих примерах будет использован данный 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 простой пример парсинга 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>

Это результат вывода.

BeautifulSoup теги, атрибуты name и text

Атрибут 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

Это результат вывода.

BeautifulSoap перебираем HTML теги

Метод 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-документа.

BeautifulSoup атрибут children

При помощи атрибута 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.

BeautifulSoup атрибут descendants

При помощи атрибута 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.

BeautifulSoup и веб-скрапинг HTML

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>

Это результат вывода.

BeautifulSoup метод prettify()

При помощи метода 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>

Это результат вывода.

BeautifulSoup метод find(), поиск элементов по id

При помощи метода 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. Строка в комментарии является альтернативным способом выполнить то же самое задание.

BeautifulSoup метод find_all() поиск всех тегов в HTML

При помощи метода 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.

Это результат вывода.

BeautifulSoup методы select() и select_one() CSS селекторы

При помощи методов 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.

find_parent и find_parents

Возвращает ближайшего родителя этого тега, который соответствует заданным критериям.

 BeautifulSoup.find_parent(name=None, attrs={}, **kwargs)

Возвращает родителей этого тега, которые соответствуют заданным критериям.

BeautifulSoup.findParents(name=None, attrs={}, limit=None, **kwargs)

find_next_sibling и find_previous_sibling

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

BeautifulSoup.find_next_sibling(name=None, attrs={}, text=None, **kwargs)

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

BeautifulSoup.find_previous_sibling(name=None, attrs={}, text=None, **kwargs)

BeautifulSoup метод append() добавление нового HTML-тега

Метод 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 выводится аккуратно отформатированным.

BeautifulSoup метод insert() вставка HTML-тега

Метод 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 теге.

BeautifulSoup метод replace_with() замена текста в теге

Метод 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(), заменить его содержимое.

BeautifulSoup метод decompose() удаление HTML-тега

Метод 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