2015-05-08 2 views
0

я пытаюсь получить некоторые всю HREF URL-адреса из вложенного HTML кода:Python вложенной HTML-теги с BeautifulSoup

... 
<li class="dropdown"> 
<a href="#" class="dropdown-toggle wide-nav-link" data-toggle="dropdown">TEXT_1 <b class="caret"></b></a> 
<ul class="dropdown-menu"> 
<li class="class_A"><a title="Title_1" href="http://www.customurl_1.com">Title_1</a></li> 
<li class="class_B"><a title="Title_2" href="http://www.customurl_2.com">Title_2</a></li> 
... 
<li class="class_A"><a title="Title_X" href="http://www.customurl_X.com">Title_X</a></li> 
</ul> 
</li> 
... 
<li class="dropdown"> 
<a href="#" class="dropdown-toggle wide-nav-link" data-toggle="dropdown">TEXT_2 <b class="caret"></b></a> 
<ul class="dropdown-menu"> 
<li class="class_A"><a title="Title_1" href="http://www.customurl_1.com">Title_1</a></li> 
<li class="class_B"><a title="Title_2" href="http://www.customurl_2.com">Title_2</a></li> 
... 
<li class="class_A"><a title="Title_X" href="http://www.customurl_X.com">Title_X</a></li> 
</ul> 
</li> 
... 

В оригинальном HTML коде есть около 15 «Ли» блоков с классом «выпадающим список ", , но я хочу получить только URL-адреса из блока с текстом = TEXT_1. Можно ли захватить все эти вложенные URL с помощью BeautifulSoup?

Спасибо за помощь

+0

Нельзя использовать регулярное выражение; используйте [парсер HTML] (http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454). – Docteur

+0

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

+0

Независимо от того, что плавает ваша лодка - вы ** можете ** использовать регулярное выражение, но вы ** не должны **. – Docteur

ответ

0

Пример с LXML и Xpath:

from lxml import etree 
from io import StringIO 

parser = etree.HTMLParser() 
tree = etree.parse(StringIO(html), parser) 
hrefs = tree.xpath('//li[@class="dropdown" and a[starts-with(.,"TEXT_1")]]/ul[@class="dropdown-menu"]/li/a/@href') 

print hrefs 

Где html это юникод строку с содержимым HTML. Результат:

['http://www.customurl_1.com', 'http://www.customurl_2.com', 'http://www.customurl_X.com'] 

Примечание: Я использую функцию starts-with, чтобы быть более точным в запросе XPath, но вы можете использовать contains в точно так же, если TEXT_1 не всегда в начале текстового узла.

Детали запроса:

//    # anywhere in the domtree 
li    # a li tag with the following conditions: 
[        # (opening condition bracket for li) 
    @class="dropdown"   # li has a class attribute equal to "dropdown" 
    and       # and 
    a       # a child tag "a" 
    [       # (open a condition for "a") 
     starts-with(.,"TEXT_1") # that the text starts with "TEXT_1" 
    ]       # (close a condition for "a") 
]        # (close the condition for li) 
/       # li's child (/ stands for immediate descendant) 
ul[@class="dropdown-menu"] # "ul" with class equal to "dropdown-menu" 
/li       # "li" children of "ul" 
/a       # "a" children of "li" 
/@href      # href attributes children of "a" 
+0

Perfect !! Спасибо! – Reat0ide

0

Пока не столь элегантно, как Xpath, вы всегда можете написать логику с использованием повседневной Python итерации. BeautifulSoup позволяет передавать функцию как фильтр в find_all в ситуациях, когда у вас есть сложный случай, такой как этот.

from bs4 import BeautifulSoup 

html_doc = """<html>...""" 
soup = BeautifulSoup(html_doc) 

def matches_block(tag): 
    return matches_dropdown(tag) and tag.find(matches_text) != None 

def matches_dropdown(tag): 
    return tag.name == 'li' and tag.has_attr('class') and 'dropdown' in tag['class'] 

def matches_text(tag): 
    return tag.name == 'a' and tag.get_text().startswith('TEXT_1') 

for li in soup.find_all(matches_block): 
    for ul in li.find_all('ul', class_='dropdown-menu'): 
     for a in ul.find_all('a'): 
      if a.has_attr('href'): 
       print (a['href'])