【问题标题】:Grabbing text inside a <p> tag in between <b> tags plus a regex issue抓取 <b> 标签之间的 <p> 标签内的文本以及正则表达式问题
【发布时间】:2017-01-23 17:49:05
【问题描述】:

好的,所以我已经非常接近了,需要帮助才能越过终点线。我有两条要使用 Scrapy 抓取的文本。格式如下:

<html>
  <div id="product-description">
    <p>
      Blah blah blah text text text reads: 874620. more text text.
      <br>
      <br>
      <b>Brand:</b>
      " Nintendo"
      <br>
      <b>Condition:</b>
      " Good"
    </p>
  </div>
</html>

到目前为止,我只能抓取粗体标题(品牌:,条件:),而不是我真正想要的文本(任天堂,好)。与正则表达式类似,我只抓取“读取:”而不是紧随其后的字符串,这就是我想要的(874620)。这是我的位置:

response.xpath('//div[@id="product-description"]//p/b').extract_first()

response.xpath('//div[@id="product-description"]//p').re(r'reads.*')

【问题讨论】:

    标签: python regex scrapy


    【解决方案1】:

    您可以提取&lt;p&gt;标签的整个文本,然后运行正则表达式从中提取相关信息

    示例代码:

    import re
    from scrapy.selector import Selector
    
    html = '''<html>
      <div id="product-description">
        <p>
          Blah blah blah text text text reads: 874620. more text text.
          <br>
          <br>
          <b>Brand:</b>
          " Nintendo"
          <br>
          <b>Condition:</b>
          " Good"
        </p>
      </div>
    </html>'''
    
    extracted_text = Selector(text=html).xpath('//div[@id="product-description"]//p//text()').extract()
    text = u''.join(extracted_text)
    
    regex = r'reads:\s*(?P<reads>\d+).*Brand:\s*" (?P<brand>\w+)".*Condition:\s*" (?P<condition>\w+)"'
    results = re.search(regex, text, flags=re.DOTALL).groupdict()
    
    results['reads'] = int(results['reads'])
    print(results)
    

    此代码输出:

    {'reads': 874620, 'brand': u'Nintendo', 'condition': u'Good'}
    

    更新:

    让我们看看这段代码的作用:

    xpath

    首先,extracted_text 使用 xpath //div[@id="product-description"]//p//text() 获取 &lt;p&gt; 标记内的所有文本 这个 xpath 的意思是:

    • 给我所有 id 属性匹配的 div “产品描述”
    • 把上面div里面的p标签都给我
    • 从这些 p 标签中获取文本

    注意// 代替 / 表示在搜索标签中还包括孩子的孩子及其孩子等等。

    运行此 xpath 将为我们找到的 &lt;p&gt; 标记内的每个标记文本返回字符串列表。

    在 xpath 之后,我们使用 u''.join(extracted_text) 将此列表连接成大字符串。

    在获得我们想要的全文后,我们可以运行正则表达式来从中提取相关数据。

    正则表达式

    让我们尝试分解正则表达式并看看它的含义:

    reads:\s*(?P&lt;reads&gt;\d+).*Brand:\s*" (?P&lt;brand&gt;\w+)".*Condition:\s*" (?P&lt;condition&gt;\w+)"

    reads:\s*(?P&lt;reads&gt;\d+) - 给我找一个以reads: 开头的字符串。后跟零个或多个空格 \s* 并创建一个名为 reads 的匹配组,其中包含 \d+ 表示一个或多个数字。

    .*Brand:\s*" (?P&lt;brand&gt;\w+)" - 以上后跟零个或多个字符(任何字符)、字符串Brand: 和再次\s* 零个或多个空格后跟双引号和单个空格"。在此之后创建另一个名为 brand 的组,其中包含 \w+ 表示一个或多个字母数字字母。

    .*Condition:\s*" (?P&lt;condition&gt;\w+)" - 这和上面第二部分一样,为条件

    创建一个匹配组

    正则表达式使用标志DOTALL 执行,这意味着. 字符匹配所有字符(包括换行符),因为我们的匹配跨越多行。

    运行上述正则表达式后,我们提取 3 个匹配组并将读取匹配从字符串转换为 int。

    我将此示例上传到 here,其中包含详细信息及其交互性,因此您可以自己尝试。

    【讨论】:

    • 你能详细说明这里发生了什么吗?特别是结果和正则表达式变量。我正在尝试学习正则表达式,并希望更好地了解机制。谢谢!
    • 难以置信!谢谢你这么棒的回答!!
    【解决方案2】:

    对于Nintendo, Good 值,您可以使用following-sibling 功能:

    In [1]: sel.xpath('//div[@id="product-description"]//b/following-sibling::text()[1]').extract()
    Out[1]: [u'\n      " Nintendo"\n      ', u'\n      " Good"\n    ']
    

    您可以添加正则表达式来避免丑陋的空格:

    In [2]: sel.xpath('//div[@id="product-description"]//b/following-sibling::text()[1]').re('"(.+)"')
    Out[2]: [u' Nintendo', u' Good']
    

    关于正则表达式的第二个问题,试试这个:

    In [3]: sel.xpath('//div[@id="product-description"]//p').re('reads: (\d+)')
    Out[3]: [u'874620']
    

    【讨论】:

    • 前两个运行良好。第三,我得到一个空列表作为结果。如果我删除(\d+) 我正确得到[u'reads: '] 但使用(\d+) 我得到[ ]。有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 2017-02-25
    • 2013-02-08
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    相关资源
    最近更新 更多