python 中的正则表达式问题

Issue with Regular expressions in python

提问人: 提问时间:9/18/2008 最后编辑:Ulf Gjerdingen 更新时间:6/2/2016 访问量:1215

问:

好的,所以我正在研究一个正则表达式来搜索网站中的所有标题信息。

我编译了正则表达式:

regex = re.compile(r'''
    <h[0-9]>\s?
    (<a[ ]href="[A-Za-z0-9.]*">)?\s?
    [A-Za-z0-9.,:'"=/?;\s]*\s?
    [A-Za-z0-9.,:'"=/?;\s]?
''',  re.X)

当我在 python reg ex. tester 中运行它时,它的效果非常好。

示例数据:

<body>
    <h1>Dog </h1>
    <h2>Cat </h2>
    <h3>Fancy </h3>
    <h1>Tall cup of lemons</h1>
    <h1><a href="dog.com">Dog thing</a></h1>
</body>

现在,在 REDemo 中,它运行得非常好。

但是,当我将其放入我的 python 代码中时,它只会打印<a href="dog.com">

这是我的 python 代码,我不确定我是否做错了什么,或者翻译中是否丢失了某些东西。感谢您的帮助。

stories=[]
response = urllib2.urlopen('http://apricotclub.org/duh.html')
html = response.read().lower()
p = re.compile('<h[0-9]>\\s?(<a href=\"[A-Za-z0-9.]*\">)?\\s?[A-Za-z0-9.,:\'\"=/?;\\s]*\\s?[A-Za-z0-9.,:\'\"=/?;\\s]?')
stories=re.findall(p, html)
for i in stories:
    if len(i) >= 5:
        print i 

我还应该注意,当我从正则表达式中取出时,它适用于非链接行。(<a href=\"[A-Za-z0-9.]*\">)?<hN>

Python HTML 正则表达式

评论


答:

4赞 habnabit 9/18/2008 #1

使用正则表达式解析事物适用于常规语言。HTML不是一种常规语言,现在你在网页上找到的东西绝对是废话。BeautifulSoup 使用类似浏览器的启发式方法处理标签汤 HTML,因此您可以获得类似于浏览器显示的解析 HTML。

缺点是它不是很快。有 lxml 用于解析格式正确的 html,但如果你不能 100% 确定你的输入总是格式正确,你真的应该使用 BeautifulSoup。

2赞 Thomas 9/18/2008 #2

由于锚标记周围的大括号,该部分被解释为捕获组。这会导致仅返回捕获组,而不是整个正则表达式匹配。

将整个正则表达式放在大括号中,您将看到正确的匹配项显示为返回的元组中的第一个元素。

但实际上,您应该使用真正的解析器。

23赞 Jerub 9/18/2008 #3

在过去的几天里,这个问题以多种形式被问到,所以我要说得很清楚。

问:如何使用正则表达式解析 HTML?

答:请不要。

使用BeautifulSoup,html5liblxml.html请。

评论

0赞 Allen 9/18/2008
不要忘记,html5lib 也可以将不符合要求的文档解析为合理的结构。
0赞 jfs 3/6/2009
@Jerub:我同意你的回答,但它没有回答OP问题。想象一下,你不能使用 BeautifulSoup、html5lib、lxml 并且你的 html 文件非常简单,那么一个简单的正则表达式就足够了。
1赞 molasses 9/18/2008 #4

如前所述,您应该使用解析器而不是正则表达式。

不过,这就是您可以使用正则表达式执行此操作的方法:

import re

html = '''
<body>

<h1>Dog </h1>
<h2>Cat </h2>
<h3>Fancy </h3>
<h1>Tall cup of lemons</h1>
<h1><a href="dog.com">Dog thing</a></h1>
</body>
'''

p = re.compile(r'''
    <(?P<header>h[0-9])>             # store header tag for later use
    \s*                              # zero or more whitespace
    (<a\shref="(?P<href>.*?)">)?     # optional link tag. store href portion
    \s*
    (?P<title>.*?)                   # title
    \s*
    (</a>)?                          # optional closing link tag
    \s*
    </(?P=header)>                   # must match opening header tag
''', re.IGNORECASE + re.VERBOSE)

stories = p.finditer(html)

for match in stories:
    print '%(title)s [%(href)s]' % match.groupdict()

以下是一些不错的正则表达式资源:

评论

0赞 jfs 3/6/2009
正则表达式不适用于带有链接的标头。OP 专门询问带有链接的标题。
2赞 rslite 9/18/2008 #5

在迄今为止的答案基础上:

最好使用解析引擎。它可以以一种优雅的方式涵盖很多情况。我尝试过 BeautifulSoup,我非常喜欢它。也易于使用,有一个很棒的教程。

如果有时感觉像用大炮射击苍蝇,您可以使用正则表达式进行快速解析。如果这是您需要的,那么这里是修改后的代码,它将捕获所有标头(甚至是多行标头):

p = re.compile(r'<(h[0-9])>(.+?)</\1>', re.IGNORECASE | re.DOTALL)
stories = re.findall(p, html)
for i in stories:
    print i

评论

0赞 jfs 3/6/2009
i在您的情况下是一个元组,例如 ('h1', '<a href=“dog.com”>Dog thing</a>')
2赞 aatifh 3/6/2009 #6

我使用 beautifulsoup 来解析您想要的 HTML。我有上面的HTML代码 名为 foo.html 的文件,稍后作为文件对象读取。

from BeautifulSoup import BeautifulSoup


H_TAGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']

def extract_data():
   """Extract the data from all headers
   in a HTML page."""
   f = open('foo.html', 'r+')
   html = f.read()
   soup = BeautifulSoup(html)
   headers = [soup.findAll(h) for h in H_TAGS if soup.findAll(h)]
   lst = []
   for x in headers:
      for y in x:
         if y.string:
            lst.append(y.string)
         else:
            lst.append(y.contents[0].string)
   return lst

上面的函数返回:

>>> [u'Dog ', u'Tall cup of lemons', u'Dog thing', u'Cat ', u'Fancy ']

您可以在列表中添加任意数量的标题标记h_tags。我已经假设了所有的标题。 如果您可以使用 BeautifulSoup 轻松解决问题,那么最好使用它。:)