2015-11-21 3 views
3

Я ожидаю код:BeautifulSoup сканирование HTML с помощью тегов, атрибутов, RegEx, и итерация

html = """ 
<th scope="row">Fruits<br /> 
<i><a href="#Fruits">Buy</a></i></th> 
<td><a href="banana.html" color="yellow">Banana</a><br /> 
    <a href="kiwi.html" color="green">Kiwi</a><br /> 
    <a href="Persimmon" color="orange">Persimmon</a><br /> 
</tr> 
""" 

import re 
from bs4 import BeautifulSoup 

soup = BeautifulSoup(html) 

th_node = soup.find('th', { 'scope' : 'row' }, text = re.compile('^Fruits')) 
td_node = th_node.find('td') 
fruits = td_node.find_all('a') 
for f in fruits: 
    print f['color'], " ", f.text 

Для печати:

yellow banana 
green kiwi 
orange Persimmon 

Что я получаю неправильно?

ответ

2

Вы делаете неправильно, потому что:

th_node = soup.find('th', { 'scope' : 'row' }, text = re.compile('^Fruits')) 
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

От this answer:

Вам нужно будет использовать гибридный подход, поскольку text= потерпит неудачу, когда элемент имеет дочерние элементы, а также текст.

И, например:

>>> a = '<th scope="row">foo</th>' 
>>> b = '<th scope="row">foo<td>bar</td></th>' 
>>> BeautifulSoup(a, "html.parser").find('th', {'scope': 'row'}, text='foo') 
<th scope="row">foo</th> 

>>> BeautifulSoup(b, "html.parser").find('th', {'scope': 'row'}, text='foo') 
>>> BeautifulSoup(b, "html.parser").find('th', {'scope': 'row'}, text='foobar') 

Престол, BeautifulSoup потерпели неудачу, когда есть td тег в th тег. Так что нам нужно (идея также от этого ответа):

html = """ 
<th scope="row">Fruits<br /> 
<i><a href="#Fruits">Buy</a></i></th> 
<td><a href="banana.html" color="yellow">Banana</a><br /> 
    <a href="kiwi.html" color="green">Kiwi</a><br /> 
    <a href="Persimmon" color="orange">Persimmon</a><br /> 
</tr> 
""" 

import re 
from bs4 import BeautifulSoup 

soup = BeautifulSoup(html) 

reg = re.compile(r'^Fruits') 
th_node = [e for e in soup.find_all(
    'th', {'scope': 'row'}) if reg.search(e.text)][0] 

print th_node 

Выход:

<th scope="row">Fruits<br/> 
<i><a href="#Fruits">Buy</a></i></th> 

Да, это вы не хотите, потому что td тег не внутри th тега. Так что теперь мы можем использовать tag.find_next() метод как это:

html = """ 
<th scope="row">Fruits<br /> 
<i><a href="#Fruits">Buy</a></i></th> 
<td><a href="banana.html" color="yellow">Banana</a><br /> 
    <a href="kiwi.html" color="green">Kiwi</a><br /> 
    <a href="Persimmon" color="orange">Persimmon</a><br /> 
</tr> 
""" 

import re 
from bs4 import BeautifulSoup 

soup = BeautifulSoup(html) 

reg = re.compile(r'^Fruits') 
th_node = [e for e in soup.find_all(
    'th', {'scope': 'row'}) if reg.search(e.text)][0] 

td_node = th_node.find_next('td') 
fruits = td_node.find_all('a') 

for f in fruits: 
    print f['color'], " ", f.text 

Выход:

yellow Banana 
green Kiwi 
orange Persimmon 

Тогда мы сделали!

0

Вы можете использовать attrs (просто) или смесь lambda и attrs, если вам нужно text значения узла должны быть проверена только

цен ниже
html = """ 
    <th scope="row">Fruits<br /> 
    <i><a href="#Fruits">Buy</a></i></th> 
    <td><a href="banana.html" color="yellow">Banana</a><br /> 
     <a href="kiwi.html" color="green">Kiwi</a><br /> 
     <a href="Persimmon" color="orange">Persimmon</a><br /> 
    </tr> 
    """ 

import re 
from bs4 import BeautifulSoup 

soup = BeautifulSoup(html) 

th_node = soup.find('th', { 'scope' : 'row' })#OR th_node = soup.find('th', { 'scope' : 'row' },lambda x: x.text.startswith('Fruits')) 
td_node = th_node.findNext('td') 
fruits = td_node.find_all('a') 
for f in fruits: 
    print f['color'], " ", f.text 
0

Вам нужно добавить class к href элементу и правильному исходному коду ниже:

from bs4 import BeautifulSoup 

html = "" 
html += "<table><th scope='row'>Fruits<br /><i><a href='#Fruits'>Buy</a></i></th>" 
html += "<tr><td><a class='fruits' href='banana.html' color='yellow'>Banana</a><br/>" 
html += "<a class='fruits' href='kiwi.html' color='green'>Kiwi</a><br/>" 
html += "<a class='fruits' href='Persimmon' color='orange'>Persimmon</a><br/>" 
html += "</tr></table>" 

soup = BeautifulSoup(html,"html.parser") 
for link in soup.findAll('a',{'class':'fruits'}): 
    col = link.get('color') 
    name = link.string 
    print(col + " " + name) 
0

причина это не работает, потому что beautifulsoup сравнивает ваше регулярное выражение против ничего:

>>> def f(s): 
...  print "comparing", s 
... 
>>> soup.find("th", text=f) 
comparing None 
None 
Смежные вопросы