Запутался в методах импорта bs4 и их влиянии на атрибуты

Я знаю, что версии этого вопроса задавались в прошлом, но я все еще в замешательстве и хотел бы развеять свои сомнения раз и навсегда, если это возможно.

Если я использую

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(). Итак, в этих случаях я должен использовать третий метод импорта? Почему есть разница в первую очередь?

Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
0
0
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это игра в имена, которую вы делаете. Давайте продолжим и заявим, что класс 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.

Спасибо! Мне действительно придется обернуть голову вокруг этого! Но я определенно узнал что-то новое....

Jack Fleeting 11.04.2019 02:01

Другие вопросы по теме