【问题标题】:Python BeautifulSoup Referencing Tag with space in XML tagPython BeautifulSoup 在 XML 标记中带有空格的引用标记
【发布时间】:2016-08-15 03:10:55
【问题描述】:

对于我格式错误的帖子和编写的代码,第一次发帖,我们深表歉意!我确定这是一个简单的解决方法,但似乎无法解决。

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

问题 2:欢迎任何关于如何继续抓取过程的指导。我正在考虑将购买/出售/全部导出到某种存储(正在考虑 CSV 文件但不是肯定的),并为不同的项目 ID 和购买/出售订单提供不同的存储。

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>

【问题讨论】:

  • 你为什么要导入 lxml 然后不使用它? bs4 使用 lxml 作为解析器,所以我不知道你为什么使用 bs4
  • 先生,这是我的第一个 python 项目,我要进行很多谷歌搜索、阅读、学习等。我在网上看到了一个使用 BS4 的示例,所以这就是我所知道的,你知道吗?像这样张贴这样的地方让其他程序员让我了解我无法谷歌的东西 - 你不知道你不知道什么,而且我不知道我可以完全跳过 BS4!
  • lxml.html 用于解析 html 或者实际上是 lxml,lxml.etree 用于 xml。 Bs4 非常用户友好并且是一个很棒的库,但是 lxml 有完整的 xpath 1.0 和几乎如果不是所有的 css3 选择器packages.python.org/cssselect/#supported-selectors

标签: python xml beautifulsoup lxml


【解决方案1】:

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

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

对于您引用的 URL,此代码将输出:

34 35

该代码仅查找标签名称为“type”的所有元素,并显示找到的每个标签的id 属性。

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

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

它显示了如何获取每个项目的 volume 和 avg 标签中包含的数据。


还有一个 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:体积 = 110242267166,平均 = 4.29419161677 35:体积 = 40908217125,平均 = 6.71507628294

虽然从 JSON 响应中获取类型 ID 与 XML 相比有点尴尬。

【讨论】:

  • 您有什么方向可以指点我找到数据类型下的隐藏项吗?例如:item.buy.volume.text.text 部分据我了解,您是在使用.buy.volume 来遍历XML 值,但我看不到text 标记?
  • item.buy.volumebs4.element.Tag1 对象的一个​​实例。 text 是该对象的一个​​属性。这是 BeautifulSoup 以 unicode 字符串形式访问标签内容的方式,例如,对于 1234,内容为 1234.
【解决方案2】:

你有几个问题,你似乎混淆了 bs4lxml 语法,iter 是一个 lxml 方法,type 是节点,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

【讨论】:

  • 我非常喜欢这个。 DictWriter 和 lxml 对我来说都是全新的。如果我想为每个单独的项目 ID 将我的 CSV 文件分成单独的买卖订单,你有什么建议吗?
  • 只需为买卖创建文件和 DictReaders,然后使用完全相同的逻辑写入适当的文件
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-18
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 2019-04-07
  • 1970-01-01
相关资源
最近更新 更多