Python BeautifulSoup在XML标记中引用空格的标记

问题描述:

对于我格式不当的帖子和书面代码的道歉,第一篇文章!我确信这是一个简单的修复,但似乎无法弄清楚。Python BeautifulSoup在XML标记中引用空格的标记

问题1:我正在为Eve Online API编写一个XML刮取器。我需要在其中包含空格的HTML标记(type id="X")上迭代*BeautifulSoup*。我想遍历XML中的项目ID标记(本例中为2)。我不确定*Data.iter*是否正确。我知道打印Data.buy将在XML中找到第一个购买标签,并打印这些孩子,但无法找到打印第一个数据的相同方法。 'type id="x"'

问题2:任何关于如何继续刮擦过程的方向都是值得欢迎的。我正在考虑将不同物品ID和买入/卖出订单的不同存储空间导出到某种存储(认为是CSV文件,但不是正面)。

import requests #Used to service API connection 
from lxml import html #Used to parse XML 
from bs4 import BeautifulSoup #Used to read XML table on webpage 

ItemTypeID1 = 34 
ItemTypeID2 = 35 
RegionID = 10000002 

Webpage = requests.get('http://api.eve-central.com/api/marketstat?typeid=%i&typeid=%i&regionlimit=%i' % (ItemTypeID1, ItemTypeID2, RegionID)) 
#Check if page is up 
if Webpage.status_code == 200: 
#Convert webpage to %Data 
     Data = BeautifulSoup(Webpage.text, 'lxml') 

     #Problem line 
     for item in Data.iter('type id='): 
      print 'something' 

http://api.eve-central.com/api/marketstat?typeid=34&typeid=35&regionlimit=10000002

<?xml version='1.0' encoding='utf-8'?> 
<evec_api version="2.0" method="marketstat_xml"> 
     <marketstat><type id="34"> 
      <buy><volume>21648183554</volume><avg>5.34</avg><max>5.78</max><min>2.00</min><stddev>0.83</stddev><median>5.52</median><percentile>5.58</percentile></buy> 
      <sell><volume>15987043271</volume><avg>6.20</avg><max>15.00</max><min>5.58</min><stddev>1.38</stddev><median>6.00</median><percentile>5.85</percentile></sell> 
      <all><volume>37635226825</volume><avg>5.71</avg><max>15.00</max><min>2.00</min><stddev>1.40</stddev><median>5.54</median><percentile>4.16</percentile></all> 
     </type><type id="35"> 
      <buy><volume>4163954948</volume><avg>7.26</avg><max>9.39</max><min>4.02</min><stddev>1.60</stddev><median>6.48</median><percentile>9.24</percentile></buy> 
      <sell><volume>10154431073</volume><avg>11.84</avg><max>17.41</max><min>9.00</min><stddev>1.80</stddev><median>10.59</median><percentile>9.46</percentile></sell> 
      <all><volume>14318386021</volume><avg>10.51</avg><max>17.41</max><min>4.02</min><stddev>2.21</stddev><median>10.00</median><percentile>5.87</percentile></all> 
     </type></marketstat> 
    </evec_api> 
+0

你为什么要导入lxml然后不使用它? bs4使用lxml作为解析器,所以我不知道你为什么使用bs4 –

+0

先生,这是我的第一个python项目,我正在进行大量的谷歌搜索,阅读,学习等。我在网上看到一个例子,使用BS4,这是我所知道的,你知道吗?发布类似这样的地方让其他程序员可以让我了解我不能谷歌的东西 - 你不知道你不知道的东西,而且我不知道我可以完全跳过BS4! –

+0

lxml.html用于解析html或实际上是lxml,lxml.etree是用于xml的。 Bs4是非常用户友好和一个很好的lib,但lxml有完整的xpath 1.0,几乎不是所有的css3选择器http://packages.python.org/cssselect/#supported-selectors。 –

type id=不是一个标签。元素的标签名称是type,而id是该元素的属性

for item in Data.find_all('type'): 
    print item.get('id') 

对于您参考该代码的URL将输出:

 
34 
35 

的代码只是找到与标签名称“类型”的所有元素,并显示找到的每个标签的id属性。

您可以访问包含在嵌套buysell标签中的数据:

for item in Data.find_all('type'): 
    print item.get('id') 
    volume = item.buy.volume.text 
    avg = item.buy.volume.text 
    # etc. 

它展示了如何在包含在数量和平均标签为每个项目中的数据得到。


还有一个JSON API访问,这可能是更容易使用,特别是使用requests模块时:

import requests 

url = 'http://api.eve-central.com/api/marketstat/json' # the JSON endpoint 
params = {'typeid': (34, 35), 'RegionID': 10000002} 
r = requests.get(url, params=params) 
data = r.json() 

这给了你Python字典的名单一起工作:

for type_ in data: 
    print '{}: volume = {}, avg = {}'.format(type_['buy']['forQuery']['types'][0], type_['buy']['volume'], type_['buy']['avg']) 
 
34: volume = 110242267166, avg = 4.29419161677 
35: volume = 40908217125, avg = 6.71507628294 

尽管从JSON响应中获取类型id有点awkwar d与XML相比较。

+0

有没有一个方向可以让我找到某种数据类型下隐藏的项目?比如:'item.buy.volume.text'的'.text'部分据我所知,你使用'.buy.volume'来行走XML值,但是没有'text'标签可以看到? –

+0

'item.buy.volume'是一个'bs4.element.Tag1'对象的实例。 'text'是该对象的一个​​属性。这是BeautifulSoup以标识字符串的形式访问标签内容的方式,例如内容是'1234'。 – mhawke

你有几个问题,你似乎是混合了BS4LXML语法,ITER是lxml的方法,是节点和ID是节点的属性。

由于您使用LXML忘掉BS4和得到的数据是相当简单:

from lxml import html # Used to parse XML 

ItemTypeID1 = 34 
ItemTypeID2 = 35 
RegionID = 10000002 

webpage = requests.get('http://api.eve-central.com/api/marketstat?typeid=%i&typeid=%i&regionlimit=%i' % (
ItemTypeID1, ItemTypeID2, RegionID)) 

if webpage.status_code == 200: 
    data = html.fromstring(webpage.content) 
    for item in data.iter('type'): 
     print(item.get("id")) # print node attribute id value. 

     buy_dict = {node.tag: node.text for node in item.xpath("buy/*")} 
     sell_dict = {node.tag: node.text for node in item.xpath("sell/*")} 
     print(buy_dict) 
     print(sell_dict) 

这会给你:

34 
{'min': '2.00', 'max': '5.81', 'median': '5.54', 'volume': '22518685011', 'percentile': '5.72', 'stddev': '0.80', 'avg': '5.37'} 
{'min': '5.57', 'max': '15.00', 'median': '6.00', 'volume': '14953114542', 'percentile': '5.78', 'stddev': '1.38', 'avg': '6.21'} 
35 
{'min': '4.02', 'max': '9.20', 'median': '6.65', 'volume': '4170891614', 'percentile': '9.20', 'stddev': '1.59', 'avg': '7.25'} 
{'min': '8.90', 'max': '17.41', 'median': '10.59', 'volume': '10089810619', 'percentile': '9.44', 'stddev': '1.84', 'avg': '11.83'} 

然后写入到CSV:

import requests # Used to service API connection 
from lxml import html # Used to parse XML 
from csv import DictWriter 

ItemTypeID1 = 34 
ItemTypeID2 = 35 
RegionID = 10000002 

webpage = requests.get('http://api.eve-central.com/api/marketstat?typeid=%i&typeid=%i&regionlimit=%i' % (
ItemTypeID1, ItemTypeID2, RegionID)) 

if webpage.status_code == 200: 
    with open("data.csv", "w") as f: 
     wr = DictWriter(f, fieldnames=["buy/sell", 'volume', 'min', 'max', 'median', 'percentile', 'stddev', 'avg']) 
     wr.writeheader() 
     data = html.fromstring(webpage.content) 
     for item in data.iter('type'): 
      buy_dict = {node.tag: node.text for node in item.xpath("buy/*")} 
      buy_dict["buy/sell"] = "buy" 
      sell_dict = {node.tag: node.text for node in item.xpath("sell/*")} 
      sell_dict["buy/sell"] = "sell" 
      wr.writerows([buy_dict, sell_dict]) 

这会给你:

buy/sell,volume,min,max,median,percentile,stddev,avg 
buy,22518685011,2.00,5.81,5.54,5.72,0.80,5.37 
sell,14953114542,5.57,15.00,6.00,5.78,1.38,6.21 
buy,4170891614,4.02,9.20,6.65,9.20,1.59,7.25 
sell,10089810619,8.90,17.41,10.59,9.44,1.84,11.83 
+0

我很喜欢这个。 DictWriter对我和lxml都是全新的。如果我想将我的CSV文件分成单独的每个单独项目ID的买卖订单,您有任何建议吗? –

+0

只需创建用于购买和出售的文件和DictReaders,然后使用完全相同的逻辑写入相应的文件 –