【问题标题】:Html5 find/parse specific element in page pythonHtml5在页面python中查找/解析特定元素
【发布时间】:2015-08-04 00:11:39
【问题描述】:

我正在尝试学习如何从 html5 网页中查找/解析数据以在数据库中使用。我想学习如何仅从 '//div[@class="col-xs-12 col-sm-6 col-md-4 col-lg-3"]' 的第一个中查找/解析数据

我试过 html5lib,从 lxml 导入 html 和 xpath 但是缺少针对我的特定用途的文档令人沮丧,我真的找不到如何实现这一点。

要查找和存储的数据:

http://csgo.steamanalyst.com/id/120565/ 
from <span class='market-name'><a style='color:white;' href='http://csgo.steamanalyst.com/id/120565/'

And the 2 numbers from "addToCart(1852864,1108)" as id1:'1852864' and id2:'1108'

in <button class='btn btn-orange' type='button' style='font-size:1.2em;margin-top:2px;' id='shopItem1' onclick='addToCart(1852864,1108)'

我正在尝试学习的 html 代码

<!DOCTYPE html> 

<div class='row'><div class='col-xs-12 col-sm-6 col-md-4 col-lg-3'><div class='featured-item'><a class='market-name market-link' href='https://opskins.com/index.php?loc=shop_view_item&item=1852864'>StatTrak&#8482; Desert Eagle | Conspiracy (Factory New)</a><br /><small class='text-muted'>StatTrak&#8482; Classified Pistol</small><img style='margin-top:-25px;' src='256fx256f' />
    <div class='item-add'>
      <div class='item-amount'><span class='icon-logo'></span>1,108</div>
      <div class='market-name' style='padding-bottom:0.3em;'><span class='market-name'><a style='color:white;' href='http://csgo.steamanalyst.com/id/120565/' target='_BLANK'>Suggested Price: <span class='icon-logo'></span>1,451</a></div>
                <div class='item-buttons'><center> class='btn btn-primary' style='margin-right:4px'>Inspect</a><a href ='/?loc=shop_search&sort=lh&StatTrak=1&search_item=+Desert+Eagle+%7C+Conspiracy+%28Factory+New%29' class='btn btn-primary'>Search</a>
                    <br /><button class='btn btn-orange' type='button' style='font-size:1.2em;margin-top:2px;' id='shopItem1' onclick='addToCart(1852864,1108)'>Add to cart</button></center></div>
    </div>
  </div></div><!-- /.col-md-4 --><div class='col-xs-12 col-sm-6 col-md-4 col-lg-3'><div class='featured-item'><a class='market-name market-link' href='https://opskins.com/index.php?loc=shop_view_item&item=1841001'>★ Karambit | Doppler (Factory New)</a><br /><small class='text-muted'>★ Covert Knife</small><img style='margin-top:-25px;' src='256fx256f' />
    <div class='item-add'>
      <div class='item-amount'><span class='icon-logo'></span>155,000</div>
      <div class='market-name' style='padding-bottom:0.3em;'><span class='market-name'><a style='color:white;' href='http://csgo.steamanalyst.com/id/62403692/' target='_BLANK'>Suggested Price: <span class='icon-logo'></span>30,300</a></div>
                <div class='item-buttons'><center> class='btn btn-primary' style='margin-right:4px'>Inspect</a><a href ='/?loc=shop_search&sort=lh&search_item=%E2%98%85+Karambit+%7C+Doppler+%28Factory+New%29' class='btn btn-primary'>Search</a>
                    <br /><button class='btn btn-orange' type='button' style='font-size:1.2em;margin-top:2px;' id='shopItem2' onclick='addToCart(1841001,155000)'>Add to cart</button></center></div>
    </div>
  </div></div><!-- /.col-md-4 --><div class='col-xs-12 col-sm-6 col-md-4 col-lg-3'><div class='featured-item'><a class='market-name market-link' href='https://opskins.com/index.php?loc=shop_view_item&item=1852853'>AK-47 | Redline (Field-Tested)</a><br /><small class='text-muted'>Classified Rifle</small><img style='margin-top:-25px;' src='256fx256f' />
    <div class='item-add'>
      <div class='item-amount'><span class='icon-logo'></span>441</div>
      <div class='market-name' style='padding-bottom:0.3em;'><span class='market-name'><a style='color:white;' href='http://csgo.steamanalyst.com/id/1420/' target='_BLANK'>Suggested Price: <span class='icon-logo'></span>520</a></div>
                <div class='item-buttons'><center> class='btn btn-primary' style='margin-right:4px'>Inspect</a><a href ='/?loc=shop_search&sort=lh&search_item=AK-47+%7C+Redline+%28Field-Tested%29' class='btn btn-primary'>Search</a>
                    <br /><button class='btn btn-orange' type='button' style='font-size:1.2em;margin-top:2px;' id='shopItem3' onclick='addToCart(1852853,441)'>Add to cart</button></center></div>
    </div>
  </div></div><!-- /.col-md-4 --><div class='col-xs-12 col-sm-6 col-md-4 col-lg-3'><div class='featured-item'><a class='market-name market-link' href='https://opskins.com/index.php?loc=shop_view_item&item=1852846'>M4A1-S | Master Piece (Field-Tested)</a><br /><small class='text-muted'>Classified Rifle</small><img style='margin-top:-25px;' src='256fx256f' />
    <div class='item-add'>
      <div class='item-amount'><span class='icon-logo'></span>6,618</div>
      <div class='market-name' style='padding-bottom:0.3em;'><span class='market-name'><a style='color:white;' href='http://csgo.steamanalyst.com/id/120409/' target='_BLANK'>Suggested Price: <span class='icon-logo'></span>8,905</a></div>
                <div class='item-buttons'><center> class='btn btn-primary' style='margin-right:4px'>Inspect</a><a href ='/?loc=shop_search&sort=lh&search_item=M4A1-S+%7C+Master+Piece+%28Field-Tested%29' class='btn btn-primary'>Search</a>
                    <br /><button class='btn btn-orange' type='button' style='font-size:1.2em;margin-top:2px;' id='shopItem4' onclick='addToCart(1852846,6618)'>Add to cart</button></center></div>
    </div>

【问题讨论】:

    标签: python html html-parsing lxml html5lib


    【解决方案1】:

    使用lxml 库中的html 解析器。对于下面的工作示例,您的 HTML 被分配给 myhtml。可能有一种更优雅的方式来解析按钮属性中的文本,但这是一个开始。

    >>> from lxml import html
    >>> tree = html.fromstring(myhtml)
    >>> mybuttons = tree.xpath('//button[@class="btn btn-orange" and @onclick]')
    >>> len(mybuttons)
    4
    >>> for button in mybuttons:
    ...     (id1, id2) = button.attrib['onclick'].replace('(', ' ').replace(',', ' ').replace(')', ' ').split()[1:]
    ...     print id1, id2
    ... 
    1852864 1108
    1841001 155000
    1852853 441
    1852846 6618
    >>> myurl = tree.xpath('//span[@class="market-name"]/a')
    >>> for u in myurl:
    ...     href = u.attrib['href']
    ...     print href
    ... 
    http://csgo.steamanalyst.com/id/120565/
    http://csgo.steamanalyst.com/id/62403692/
    http://csgo.steamanalyst.com/id/1420/
    http://csgo.steamanalyst.com/id/120409/
    >>> 
    

    【讨论】:

    • 这就是我要找的,谢谢!虽然对于按钮属性,它返回一个 KeyError File "lxml.etree.pyx", line 2295, in lxml.etree._Attrib.__getitem__ (src/lxml/lxml.etree.c:59791) KeyError: 'onclick'
    • @MarieAnne 如果您正在读取文件,例如您的 HTML 在名为 myhtml.htm 的文件中,您需要将树阅读器行从 tree = html.fromstring(myhtml) 更改为 tree = html.parse('myhtml.htm')。发布的答案将数据解析为字符串,但如果您从本评论中显示的文件进行解析,它也同样有效。
    • @MarieAnne 我编辑了上面的代码以使用您提供的 URL,方法是将选择器更改为需要 onclick 属性。您可能希望删除所有脚本以使其更易于解析。
    • 这正是我想要的,谢谢。请再问一个问题,是否可以将这些字符串解析为 href、id1、id2 和下一个 href、id1、id2 等之间的链接数据,而不是拥有 2 个完全不同的列表?
    • 是的,您应该首先从 xpath 查询中获取按钮和 url,然后使用 zip 函数将它们合并。见docs.python.org/2/library/functions.html#zip。在这种情况下,它看起来像这样:for (button, u) in zip(mybuttons, myurl): # Operate on button and u here...
    【解决方案2】:

    我使用了一个更简单的库来解决类似的问题:

    import re
    from HTMLParser import HTMLParser
    
    class MyParser(HTMLParser):
      def __init__(self):
        HTMLParser.__init__(self)
        self.in_market = 0
        self.markets = {}
        self.market = None
    
      def handle_starttag(self, tag, attrs):
        if tag == 'span':
          if "class" in attrs and \
          and attrs["class"].indexof('market-name') != -1:
            self.in_market = 1
          elif self.in_market:
            self.in_market += 1
        elif self.in_market:
          if tag == 'a' and 'href' in attrs:
            self.market = attrs["href"]
          elif tag == 'button' and 'onclick' in attrs:
            add_to_cart_RE = re.compile(r'addToCart\((\d+),(\d+)\)')
            match = add_to_cart_RE.match(attrs["onclick"])
            self.markets[self.market] = [match.group(1), match.group(2)]
    
    
      def handle_endtag(self, tag):
        if self.tag == 'span' and self.in_market:
          self.in_market -= 1
    
      def handle_data(self, data):
        pass
    

    如果您不清楚代码,请向我提问。

    【讨论】:

    • 正则表达式不擅长解析 html 吗? stackoverflow.com/a/1732454/4570549我会尝试回复你,但似乎有很多条件,那不也影响性能吗?
    • 正则表达式只是从 onclick 事件中提取两个数字。如果格式固定好,您可以使用更基本的方法对其进行处理。对于最有效的正则表达式,我应该说 '^addToCart...)$'。那么它可能会比手动操作更有效。它肯定会出现在 V8 中——对于 Python 不太确定。
    • 我要测试 regex 和 lxml 看看哪个效果最好,谢谢
    • 更新,为了代码的简单,我选择了lxml版本,但是再次感谢你的这个方法,正因为如此我对正则表达式有了更多的了解。
    猜你喜欢
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2020-07-12
    • 2018-01-18
    • 1970-01-01
    • 2015-04-06
    • 2013-09-09
    相关资源
    最近更新 更多