Почему BeautifulSoup не находит конкретный класс таблицы?

Я использую Beautiful Soup, чтобы попробовать и очистить таблицу товаров от Oil-Price.net. Я могу найти первый div, стол, тело таблицы и строки тела таблицы. Но в одной из строк есть столбец, который я не могу найти, используя красивый суп. Когда я говорю python для печати всех таблиц в этой конкретной строке, он не отображает тот, который я хочу. Это мой код:

from urllib2 import urlopen from bs4 import BeautifulSoup html = urlopen('http://oil-price.net').read() soup = BeautifulSoup(html) div = soup.find("div",{"id":"cntPos"}) table1 = div.find("table",{"class":"cntTb"}) tb1_body = table1.find("tbody") tb1_rows = tb1_body.find_all("tr") tb1_row = tb1_rows[1] td = tb1_row.find("td",{"class":"cntBoxGreyLnk"}) print td 

Все, что он печатает, – None. Я даже пытаюсь напечатать каждую из строк, чтобы увидеть, могу ли я найти столбец вручную и ничего. “ Он покажет другим. Но не тот, который я хочу.

2 Solutions collect form web for “Почему BeautifulSoup не находит конкретный класс таблицы?”

На странице используется разбитый HTML-код, и разные парсеры будут пытаться восстановить его по-разному. Установите парсер lxml , он лучше анализирует эту страницу:

 >>> BeautifulSoup(html, 'html.parser').find("div",{"id":"cntPos"}).find("table",{"class":"cntTb"}).tbody.find_all("tr")[1].find("td",{"class":"cntBoxGreyLnk"}) is None True >>> BeautifulSoup(html, 'lxml').find("div",{"id":"cntPos"}).find("table",{"class":"cntTb"}).tbody.find_all("tr")[1].find("td",{"class":"cntBoxGreyLnk"}) is None False 

Глядя на источник страницы:

 <td class="cntBoxGreyLnk" rowspan="2" valign="top"> <script type="text/javascript" src="http://www.oil-price.net/COMMODITIES/gen.php?lang=en"></script> <noscript> To get live <a href="http://www.oil-price.net/dashboard.php?lang=en#COMMODITIES">gold, oil and commodity price</a>, please enable Javascript.</noscript> 

данные, которые вы хотите, динамически загружаются на страницу; вы не можете получить его с помощью BeautifulSoup, потому что он не существует в HTML.

Если вы посмотрите ссылку на связанный скрипт по адресу http://www.oil-price.net/COMMODITIES/gen.php?lang=en, вы увидите кучу javascript, например

 document.writeln('<table summary=\"Crude oil and commodity prices (c) http://oil-price.net\" style=\"font-family: Lucida Sans Unicode, Lucida Grande, Sans-Serif; font-size: 12px; background: #fff; border-collapse: collapse; text-align: left; border-color: #6678b1; border-width: 1px 1px 1px 1px; border-style: solid;\">'); document.writeln('<thead>'); /* ... */ document.writeln('<tr>'); document.writeln('<td style=\"font-size: 12px; font-weight: bold; border-bottom: 1px solid #ccc; color: #1869bd; padding: 2px 6px; white-space: nowrap;\">'); document.writeln('<a href=\"http://oil-price.net/dashboard.php?lang=en#COMMODITIES\" style=\"color: #1869bd; text-decoration:none\">Heating Oil<\/a>'); document.writeln('<\/td>'); document.writeln('<td style=\"font-size: 12px; font-weight: normal; border-bottom: 1px solid #ccc; color: #000000; padding: 2px 6px; white-space: nowrap;\">'); document.writeln('3.05'); document.writeln('<\/td>'); document.writeln('<td style=\"font-size: 12px; font-weight: normal; border-bottom: 1px solid #ccc; color: green; padding: 2px 6px; white-space: nowrap;\">'); document.writeln('+1.81%'); document.writeln('<\/td><\/tr>'); 

Когда страница загружается, этот javascript запускается и динамически записывается в значения, которые вы ищете. (В стороне: это совершенно архаичный, оскорбленный и, как правило, ужасный способ делать вещи, я могу только предположить, что кто-то думает об этом как о дополнительном уровне безопасности. Они заслуживают наказания за их безрассудство! ).

Теперь этот код довольно прямолинейный; вы могли бы, вероятно, захватить html-данные с регулярным выражением. Но (а) есть некоторые escape-коды, которые могут вызвать проблемы, (б) нет никакой гарантии, что они не могут запутать свой код в будущем, и (c) где это забавно?

Модуль PyV8 обеспечивает прямолинейный метод выполнения кода javascript из Python и даже позволяет нам писать код Python, вызываемый javascript! Мы воспользуемся этим, чтобы получить данные в несовместимом виде:

 import PyV8 import requests from bs4 import BeautifulSoup SCRIPT = "http://www.oil-price.net/COMMODITIES/gen.php?lang=en" class Document: def __init__(self): self.lines = [] def writeln(self, s): self.lines.append(s) @property def content(self): return '\n'.join(self.lines) class DOM(PyV8.JSClass): def __init__(self): self.document = Document() def main(): # Create a javascript context which contains # a document object having a writeln method. # This allows us to capture the calls to document.writeln() dom = DOM() ctxt = PyV8.JSContext(dom) ctxt.enter() # Grab the javascript and execute it js = requests.get(SCRIPT).content ctxt.eval(js) # The result is the HTML code you are looking for html = dom.document.content # html is now "<table> ... </table>" containing the data you are after; # you can go ahead and finish parsing it with BeautifulSoup tbl = BeautifulSoup(html) for row in tbl.findAll('tr'): print(' / '.join(td.text.strip() for td in row.findAll('td'))) if __name__ == "__main__": main() 

Это приводит к:

 Crude Oil / 99.88 / +2.04% Natural Gas / 4.78 / -3.27% Gasoline / 2.75 / +2.40% Heating Oil / 3.05 / +1.81% Gold / 1263.30 / +0.45% Silver / 19.92 / +0.06% Copper / 3.27 / +0.37% 

которые вы хотите.

Изменить: я больше не могу его опустить; это мертвый минимальный код, который выполняет эту работу. Но, может быть, мне лучше объяснить, как это работает (это действительно не так страшно, как кажется!):

Модуль PyV8 обертывает интерпретатор JavaScript V8 от Google таким образом, что Python может взаимодействовать с ним. Вам нужно будет перейти на https://code.google.com/p/pyv8/downloads/list для загрузки и установки соответствующей версии, прежде чем вы сможете запустить мой код.

Сам язык javascript ничего не знает о том, как взаимодействовать с внешним миром; он не имеет встроенных методов ввода или вывода. Это не очень полезно. Чтобы решить эту проблему, мы можем перейти в «контекстный объект», который содержит информацию о внешнем мире и как взаимодействовать с ним. Когда javascript запускается в веб-браузере, он получает объект контекста, который предоставляет все виды информации о браузере и текущей веб-странице и о том, как с ними взаимодействовать.

Код javascript из http://www.oil-price.net/COMMODITIES/gen.php?lang=en предполагает, что он будет запущен в браузере, где контекст имеет объект «документ», представляющий веб-страницу, который имеет метод «writeln», который добавляет текст в текущий конец веб-страницы. Когда страница загружается, скрипт загружается и запускается; он записывает текст (который, как раз, является действительным HTML) на страницу; это становится отображаемым как часть страницы, заканчивая как таблица товаров, которую вы хотели. Вы не можете получить таблицу с BeautifulSoup, потому что таблица не существует до запуска javascript, а BeautifulSoup не загружает и не запускает javascript.

Мы хотим запустить javascript; для этого нам нужен фальшивый контекст браузера, который имеет объект «document» с методом «writeln». Затем нам нужно сохранить информацию, которая передается в «writeln», и нам нужен способ вернуть ее, когда скрипт закончен. Мой класс DOM – это поддельный контекст браузера; при создании экземпляра (т. е. когда мы делаем один из них), он дает объект Document, называемый документом, который имеет метод writeln. Когда вызывается document.writeln, он добавляет строку текста в document.lines, и в любое время мы можем вызвать document.content, чтобы вернуть весь текст, написанный до сих пор.

Теперь: действие! В основной функции мы создаем фальшивый контекст браузера, устанавливаем его как текущий контекст интерпретатора и запускаем интерпретатор. Мы захватим код javascript и попросим интерпретатора оценить (т.е. запустить) его. (Обфускация исходного кода, которая может испортить статический анализ, не повлияет на нас, потому что код должен выдавать хороший результат при запуске, и мы фактически запускаем его!) Как только код будет закончен, мы получим окончательный вывод из документа .context; это таблица html, которую вы не смогли получить. Мы передаем это обратно в BeautifulSoup, чтобы вытащить данные, а затем распечатать данные.

Надеюсь, это поможет!

  • Загрузите изображения из Google image search (python)
  • Beautifulsoup findall застревает без обработки
  • как извлечь текст в теге font с помощью beautifulsoup
  • Потрясающая кнопка кнопки Selenium Python
  • Ошибка импорта BeautifulSoup
  • Python 2.7 Прекрасная очистка электронной почты BeautifulSoup до завершения полной базы данных
  • Извлечение изображения src на основе атрибута с помощью BeautifulSoup
  • Как перемещаться по HTMl-страницам, которые имеют пейджинг для своего контента с помощью Python?
  • Неправильная дата, связанная с ранним утром, соскоблила с веб-сайта погоды (Python) + только данные за январь?
  • Ошибка HTTP 999: запрос отклонен
  • Как найти определенный атрибут данных из тега html в BeautifulSoup4?
  • Python - лучший язык программирования в мире.