当父元素在隐式命名空间中时,BeautifulSoup丢失子元素

1 投票
1 回答
765 浏览
提问于 2025-04-17 14:21

我正在用selenium和BeautifulSoup为Nordstrom的网站制作一个屏幕抓取工具。这个网站其实并没有每个标签都放在一个命名空间里,但Firefox的webdriver为了避免混淆,给它创建了一个命名空间(具体来说,网站有一个<html xmlns>标签,这让驱动有点困惑)。
因此,所有内容都放在了命名空间a0里。不过,使用Beautiful Soup的find()方法时,它只会返回父元素和(有时)一层子元素。
举个例子,这段html是这样的:

<div class='division'>
   <a href='#'>
      <img />
   </a>
</div>

所有内容都在隐含的a0命名空间中,所以我们可以用以下方式获取图片:

soup.find('a0:div',{'class':'division'}).find('a0:img')

但是,这样返回的是None。我查看了soup.prettify(),可以肯定a0:img是在a0:div里面。请问这是一个预期的功能(那我就需要找其他方法)还是一个bug(那我就需要找到解决办法)?

编辑

为了避免混淆,这里有一个示例,展示整个工作流程:

from selenium import webdriver
from BeautifulSoup import BeautifulSoup # Note that this is BeautifulSoup 3
b = webdriver.Firefox()
b.get("http://shop.nordstrom.com/c/womens-skirts")
borscht = BeautifulSoup(b.page_source)
theImageThatCannotBeFound = borscht.find('a0:div',{'class':'fashion-item'}).find('a0:img')

上面的代码将theImageThatCannotBeFound设置为None,我认为这是不对的。希望这样能让事情更清楚。

1 个回答

2

这个方法对我有效。

import urllib
from BeautifulSoup import BeautifulSoup

url = 'http://shop.nordstrom.com/c/womens-skirts'
fp = urllib.urlopen(url)
soup = BeautifulSoup(fp)

print soup.find('div',{'class':'fashion-item'}).findAll('img') # also tried .find

试着去掉a0:。这似乎就是你遇到的问题所在。

编辑:

我在使用Chrome和Firefox浏览器时,无论是在Selenium里面还是外面,查看时xmlns都是空字符串,这就是为什么上面的代码对我有效。看起来是某个组件不匹配,导致我们得到的结果不一样,而你得到了命名空间a0:

因为我无法重现这个情况,我能找到的唯一解决办法(虽然有点笨拙)就是手动替换命名空间:

source = browser.page_source.replace('a0:div','div')
soup = BeautifulSoup(source)

print soup.find('div',{'class':'fashion-item'}).find('img')

我承认这并不是一个理想的解决方案。如果我找到更好的方法,我会继续寻找并更新我的回答。

撰写回答