Я знаю, что версии этого вопроса задавались в прошлом, но я все еще в замешательстве и хотел бы развеять свои сомнения раз и навсегда, если это возможно.
Если я использую
from bs4 import BeautifulSoup
мое soup
задание будет
soup = BeautifulSoup(html, "lxml")
Если я сделаю импорт таким образом:
from bs4 import BeautifulSoup as bs4
мое soup
задание
soup = bs4(html, "lxml")
Наконец, если я импортирую с помощью:
import bs4
мое soup
задание
soup = bs4.BeautifulSoup(html, "lxml")
Давайте использовать простой HTML и код:
html = """
<a href = "some link" style = "some style">Some Document</a>
"""
link = soup.select('a:contains(Document)')
Далее главный вопрос:
type(link[0])
Выход - во всех трех случаях импорта - это:
bs4.element.Tag
Но если я спрошу:
isinstance(link[0],bs4.element.Tag)
В третьем случае я получаю True
, а в первых двух случаях я получаю
AttributeError: type object 'BeautifulSoup' has no attribute 'element'
Поскольку методы select()
и find_all()
часто дают результаты как Tag
, так и NavigableString
, мне нужно определить, что есть что, используя, например, isinstance()
. Итак, в этих случаях я должен использовать третий метод импорта? Почему есть разница в первую очередь?
Это игра в имена, которую вы делаете. Давайте продолжим и заявим, что класс bs4.element.Tag
— это класс экземпляров элементов. Думайте об этом как об абсолютном расположении класса Tag
в bs4
. bs4.element
представляет вложенные модули, где Tag
(который находится под модулем element
) является классом, экземплярами которого являются элементы. При отображении информации о классе этих элементов всегда будет отображаться bs4.element.Tag
.
Теперь, после всего сказанного, вы можете получить доступ к объекту BeautifulSoup
разными способами. И ничто из этого не меняет того факта, что теги элементов относятся к типу bs4.element.Tag
. При импорте bs4:
import bs4
bs4.BeautifulSoup()
Это импортирует модуль под именем модуля по умолчанию bs4
. И тогда вы можете получить доступ к BeautifulSoup
в этом модуле с помощью записи через точку, поскольку BeautifulSoup
является членом этого модуля. Но локально bs4
— это просто переменная, которая ссылается на модуль bs4
.
При импорте как:
from bs4 import BeautifulSoup as bs4
bs4
не означает то же самое, что и первый пример. В первом примере мы импортировали весь модуль под его именем по умолчанию (bs4
), но здесь вместо этого мы импортируем класс BeautifulSoup
и переименовываем его локально в bs4
. Независимо от того, как мы его называем локально, это все равно класс в bs4.BeautifulSoup
, где bs4
— имя модуля. Однако локально (локально для этого файла) мы создали ссылку на переменную класса BeautifulSoup
с именем, которое совпадает с именем модуля.
Итак, когда вы используете select
для возврата элементов, они относятся к типу bs4.element.Tag
. Это верно независимо от того, как называются ваши локальные переменные. Это внутренне, как они известны.
Итак, при сравнении instance
важно знать, имя переменной не важно, важно то, на что ссылается переменная. В третьем примере import bs4
заставляет bs4
ссылаться на модуль bs4
; поэтому к Tag
можно получить доступ по адресу bs4.element.Tag
. Но в случае, когда вы используете from bs4 import BeautifulSoup as bs4
, bs4
больше не ссылается на модуль bs4
, он ссылается на класс BeautifulSoup
, у которого нет атрибутов, называемых element
, с атрибутом Tag
, поскольку это не модуль, а класс.
Локальное имя — это то, как ваш текущий файл ссылается на объект, на который он ссылается.
Таким образом, в ваших неудачных случаях вам нужно будет импортировать ссылку Tag
на переменную, которую вы можете предоставить instance
:
>>> from bs4 import BeautifulSoup
>>> from bs4.element import Tag
>>> soup = bs4.BeautifulSoup('<div>Test<span>test</span><span>test2</span></div>')
>>> isinstance(soup.find('div'), Tag)
True
Tag
здесь просто имя, но оно ссылается на bs4.element.Tag
, так что работает.
Мы могли бы назвать его как угодно, и он все равно будет работать, пока ссылается на правильный объект:
>>> from bs4 import BeautifulSoup
>>> from bs4.element import Tag as Apple
>>> soup = bs4.BeautifulSoup('<div>Test<span>test</span><span>test2</span></div>')
>>> isinstance(soup.find('div'), Apple)
True
Надеюсь, это имеет больше смысла :).
Обновлено: Просто совет, но bs4
делает некоторые ссылки на такие вещи, как NavigableString
и Tag
, доступными в модуле верхнего уровня, поэтому вам не нужно доходить до bs4.element
, чтобы получить правильную ссылку, вы можете просто сделать:
from bs4 import Tag, NavigableString
Опять же, эта альтернативная ссылка на bs4.Tag
— это просто переменная с именем Tag
в модуле bs4
, которая ссылается на реальный класс bs4.element.Tag
. Вы можете использовать это, и оно по-прежнему будет относиться к тому же классу. Он просто используется локально в модуле bs4
для ссылки на класс Tag
в element
.
Спасибо! Мне действительно придется обернуть голову вокруг этого! Но я определенно узнал что-то новое....