Можно ли использовать xpath с BeautifulSoup?
Я использую BeautifulSoup для очистки URL-адреса, и у меня был следующий код
import urllib
import urllib2
from BeautifulSoup import BeautifulSoup
url = "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
req = urllib2.Request(url)
response = urllib2.urlopen(req)
the_page = response.read()
soup = BeautifulSoup(the_page)
soup.findAll('td',attrs={'class':'empformbody'})
Теперь в приведенном выше коде мы можем использовать findAll
для получения тегов и связанной с ними информации, но я хочу использовать xpath. Можно ли использовать xpath с BeautifulSoup? Если возможно, может ли кто-нибудь указать мне примерный код, чтобы он стал более полезным?
Ответы
Ответ 1
Нет, BeautifulSoup сам по себе не поддерживает выражения XPath.
Альтернативная библиотека lxml поддерживает XPath 1.0. Он имеет совместимый с BeautifulSoup режим, где он будет пытаться анализировать битый HTML, как это делает Soup. Тем не менее, стандартный HTML-анализатор lxml отлично справляется с задачей анализа разбитого HTML, и я считаю, что это быстрее.
Разобрав ваш документ в дерево lxml, вы можете использовать метод .xpath()
для поиска элементов.
try:
# Python 2
from urllib2 import urlopen
except ImportError:
from urllib.request import urlopen
from lxml import etree
url = "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
response = urlopen(url)
htmlparser = etree.HTMLParser()
tree = etree.parse(response, htmlparser)
tree.xpath(xpathselector)
Существует также специальный модуль lxml.html()
с дополнительными функциями.
Обратите внимание, что в приведенном выше примере я передал объект response
непосредственно в lxml
, так как считывание парсера непосредственно из потока более эффективно, чем сначала чтение ответа в большую строку. Чтобы сделать то же самое с библиотекой requests
, вы хотите установить stream=True
и передать объект response.raw
после включения прозрачной декомпрессии транспорта:
import lxml.html
import requests
url = "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
response = requests.get(url, stream=True)
response.raw.decode_content = True
tree = lxml.html.parse(response.raw)
Вас может заинтересовать поддержка CSS Selector; класс CSSSelector
переводит операторы CSS в выражения XPath, что значительно упрощает поиск по td.empformbody
:
from lxml.cssselect import CSSSelector
td_empformbody = CSSSelector('td.empformbody')
for elem in td_empformbody(tree):
# Do something with these table cells.
Полный круг: у самой BeautifulSoup очень полная поддержка селектора CSS:
for cell in soup.select('table#foobar td.empformbody'):
# Do something with these table cells.
Ответ 2
Я могу подтвердить, что в Beautiful Soup нет поддержки XPath.
Ответ 3
Как уже говорили другие, BeautifulSoup не имеет поддержки xpath. Вероятно, есть несколько способов получить что-то из xpath, включая использование Selenium. Однако вот решение, которое работает в Python 2 или 3:
from lxml import html
import requests
page = requests.get('http://econpy.pythonanywhere.com/ex/001.html')
tree = html.fromstring(page.content)
#This will create a list of buyers:
buyers = tree.xpath('//div[@title="buyer-name"]/text()')
#This will create a list of prices
prices = tree.xpath('//span[@class="item-price"]/text()')
print('Buyers: ', buyers)
print('Prices: ', prices)
Я использовал этот в качестве ссылки.
Ответ 4
BeautifulSoup имеет функцию с именем findNext из текущего элемента, направленного на детей, поэтому:
father.findNext('div',{'class':'class_value'}).findNext('div',{'id':'id_value'}).findAll('a')
Выше код может имитировать следующий xpath:
div[class=class_value]/div[id=id_value]
Ответ 5
Я просмотрел их docs, и, похоже, нет опции xpath. Кроме того, как вы можете видеть здесь по аналогичному вопросу о SO, OP просит перевод с xpath на BeautifulSoup, поэтому мой вывод будет - нет, есть Отсутствует синтаксический анализ xpath.
Ответ 6
когда вы используете lxml все просто:
tree = lxml.html.fromstring(html)
i_need_element = tree.xpath('//a[@class="shared-components"]/@href')
но при использовании BeautifulSoup BS4 все тоже просто:
- сначала удалите "//" и "@"
- второе - добавьте звездочку перед "="
попробуй эту магию:
soup = BeautifulSoup(html, "lxml")
i_need_element = soup.select ('a[class*="shared-components"]')
как вы видите, это не поддерживает под-тег, поэтому я удалил часть "/@href"
Ответ 7
Это довольно старый поток, но теперь есть решение для работы, которое, возможно, не было в BeautifulSoup в то время.
Вот пример того, что я сделал. Я использую модуль "запросы" для чтения RSS-канала и получаю его текстовое содержимое в переменной "rss_text". При этом я запускаю его через BeautifulSoup, ища xpath/rss/channel/title и извлекаю его содержимое. Это не совсем XPath во всей красе (подстановочные знаки, несколько путей и т.д.), Но если у вас есть только основной путь, который вы хотите найти, это работает.
from bs4 import BeautifulSoup
rss_obj = BeautifulSoup(rss_text, 'xml')
cls.title = rss_obj.rss.channel.title.get_text()