我正在尝试使用python,Requests和BeautifulSoup从HTML页面获取一些信息。
我的问题是我无法通过BeautifulSoup获得关键参数(如“Beginning Stocks”和“Domestic Crush”),因为他们有一个错误的“输入”代理名称。
这很奇怪,因为在网站上他们并没有“破产”。我以前从未见过这个。
<m1_region_group2 region4="World 2/">
<m1_attribute_group2_collection>
<m1_attribute_group2 attribute4="Beginning
Stocks">
<cell cell_value4="77.73"></cell>
</m1_attribute_group2>
<m1_attribute_group2 attribute4="Production">
<cell cell_value4="313.77"></cell>
</m1_attribute_group2>
<m1_attribute_group2 attribute4="Imports">
<cell cell_value4="133.33"></cell>
</m1_attribute_group2>
<m1_attribute_group2 attribute4="Domestic
Crush">
<cell cell_value4="275.36"></cell>
</m1_attribute_group2>
<m1_attribute_group2 attribute4="Domestic
Total">
<cell cell_value4="314.35"></cell>
</m1_attribute_group2>
<m1_attribute_group2 attribute4="Exports">
<cell cell_value4="132.55"></cell>
</m1_attribute_group2>
<m1_attribute_group2 attribute4="Ending
Stocks">
<cell cell_value4="77.92"></cell>
</m1_attribute_group2>
</m1_attribute_group2_collection>
</m1_region_group2>
“进口”和“生产”的论点运作良好。例如:
x.find("m1_attribute_group2", {"attribute4":"Imports"}).find("cell")["cell_value4"]
它返回'133.33'。
但是当我试图获得国内总计时,结果是“无”,就像BS无法找到参数一样。
z = x.find("m1_attribute_group2", {"attribute4":"Domestic Total"})
有谁知道发生了什么?我该如何解决?
Mac OS High Sierra / Python3.6
更保守的方法是甚至不尝试解决问题,而是预处理HTML以消除元素属性中的换行符。巧合的是,这正是the problem we've recently solved here:
In [25]: for tag in soup():
...: tag.attrs = {
...: attr: [" ".join(attr_value.replace("\n", " ").split()) for attr_value in value]
...: if isinstance(value, list)
...: else " ".join(value.replace("\n", " ").split())
...: for attr, value in tag.attrs.items()
...: }
...:
In [26]: soup.find("m1_attribute_group2", {"attribute4":"Domestic Total"})
Out[26]:
<m1_attribute_group2 attribute4="Domestic Total">
<cell cell_value4="314.35"></cell>
</m1_attribute_group2>
这只是一个非格式良好的HTML,BeautifulSoup
仍然能够解析。只是attribute4="Domestic Total"
永远不会真实,因为它不是Domestic
和Total
之间的空间,而是一个换行符。
一种方法是使用find()
方法解决方法,使用a function作为attribute4
属性值,拆分和重新连接,这将有效地删除所有换行符并用空格替换它们:
In [19]: soup.find("m1_attribute_group2", attribute4=lambda x: x and " ".join(x.split()) == "Domestic Total")
Out[19]:
<m1_attribute_group2 attribute4="Domestic
Total">
<cell cell_value4="314.35"></cell>
</m1_attribute_group2>
然后,您可以将其概括为:
def filter_attribute(attr_value):
def f(attr):
return attr and " ".join(attr.split()) == attr_value
return f
并使用:
In [23]: soup.find("m1_attribute_group2", attribute4=filter_attribute("Domestic Total"))
Out[23]:
<m1_attribute_group2 attribute4="Domestic
Total">
<cell cell_value4="314.35"></cell>
</m1_attribute_group2>
另一种方法是使用a regular expression和\s+
作为单词之间的分隔符,其中\s+
表示“包括换行符的一个或多个空格字符”:
In [24]: soup.find("m1_attribute_group2", attribute4=re.compile(r"Domestic\s+Total"))
Out[24]:
<m1_attribute_group2 attribute4="Domestic
Total">
<cell cell_value4="314.35"></cell>
</m1_attribute_group2>
除了alecxe先生已经展示的内容之外,如果您的要求是找到与之前的对相关的任何属性,您也可以执行类似下面的操作:
from bs4 import BeautifulSoup
soup = BeautifulSoup(content,"lxml")
for item in soup.select("m1_region_group2 m1_attribute_group2"):
post = ' '.join(item['attribute4'].split())
if "Beginning Stocks" in post: #try to see if it misses any attribute
val = item.find_next("cell")['cell_value4']
print(val)
结果:
77.73