Python Beautiful Soup - 根据HTML中的文本查找值

时间:2016-03-08 15:13:24

标签: python html beautifulsoup python-requests

我在根据文字找到汤中的值时遇到问题。这是代码

from bs4 import BeautifulSoup as bs
import requests
import re

html='http://finance.yahoo.com/q/ks?s=aapl+Key+Statistics'
r = requests.get(html)
soup = bs(r.text)
findit=soup.find("td", text=re.compile('Market Cap'))

这会返回[],但“td”中绝对有文字。标记为' Market Cap'。 当我使用

soup.find_all("td")

我得到的结果集包括:

<td class="yfnc_tablehead1" width="74%">Market Cap (intraday)<font size="-1"><sup>5</sup></font>:</td>

3 个答案:

答案 0 :(得分:2)

<强>解释

问题是这个特定的标签有其他子元素,.string值在应用文本参数时被检查,是None(bs4记录了here) 。

<强>解决方案/解决方法:

此处不要指定标记名称,找到文本节点并转到父级:

soup.find(text=re.compile('Market Cap')).parent.get_text()

或者,如果td不是文本节点的直接父级,则可以使用find_parent()

soup.find(text=re.compile('Market Cap')).find_parent("td").get_text()

您还可以使用"search function"搜索td标记,并查看直接文本子节点是否包含Market Cap文本:

soup.find(lambda tag: tag and
                      tag.name == "td" and
                      tag.find(text=re.compile('Market Cap'), recursive=False))

或者,如果您希望找到以下号码5

soup.find(text=re.compile('Market Cap')).next_sibling.get_text()

答案 1 :(得分:2)

您无法在标记中使用正则表达式。它不会起作用。不知道这是否是规范的错误。我只是搜索,然后让父母回到列表理解中,因为“td”“regex”会给你td标签。

<强>代码

from bs4 import BeautifulSoup as bs
import requests
import re

html='http://finance.yahoo.com/q/ks?s=aapl+Key+Statistics'
r = requests.get(html)
soup = bs(r.text, "lxml")

findit=soup.find_all(text=re.compile('Market Cap'))
findit=[x.parent for x in findit if x.parent.name == "td"]
print(findit)

<强>输出

[<td class="yfnc_tablehead1" width="74%">Market Cap (intraday)<font size="-1"><sup>5</sup></font>:</td>]

答案 2 :(得分:0)

正则表达式是整合到解析代码中的一个可怕的事情,我认为应尽可能避免使用。

就个人而言,由于缺乏XPath支持,我不喜欢BeautifulSoup。你想要做的是XPath非常适合的那种东西。如果我正在做你正在做的事情,我会使用lxml进行解析,而不是使用BeautifulSoup内置的解析和/或正则表达式。它真的很优雅,非常快:

from lxml import etree
import requests

source = requests.get('http://finance.yahoo.com/q/ks?s=aapl+Key+Statistics').content
parsed = etree.HTML(source)
tds_w_market_cap = parsed.xpath('//td[contains(., "Market Cap")]')

上述FYI返回一个lxml对象而不是页面源文本。在lxml中,你本身并不直接使用源代码。如果由于某种原因需要返回实际源列表,可以添加如下内容:

print [etree.tostring(i) for i in tds_w_market_cap]

如果您必须使用BeautifulSoup完成此任务,那么我将使用列表理解:

from bs4 import BeautifulSoup as bs
import requests

source = requests.get('http://finance.yahoo.com/q/ks?s=aapl+Key+Statistics').content
parsed = bs(source, 'lxml')
tds_w_market_cap = [i for i in parsed.find_all('td') if 'Market Cap' in i.get_text()]