Sfortunatamente, quando si tenta di associare un'espressione regolare a un valore di attributo di classe che contiene più classi, BeautifulSoup
applicherà l'espressione regolare a ogni singola classe separatamente. Qui ci sono i temi rilevanti sul problema:
Questo è tutto, perché class
is a very special multi-valued attribute e ogni volta che analizzare HTML, uno dei costruttori di albero s' il BeautifulSoup
(a seconda della scelta del parser) divide internamente un valore di stringa di classe in un elenco di classi (citazione dalla docstring di HTMLTreeBuilder
):
# The HTML standard defines these attributes as containing a
# space-separated list of values, not a single value. That is,
# class="foo bar" means that the 'class' attribute has two values,
# 'foo' and 'bar', not the single value 'foo bar'. When we
# encounter one of these attributes, we will parse its value into
# a list of values if possible. Upon output, the list will be
# converted back into a string.
ci sono più soluzioni alternative, ma qui è un hack-ish uno - ci accingiamo a chiedere BeautifulSoup
di non gestire class
come un attributo con più valori, rendendo il nostro semplice costruttore di albero personalizzato:
import re
from bs4 import BeautifulSoup
from bs4.builder._htmlparser import HTMLParserTreeBuilder
class MyBuilder(HTMLParserTreeBuilder):
def __init__(self):
super(MyBuilder, self).__init__()
# BeautifulSoup, please don't treat "class" specially
self.cdata_list_attributes["*"].remove("class")
bs = """<a class="name-single name692" href="www.example.com"">Example Text</a>"""
bsObj = BeautifulSoup(bs, "html.parser", builder=MyBuilder())
found_elements = bsObj.find_all("a", class_=re.compile(r"^name\-single name\d+$"))
print(found_elements)
In questo caso l'espressione regolare verrebbe applicata a un valore di attributo class
nel suo complesso.
In alternativa, si può solo analizzare il codice HTML con xml
funzioni abilitate (laddove prevista):
soup = BeautifulSoup(data, "xml")
È anche possibile utilizzare CSS selectors e abbinare tutti gli elementi con name-single
classe e una classe staring con "nome":
soup.select("a.name-single,a[class^=name]")
Yo u può quindi applicare l'espressione regolare manualmente, se necessario:
pattern = re.compile(r"^name-single name\d+$")
for elm in bsObj.select("a.name-single,a[class^=name]"):
match = pattern.match(" ".join(elm["class"]))
if match:
print(elm)
Sì, perché la classe attributo valori vengono trattati come liste/array di valori separati con lo spazio. –
Beh, ho cercato una soluzione una volta, ma non ho potuto. Suggerisco solo di farlo in 2 passaggi: 1) ottenere tutti gli ancore con la classe "name-single" e 2) ottenere quelli che corrispondono anche alla regex '^ name \ d * $'. –
FYI, ha creato un follow-up e una domanda più generica sulla gestione dell'attributo 'class': [Disabilita la gestione dell'attributo" class "speciale] (http://stackoverflow.com/questions/34295928/disable-special-class-attribute -la gestione). – alecxe