【问题标题】:Use regex or something else to capture website data使用正则表达式或其他东西来捕获网站数据
【发布时间】:2016-06-26 22:10:22
【问题描述】:

我正在尝试使用 python 和正则表达式在下面的示例网站中提取价格,但没有得到任何结果。

我如何才能最好地捕捉价格(我不关心美分,只关心美元金额)?

http://www.walmart.com/store/2516/search?dept=4044&dept_name=Home&query=43888060

相关 HTML:

<div class="price-display csTile-price">
       <span class="sup">$</span>
       299
       <span class="currency-delimiter">.</span>
       <span class="sup">00</span>
</div>

捕获“299”的正则表达式是什么,或者是更简单的方法?谢谢!

【问题讨论】:

  • 您能展示一下您尝试了什么以及取得了什么结果吗?
  • 大多数人使用像流行的Beautiful Soup这样的解析器。您可以在网上找到大量教程或在here 上找到问题。

标签: python html regex web-scraping


【解决方案1】:

使用正则表达式,您的模式应该有多准确可能有点棘手。 我在这里快速输入了一些东西:https://regex101.com/r/lF5vF2/1

你应该明白这个想法并修改这个以适应你的实际需要。

亲切的问候

【讨论】:

    【解决方案2】:

    不要使用正则表达式,使用像bs4这样的html解析器:

    from bs4 import BeautifulSoup
    h = """<div class="price-display csTile-price">
           <span class="sup">$</span>
           299
           <span class="currency-delimiter">.</span>
           <span class="sup">00</span>
    </div>"""
    soup = BeautifulSoup(h)
    
    amount = soup.select_one("div.price-display.csTile-price span.sup").next_sibling.strip()
    

    这会给你:

    299
    

    或者使用currency-delimiter span 并获取上一个元素:

    amount = soup.select_one("span.currency-delimiter").previous.strip()
    

    这会给你同样的。您问题中的 html 也是通过 Javascript 动态生成的,因此您不会使用 urllib.urlopen 获取它,它根本不在返回的源代码中。

    您将需要类似 selenium 的东西,或者使用 requests 来模仿下面的 ajax 调用。

    import requests
    import json
    js = requests.post("http://www.walmart.com/store/ajax/search",
                        data={"searchQuery":"store=2516&size=18&dept=4044&query=43888060"} ).json()
    
    data = json.loads(js['searchResults'])
    
    from pprint import pprint as pp
    pp(data)
    

    这给了你一些 json:

    {u'algo': u'polaris',
     u'blacklist': False,
     u'cluster': {u'apiserver': {u'hostname': u'dfw-iss-api8.stg0',
                                 u'pluginVersion': u'2.3.0'},
                  u'searchengine': {u'hostname': u'dfw-iss-esd.stg0.mobile.walmart.com'}},
     u'count': 1,
     u'offset': 0,
     u'performance': {u'enrichment': {u'inventory': 70}},
     u'query': {u'actualQuery': u'43888060',
                u'originalQuery': u'43888060',
                u'suggestedQueries': []},
     u'queryTime': 181,
     u'results': [{u'department': {u'name': u'Home', u'storeDeptId': -1},
                   u'images': {u'largeUrl': u'http://i5.walmartimages.com/asr/7b8fd3b1-8eed-4b68-971b-81188ddb238c_1.a181800cade4db9d42659e72fa31469e.jpeg?odnHeight=180&odnWidth=180',
                               u'thumbnailUrl': u'http://i5.walmartimages.com/asr/7b8fd3b1-8eed-4b68-971b-81188ddb238c_1.a181800cade4db9d42659e72fa31469e.jpeg?odnHeight=180&odnWidth=180'},
                   u'inventory': {u'isRealTime': True,
                                  u'quantity': 1,
                                  u'status': u'In Stock'},
                   u'isWWWItem': True,
                   u'location': {u'aisle': [], u'detailed': []},
                   u'name': u'Dyson Ball Multi-Floor Bagless Upright Vacuum, 206900-01',
                   u'price': {u'currencyUnit': u'USD',
                              u'isRealTime': True,
                              u'priceInCents': 29900},
                   u'productId': {u'WWWItemId': u'43888060',
                                  u'productId': u'2FY1C7B7RMM4',
                                  u'upc': u'88560900430'},
                   u'ratings': {u'rating': u'4.721',
                                u'ratingUrl': u'http://i2.walmartimages.com/i/CustRating/4_7.gif'},
                   u'reviews': {u'reviewCount': u'1436'},
                   u'score': u'0.507073'}],
     u'totalCount': 1}
    

    这为您提供了您可能需要的所有信息,您所做的只是将您在 url 中的参数和商店编号发布到 http://www.walmart.com/store/ajax/search

    要获取价格和名称:

    In [22]: import requests
    
    In [23]: import json
    
    In [24]: js = requests.post("http://www.walmart.com/store/ajax/search",
       ....:                     data={"searchQuery":"store=2516&size=18&dept=4044&query=43888060"} ).json()
    
    In [25]: data = json.loads(js['searchResults'])
    
    In [26]: res = data["results"][0]
    
    In [27]: print(res["name"])
    Dyson Ball Multi-Floor Bagless Upright Vacuum, 206900-01
    
    In [28]: print(res["price"])
    {u'priceInCents': 29900, u'isRealTime': True, u'currencyUnit': u'USD'}
    In [29]: print(res["price"]["priceInCents"])
    29900
    
    In [30]: print(res["price"]["priceInCents"]) / 100
    299
    

    【讨论】:

    • 哇——你真快!!我需要一些时间来消化。目前我有这个,它还没有抢到价格。看来我应该修补 bs4...
    • @MiaElla,urlopen 不会为您提供所需的源,请在浏览器中右键单击并选择查看源,您将不会在任何地方看到问题中的 html。它是通过 javascript 加载的。您需要使用可以处理 javascript 的 selenium 之类的东西,或者我使用请求所做的事情。我会使用请求逻辑
    • 我复制了您的 json 输出,但在如何实现“获取价格和名称:”之后的部分时迷失了方向。我的另一个目标是遍历商店#s 列表并按商店# 输出结果。有什么想法吗?我显然还在学习,所以对我的缓慢学习表示歉意。
    • price = res["price"]["priceInCents"/ 100 use / 100.0 if using python2 and you want the cents,name = res["name"]),显然遵循data = json.loads(js['searchResults'])res = data["results"][0],基本上只需按照答案中的步骤。跨度>
    • 有一个类型,name = res["name"]
    【解决方案3】:

    好的,只需搜索数字(我添加了 $ 和 .)并将结果连接成一个字符串(我使用了 "".join())。

    >>> txt = """
          <div class="price-display csTile-price">
              <span class="sup">$</span>
                299
              <span class="currency-delimiter">.</span>
              <span class="sup">00</span>
          </div>
          """
    
    
    >>> ''.join(re.findall('[0-9$.]',txt.replace("\n","")))
    '$299.00'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-24
      • 2023-02-18
      • 1970-01-01
      相关资源
      最近更新 更多