【问题标题】:re.search only return part of stringsre.search 只返回部分字符串
【发布时间】:2021-09-22 23:55:22
【问题描述】:

我想使用 Python re 模块来获取 <script>...</script> 标签之间的内容。我使用re.search(r'<script>[\S\s]*</script>', myhtml) 搜索[\S\s]* 表示搜索任何字符串的内容。但是这个函数的行为很奇怪,它只返回了所需内容的一部分。所以我做一个小例子来说明我的意思。

import re
re.search('[\S\s]*','<!DOCTYPE HTML PUBLIC "-<!DO/W3C//DTD C 1.0Traitional//E')

所需的结果应该是'&lt;!DOCTYPE HTML PUBLIC "-&lt;!DO/W3C//DTD C 1.0Traitional//E',它是原始输入字符串。但是,它会打印 &lt;_sre.SRE_Match object; span=(0, 56), match='&lt;!DOCTYPE HTML PUBLIC "-&lt;!DO/W3C//DTD C 1.0Traiti&gt;。可以看出,字符串的最后一部分,即'onal//E' 丢失了。

这是为什么呢?如何提取标签之间的内容?

另外,有些人可能会建议我应该使用lxmlBeautifulSoup,因为我也发现了一些奇怪的东西:

使用此代码:

from lxml import etree
rr='''
<script>
<div>
im here
</div>
</script>

'''
html = etree.HTML(rr, etree.HTMLParser())
print(html.xpath('//div//text()'))

上面的代码什么也没打印。如果我将&lt;script&gt; 更改为&lt;script1&gt;,那么它会按预期打印im here,并且BeautifulSoup 具有相同的行为。

【问题讨论】:

  • 您看到的是匹配的一部分,因为re.Match 类的__repr__ 方法为了显示目的截断了字符串。尝试re.search(...).group(0) 观看整场比赛。

标签: python beautifulsoup lxml re


【解决方案1】:

要添加到@Selcuk's comment,您正在执行.search,它返回re.Match 类,该类具有0 到多个单独的匹配组。它们比.findall 包含更多数据,例如匹配的起始索引及其长度。

>>> match = re.search('[\S\s]*','<!DOCTYPE HTML PUBLIC "-<!DO/W3C//DTD C 1.0Traitional//E')
>>> match
<re.Match object; span=(0, 56), match='<!DOCTYPE HTML PUBLIC "-<!DO/W3C//DTD C 1.0Traiti>
>>> dir(match)
['__class__', '__class_getitem__', '__copy__', '__deepcopy__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'end', 'endpos', 'expand', 'group', 'groupdict', 'groups', 'lastgroup', 'lastindex', 'pos', 're', 'regs', 'span', 'start', 'string']

你也可以使用.findall(),它会返回一个列表。

我还建议在传递正则表达式模式时始终使用 r'' 字符串。

>>> re.search(r'[\S\s]*','<!DOCTYPE HTML PUBLIC "-<!DO/W3C//DTD C 1.0Traitional//E').group(0)
'<!DOCTYPE HTML PUBLIC "-<!DO/W3C//DTD C 1.0Traitional//E'
>>> re.findall(r'[\S\s]*','<!DOCTYPE HTML PUBLIC "-<!DO/W3C//DTD C 1.0Traitional//E')
['<!DOCTYPE HTML PUBLIC "-<!DO/W3C//DTD C 1.0Traitional//E', '']

【讨论】:

  • 谢谢!!!但是为什么 lxml 不能识别标签?
【解决方案2】:

您的第一个问题已经解决。

第二个问题的答案:

上面的代码什么也没打印。如果我将&lt;script&gt; 更改为&lt;script1&gt;,那么 它按预期打印im here,并且BeautifulSoup 具有相同的 行为。

这是因为&lt;div&gt; 实际上是&lt;script&gt; 标签内。

使用您提供的 HTML:

<script>
<div>
im here
</div>
</script>

如果我们对其进行美化,您会清楚地看到&lt;div&gt; 标记&lt;script&gt;

<script>
  <div>
  im here
  </div>
</script>

因此,要获取&lt;div&gt;,使用BeautifulSoup,您可以使用next_element 属性:

soup = BeautifulSoup(html, "html.parser")
print(soup.find("script").next_element)

输出:

<div>
im here
</div>

【讨论】:

  • 非常感谢!但为什么会这样呢?我不明白...
  • @user8641707 如果你会做soup.find('div'),它会返回None,因为没有divdivinsidescript,所以你需要找到script,而不是div。明白了吗?
猜你喜欢
  • 2013-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-15
  • 2016-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多